001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.text.csv; 020 021import java.util.ArrayList; 022import java.util.List; 023 024import lucee.commons.lang.StringUtil; 025 026 027public class CSVString { 028 029 private static final char LF=10; 030 private static final char CR=13; 031 032 private char[] buffer; 033 private int pos; 034 private char delim; 035 036 public CSVString( String input, char delim ) { 037 this.buffer = input.toCharArray(); 038 this.delim = delim; 039 } 040 041 public List<List<String>> parse() { 042 043 List<List<String>> result = new ArrayList(); 044 List<String> line = new ArrayList(); 045 046 if ( buffer.length == 0 ) 047 return result; 048 049 StringBuilder sb = new StringBuilder(); 050 char c; 051 052 do { 053 054 c = buffer[ pos ]; 055 if ( c == '"' || c == '\'' ) { 056 sb.append( fwdQuote( c ) ); 057 } 058 else if ( c == LF || c == CR ) { 059 if(c == CR && isNext(LF)) next(); 060 line.add( sb.toString().trim() ); 061 sb = new StringBuilder(); 062 if ( isValidLine( line ) ) 063 result.add( line ); 064 line = new ArrayList<String>(); 065 } 066 else if ( c == delim ) { 067 068 line.add( sb.toString().trim() ); 069 sb = new StringBuilder(); 070 } 071 else 072 sb.append( c ); 073 074 next(); 075 } while ( pos < buffer.length); 076 077 078 line.add( sb.toString() ); 079 080 if ( isValidLine( line ) ) 081 result.add( line ); 082 return result; 083 } 084 085 086 /** forward pos until the end of quote */ 087 StringBuilder fwdQuote( char q ) { 088 089 StringBuilder sb = new StringBuilder(); 090 091 while ( hasNext() ) { 092 093 next(); 094 sb.append( buffer[ pos ] ); 095 096 if ( isCurr( q ) ) { 097 if ( isNext( q ) ) { // consecutive quote sign 098 next(); 099 } 100 else { 101 break; 102 } 103 } 104 } 105 106 if ( sb.length() > 0 ) 107 sb.setLength( sb.length() - 1 ); // remove closing quote sign 108 109 return sb; 110 } 111 112 void next() { 113 114 pos++; 115 } 116 117 boolean hasNext() { 118 119 return pos < ( buffer.length - 1 ); 120 } 121 122 boolean isNext( char c ) { 123 124 if ( !hasNext() ) return false; 125 126 return buffer[ pos + 1 ] == c; 127 } 128 129 130 boolean isCurr( char c ) { 131 132 if ( !isValidPos() ) 133 return false; 134 135 return buffer[ pos ] == c; 136 } 137 138 139 boolean isValidPos() { 140 141 return pos >= 0 && pos < buffer.length - 1; 142 } 143 144 145 boolean isValidLine( List<String> line ) { 146 147 for ( String s : line ) { 148 149 if ( !StringUtil.isEmpty( s, true ) ) 150 return true; 151 } 152 153 return false; 154 } 155 156}