1
2
3
4
5
6
7
8
9
10
11 package org.csveed.row;
12
13 import java.io.IOException;
14 import java.io.Reader;
15 import java.util.ArrayList;
16 import java.util.List;
17
18 import org.csveed.api.Header;
19 import org.csveed.api.Row;
20 import org.csveed.report.CsvException;
21 import org.csveed.report.RowError;
22 import org.csveed.token.ParseException;
23 import org.csveed.token.ParseStateMachine;
24
25
26
27
28
29 public class RowReaderImpl implements RowReader {
30
31
32 private ParseStateMachine stateMachine = new ParseStateMachine();
33
34
35 private RowInstructionsImpl rowInstructions;
36
37
38 private int maxNumberOfColumns = -1;
39
40
41 private HeaderImpl header;
42
43
44 private Reader reader;
45
46
47
48
49
50
51
52 public RowReaderImpl(Reader reader) {
53 this(reader, new RowInstructionsImpl());
54 }
55
56
57
58
59
60
61
62
63
64 public RowReaderImpl(Reader reader, RowInstructions instructionsInterface) {
65 this.reader = reader;
66 this.rowInstructions = (RowInstructionsImpl) instructionsInterface;
67 stateMachine.setSymbolMapping(rowInstructions.getSymbolMapping());
68 }
69
70 @Override
71 public List<Row> readRows() {
72 List<Row> allRows = new ArrayList<>();
73 while (!isFinished()) {
74 Row row = readRow();
75 if (row != null && row.size() > 0) {
76 allRows.add(row);
77 }
78 }
79 return allRows;
80 }
81
82 @Override
83 public Row readRow() {
84 getHeader();
85 Line unmappedLine = readBareLine();
86 if (unmappedLine == null) {
87 return null;
88 }
89 checkNumberOfColumns(unmappedLine);
90 return new RowImpl(unmappedLine, getHeader());
91 }
92
93 @Override
94 public int getCurrentLine() {
95 return this.stateMachine.getCurrentLine();
96 }
97
98 @Override
99 public Header getHeader() {
100 return header == null && rowInstructions.isUseHeader() ? readHeader() : header;
101 }
102
103
104
105
106
107
108 public int getMaxNumberOfColumns() {
109 return this.maxNumberOfColumns;
110 }
111
112 @Override
113 public Header readHeader() {
114 if (header != null) {
115 return header;
116 }
117 Line unmappedLine = readBareLine();
118 if (unmappedLine == null) {
119 return null;
120 }
121 header = new HeaderImpl(unmappedLine);
122 return header;
123 }
124
125
126
127
128
129
130
131 private void checkNumberOfColumns(Line unmappedLine) {
132 if (maxNumberOfColumns == -1) {
133 maxNumberOfColumns = header == null ? unmappedLine.size() : header.size();
134 }
135 if (unmappedLine.size() != maxNumberOfColumns) {
136 throw new CsvException(new RowError("The expected number of columns is " + maxNumberOfColumns
137 + ", whereas it was " + unmappedLine.size(), unmappedLine.reportOnEndOfLine(), getCurrentLine()));
138 }
139 }
140
141 @Override
142 public boolean isFinished() {
143 return stateMachine.isFinished();
144 }
145
146
147
148
149 protected void logSettings() {
150 rowInstructions.logSettings();
151 this.stateMachine.getSymbolMapping().logSettings();
152 }
153
154
155
156
157
158
159 protected Line readBareLine() {
160 logSettings();
161
162 LineWithInfo line = null;
163 while (line == null && !stateMachine.isFinished()) {
164 line = new LineWithInfo();
165 while (!stateMachine.isFinished()) {
166 final String token;
167 final int symbol;
168 try {
169 symbol = reader.read();
170 } catch (IOException err) {
171 throw new RuntimeException(err);
172 }
173 try {
174 token = stateMachine.offerSymbol(symbol);
175 } catch (ParseException e) {
176 throw new CsvException(new RowError(e.getMessage(), line.reportOnEndOfLine(), getCurrentLine()));
177 }
178 if (stateMachine.isTrash()) {
179 continue;
180 }
181 if (stateMachine.isTokenStart()) {
182 line.markStartOfColumn();
183 }
184 if (token != null) {
185 line.addCell(token);
186 }
187 line.addCharacter(symbol);
188 if (stateMachine.isLineFinished()) {
189 break;
190 }
191 }
192 line = stateMachine.ignoreLine() && rowInstructions.isSkipEmptyLines() ? null : line;
193 }
194 return line;
195 }
196
197 @Override
198 public RowInstructions getRowInstructions() {
199 return this.rowInstructions;
200 }
201
202 }