1 package com.github.mygreen.supercsv.io;
2
3 import java.io.IOException;
4 import java.io.Reader;
5 import java.util.List;
6
7 import org.supercsv.comment.CommentMatcher;
8 import org.supercsv.io.AbstractTokenizer;
9 import org.supercsv.prefs.CsvPreference;
10 import org.supercsv.util.CsvContext;
11
12 import com.github.mygreen.supercsv.builder.BeanMapping;
13 import com.github.mygreen.supercsv.builder.ColumnMapping;
14 import com.github.mygreen.supercsv.builder.FixedSizeColumnProperty;
15 import com.github.mygreen.supercsv.exception.SuperCsvFixedSizeException;
16 import com.github.mygreen.supercsv.util.Utils;
17
18
19
20
21
22
23
24
25 public class FixedSizeTokenizer extends AbstractTokenizer {
26
27
28 private final StringBuilder currentRow = new StringBuilder();
29
30
31 private final boolean ignoreEmptyLines;
32
33
34 private final CommentMatcher commentMatcher;
35
36
37 private final List<ColumnMapping> columnMappings;
38
39 public FixedSizeTokenizer(Reader reader, CsvPreference preferences, BeanMapping<?> beanMapping) {
40 super(reader, preferences);
41
42 if (beanMapping.getColumns().isEmpty()) {
43 throw new IllegalArgumentException("columnMappings should not be empty.");
44 }
45
46 this.ignoreEmptyLines = preferences.isIgnoreEmptyLines();
47 this.commentMatcher = preferences.getCommentMatcher();
48 this.columnMappings = beanMapping.getColumns();
49 }
50
51
52
53
54
55
56 @Override
57 public boolean readColumns(final List<String> columns) throws IOException {
58
59 if( columns == null ) {
60 throw new NullPointerException("columns should not be null");
61 }
62
63 columns.clear();
64
65
66 String line;
67 do {
68 line = readLine();
69 if( line == null ) {
70 return false;
71 }
72 }
73 while( ignoreEmptyLines && line.length() == 0 || (commentMatcher != null && commentMatcher.isComment(line)) );
74
75
76 currentRow.append(line);
77
78 final int[] codePointArray = Utils.toCodePointArray(line);
79
80 int pos = 0;
81 for (ColumnMapping columnMapping : columnMappings) {
82
83 if (pos >= codePointArray.length) {
84
85 break;
86 }
87
88 StringBuilder text = new StringBuilder();
89 int lastPos = lastPosition(pos, codePointArray, text, columnMapping);
90
91
92
93
94
95
96 columns.add(text.toString());
97
98 pos = lastPos;
99 }
100
101
102 if (pos < codePointArray.length) {
103 columns.add(new String(codePointArray, pos, codePointArray.length - pos));
104 }
105
106
107 return true;
108 }
109
110
111
112
113
114
115
116
117
118
119
120 private int lastPosition(final int start, int[] codePointArray, StringBuilder column, ColumnMapping columnMapping) {
121
122 int pos = start;
123 int actualSize = 0;
124 final int arrayLength = codePointArray.length;
125 final FixedSizeColumnProperty fixedSizeColumnProperty = columnMapping.getFixedSizeProperty();
126 while(pos < arrayLength && actualSize < fixedSizeColumnProperty.getSize()) {
127 actualSize += fixedSizeColumnProperty.getPaddingProcessor().count(codePointArray[pos]);
128 pos++;
129 }
130
131 if (actualSize < fixedSizeColumnProperty.getSize()) {
132
133
134 throw new SuperCsvFixedSizeException.Builder("csvError.fixedSizeInsufficient", new CsvContext(getLineNumber(), 0, columnMapping.getNumber()))
135 .messageFormat("Insufficient column size. fixedColumnSize: %d, actualSize: %d",
136 fixedSizeColumnProperty.getSize(), actualSize)
137 .messageVariables("fixedColumnSize", fixedSizeColumnProperty.getSize())
138 .messageVariables("actualSize", actualSize)
139 .build();
140 }
141
142 column.append(new String(codePointArray, start, pos - start));
143
144 return pos;
145
146 }
147
148 @Override
149 public String getUntokenizedRow() {
150 return currentRow.toString();
151 }
152 }