Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1069)

Side by Side Diff: sdk/lib/convert/line_splitter.dart

Issue 17580014: dart:convert library. Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/convert/json.dart ('k') | sdk/lib/convert/string_converter.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart.convert;
6
7 class LineSplitter extends Converter<String, List<String>> {
8 LineSplitter();
9
10 ChunkedConversionSink<Object> startChunkedConversion(
11 ChunkedConversionSink sink) {
12 return new _LineSplitterSink(outputInterface.adapt(sink));
13 }
14
15 ChunkedConversionInterface get inputInterface =>
16 StringConversionSink.INTERFACE;
17
18 ChunkedConversionInterface get outputInterface =>
19 MultiStringConversionSink.INTERFACE;
20 }
21
22 class LineFuser extends Converter<List<String>, String> {
23 LineFuser();
24
25 String convert(List<String> input) => input.join("\n");
26
27 fuse(Converter other) => other.fuseInput(this);
28 fuseInput(Converter other) => new FusedConverter(other, this);
29
30 MultiStringConversionSink startChunkedConversion(ChunkedConversionSink sink) {
31 return new _LineFuserSink(outputInterface.adapt(sink));
32 }
33
34 ChunkedConversionInterface get inputInterface =>
35 StringConversionSink.INTERFACE;
36 }
37
38 class _LineSplitterSink extends StringConversionSinkBase {
39 static const int _LF = 10;
40 static const int _CR = 13;
41
42 Utf8Handler _utf8Handler;
43 MultiStringConversionSink _sink;
44 StringBuffer _carry;
45 // True if the last chunk finished with a _CR.
46 bool _ignoreLineFeed = false;
47
48 _LineSplitterSink(this._sink);
49
50 bool get _hasPartialUtf8Input {
51 return _utf8Handler != null && _utf8Handler.hasPartialInput;
52 }
53
54 bool get _hasPartialInput {
55 if (_carry != null && _carry.isNotEmpty) return true;
56 return _hasPartialUtf8Input;
57 }
58
59 int _findFirstLineSplit(List<int> charCodes, int start, int end) {
60 for (int i = start; i < end; i++) {
61 int codeUnit = charCodes[i];
62 if (codeUnit == _LF || codeUnit == _CR) {
63 return i;
64 };
65 }
66 return end;
67 }
68
69 void _addCarry(List<int> charCodes, int start, int end) {
70 if (_utf8Handler != null && _utf8Handler.hasPartialInput) {
71 throw "Incomplete UTF8 sequence";
72 }
73 if (_carry == null) _carry = new StringBuffer();
74 for (int i = start; i < end; i++) {
75 _carry.writeCharCode(charCodes[i]);
76 }
77 }
78
79 void _addUtf8Carry(List<int> codeUnits, int start, int end) {
80 if (_utf8Handler == null) _utf8Handler = new Utf8Handler();
81 if (_carry == null) _carry = new StringBuffer();
82 _utf8Handler.convertToSink(codeUnits, start, end, _carry);
83 }
84
85 void _split(
86 List<int> charCodes,
87 int startIndex,
88 int endIndex,
89 bool isLast,
90 void addLine(List<int> charCodes, int start, int end, bool isLast),
91 void addCarry(List<int> charCodes, int start, int end)) {
92 int lineStart = startIndex;
93 // If the last chunk ended with a carriage-return we have to ignore a
94 // leading line feed.
95 if (_ignoreLineFeed) {
96 if (startIndex != endIndex && charCodes[startIndex] == _LF) {
97 startIndex++;
98 _ignoreLineFeed = false;
99 }
100 }
101 // Set the `_ignoreLineFeed` boolean for the next chunk.
102 if (startIndex != endIndex) {
103 if (charCodes[endIndex - 1] == _CR) {
104 _ignoreLineFeed = true;
105 }
106 }
107 // If there is a carry we have to append the next part of the line to the
108 // buffer.
109 if (_hasPartialInput) {
110 int firstSplit = _findFirstLineSplit(charCodes, startIndex, endIndex);
111 addCarry(charCodes, startIndex, firstSplit);
112 if (firstSplit == endIndex) {
113 // If `isLast` then nothing comes anymore. Send the carry.
114 if (isLast) {
115 if (_hasPartialUtf8Input) {
116 throw "Incomplete Utf8 sequence";
117 }
118 _sink.addString(_carry.toString(), true);
119 }
120 // Otherwise just return and wait for the next chunk.
121 return;
122 } else {
123 // Send the string that is in the carry and reset it.
124 _sink.addString(_carry.toString(), false);
125 _carry.clear();
126 lineStart = firstSplit + 1;
127 if (charCodes[firstSplit] == _CR &&
128 firstSplit + 1 < endIndex &&
129 charCodes[firstSplit + 1] == _LF) {
130 // Ignore LF following a CR.
131 lineStart++;
132 }
133 }
134 }
135 assert(!_hasPartialInput);
136
137 // At this point the carry is empty. We are now exclusively working on the
138 // new chunk.
139 for (int i = lineStart; i < endIndex; i++) {
140 int codeUnit = charCodes[i];
141 if (codeUnit == _LF) {
142 bool isLastLine = isLast && i == endIndex - 1;
143 addLine(charCodes, lineStart, i, isLastLine);
144 lineStart = i + 1;
145 } else if (codeUnit == _CR) {
146 int lineEnd = i;
147 if (i + 1 < charCodes.length && charCodes[i + 1] == _LF) {
148 i++;
149 }
150 bool isLastLine = isLast && i == endIndex - 1;
151 addLine(charCodes, lineStart, lineEnd, isLastLine);
152 lineStart = i + 1;
153 }
154 }
155 if (lineStart != endIndex) {
156 // The last part of the chunk was not consumed. Store it in the carry or
157 // send it directly if this is the last chunk.
158 if (isLast) {
159 addLine(charCodes, lineStart, endIndex, true);
160 } else {
161 addCarry(charCodes, lineStart, endIndex);
162 }
163 } else if (isLast) {
164 _sink.close();
165 }
166 }
167
168 void add(String str) => addString(str, false);
169
170 void addString(String str, bool isLast) {
171 _split(str.codeUnits, 0, str.length, isLast, _sink.addCodeUnits, _addCarry);
172 }
173
174 void addCodeUnits(List<int> codeUnits, int start, int end, bool isLast) {
175 _split(codeUnits, start, end, isLast, _sink.addCodeUnits, _addCarry);
176 }
177
178 void addRunes(List<int> runes, int start, int end, bool isLast) {
179 _split(runes, start, end, isLast, _sink.addRunes, _addCarry);
180 }
181
182 void addUtf8(List<int> utf8Units, int start, int end, bool isLast) {
183 _split(utf8Units, start, end, isLast, _sink.addUtf8, _addUtf8Carry);
184 }
185
186 void addIsoLatin1(List<int> codeUnits, int start, int end, bool isLast) {
187 _split(codeUnits, start, end, isLast, _sink.addIsoLatin1, _addCarry);
188 }
189
190 void addAscii(List<int> codeUnits, int start, int end, bool isLast) {
191 _split(codeUnits, start, end, isLast, _sink.addAscii, _addCarry);
192 }
193 }
194
195 class _LineFuserSink implements MultiStringConversionSink {
196 static const _NL = 10; // New line code.
197 bool needsSeparator = false;
198 StringConversionSink _sink;
199
200 _LineFuserSink(this._sink);
201
202 var _handler = null;
203
204 void writeNewLineIfNecessary() {
205 if (needsSeparator) _sink.writeCharCode(_NL);
206 needsSeparator = true;
207 }
208
209 void addNonChunked(List<String> list) {
210 _sink.writeAll(list, "\n");
211 _sink.close();
212 }
213
214 void add(String str) {
215 writeNewLineIfNecessary();
216 _sink.add(str);
217 }
218
219 void addString(String str, bool isLast) {
220 writeNewLineIfNecessary();
221 _sink.addString(str, isLast);
222 }
223
224 void addCodeUnits(List<int> codeUnits, int start, int end, bool isLast) {
225 writeNewLineIfNecessary();
226 _sink.addCodeUnits(codeUnits, start, end, isLast);
227 }
228 void addRunes(List<int> runes, int start, int end, bool isLast) {
229 writeNewLineIfNecessary();
230 _sink.addRunes(runes, start, end, isLast);
231 }
232 void addUtf8(List<int> utf8Units, int start, int end, bool isLast) {
233 writeNewLineIfNecessary();
234 _sink.addUtf8(utf8Units, start, end, isLast);
235 }
236 void addIsoLatin1(List<int> codeUnits, int start, int end, bool isLast) {
237 writeNewLineIfNecessary();
238 _sink.addIsoLatin1(codeUnits, start, end, isLast);
239 }
240 void addAscii(List<int> codeUnits, int start, int end, bool isLast) {
241 writeNewLineIfNecessary();
242 _sink.addAscii(codeUnits, start, end, isLast);
243 }
244 void iterateCodeUnits(StringIterator iterator, bool isLast) {
245 writeNewLineIfNecessary();
246 _sink.iterateCodeUnits(iterator, isLast);
247 }
248 void iterateRunes(StringIterator iterator, bool isLast) {
249 writeNewLineIfNecessary();
250 _sink.iterateRunes(iterator, isLast);
251 }
252 void iterateUtf8(StringIterator iterator, bool isLast) {
253 writeNewLineIfNecessary();
254 _sink.iterateUtf8(iterator, isLast);
255 }
256 void iterateIsoLatin1(StringIterator iterator, bool isLast) {
257 writeNewLineIfNecessary();
258 _sink.iterateIsoLatin1(iterator, isLast);
259 }
260 void iterateAscii(StringIterator iterator, bool isLast) {
261 writeNewLineIfNecessary();
262 _sink.iterateAscii(iterator, isLast);
263 }
264
265 void write(Object o) {
266 writeNewLineIfNecessary();
267 _sink.write(o);
268 }
269 void writeln([Object o]) {
270 writeNewLineIfNecessary();
271 _sink.writeln(o);
272 }
273 void writeCharCode(int charCode) {
274 writeNewLineIfNecessary();
275 _sink.writeCharCode(charCode);
276 }
277 void writeAll(Iterable objects, [String separator = ""]) {
278 writeNewLineIfNecessary();
279 _sink.writeAll(objects, separator);
280 }
281
282 close() {
283 _sink.close();
284 }
285
286 ChunkedConversionInterface get interface =>
287 MultiStringConversionSink.INTERFACE;
288 }
OLDNEW
« no previous file with comments | « sdk/lib/convert/json.dart ('k') | sdk/lib/convert/string_converter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698