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

Side by Side Diff: sdk/lib/io/string_transformer.dart

Issue 12335093: Fix string_transformer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 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/async/stream.dart ('k') | tests/standalone/io/string_transformer_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.io; 5 part of dart.io;
6 6
7 /** 7 /**
8 * String encodings. 8 * String encodings.
9 */ 9 */
10 class Encoding { 10 class Encoding {
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 controller.stream 146 controller.stream
147 .transform(new StringEncoder(encoding)) 147 .transform(new StringEncoder(encoding))
148 .listen((data) => bytes = data); 148 .listen((data) => bytes = data);
149 controller.add(string); 149 controller.add(string);
150 controller.close(); 150 controller.close();
151 assert(bytes != null); 151 assert(bytes != null);
152 return bytes; 152 return bytes;
153 } 153 }
154 154
155 155
156 class LineTransformer implements StreamTransformer<String, String> { 156 class LineTransformer extends StreamEventTransformer<String, String> {
157 const int _LF = 10; 157 const int _LF = 10;
158 const int _CR = 13; 158 const int _CR = 13;
159 159
160 final StringBuffer _buffer = new StringBuffer(); 160 final StringBuffer _buffer = new StringBuffer();
161 161
162 StreamSubscription<String> _subscription; 162 StreamSubscription<String> _subscription;
163 StreamController<String> _controller;
164 String _carry; 163 String _carry;
165 164
166 Stream<String> bind(Stream<String> stream) { 165 void _handle(String data, StreamSink<String> sink, bool isClosing) {
167 _controller = new StreamController<String>( 166 if (_carry != null) {
168 onPauseStateChange: _pauseChanged, 167 data = _carry.concat(data);
169 onSubscriptionStateChange: _subscriptionChanged); 168 _carry = null;
170 169 }
171 void handle(String data, bool isClosing) { 170 int startPos = 0;
172 if (_carry != null) { 171 int pos = 0;
173 data = _carry.concat(data); 172 while (pos < data.length) {
174 _carry = null; 173 int skip = 0;
175 } 174 int char = data.codeUnitAt(pos);
176 int startPos = 0; 175 if (char == _LF) {
177 int pos = 0; 176 skip = 1;
178 while (pos < data.length) { 177 } else if (char == _CR) {
179 int skip = 0; 178 skip = 1;
180 int char = data.codeUnitAt(pos); 179 if (pos + 1 < data.length) {
181 if (char == _LF) { 180 if (data.codeUnitAt(pos + 1) == _LF) {
182 skip = 1; 181 skip = 2;
183 } else if (char == _CR) {
184 skip = 1;
185 if (pos + 1 < data.length) {
186 if (data.codeUnitAt(pos + 1) == _LF) {
187 skip = 2;
188 }
189 } else if (!isClosing) {
190 _carry = data.substring(startPos);
191 return;
192 } 182 }
193 } 183 } else if (!isClosing) {
194 if (skip > 0) { 184 _carry = data.substring(startPos);
195 _buffer.add(data.substring(startPos, pos)); 185 return;
196 _controller.add(_buffer.toString());
197 _buffer.clear();
198 startPos = pos = pos + skip;
199 } else {
200 pos++;
201 } 186 }
202 } 187 }
203 if (pos != startPos) { 188 if (skip > 0) {
204 // Add remaining
205 _buffer.add(data.substring(startPos, pos)); 189 _buffer.add(data.substring(startPos, pos));
206 } 190 sink.add(_buffer.toString());
207 if (isClosing && !_buffer.isEmpty) {
208 _controller.add(_buffer.toString());
209 _buffer.clear(); 191 _buffer.clear();
192 startPos = pos = pos + skip;
193 } else {
194 pos++;
210 } 195 }
211 } 196 }
212 197 if (pos != startPos) {
213 _subscription = stream.listen( 198 // Add remaining
214 (data) => handle(data, false), 199 _buffer.add(data.substring(startPos, pos));
215 onDone: () { 200 }
216 // Handle remaining data (mainly _carry). 201 if (isClosing && !_buffer.isEmpty) {
217 handle("", true); 202 sink.add(_buffer.toString());
218 _controller.close(); 203 _buffer.clear();
219 },
220 onError: _controller.signalError);
221 return _controller.stream;
222 }
223
224 void _pauseChanged() {
225 if (_controller.isPaused) {
226 _subscription.pause();
227 } else {
228 _subscription.resume();
229 } 204 }
230 } 205 }
231 206
232 void _subscriptionChanged() { 207 handleData(String data, StreamSink<String> sink) {
233 if (!_controller.hasSubscribers) { 208 _handle(data, sink, false);
234 _subscription.cancel(); 209 }
235 } 210
211 handleDone(StreamSink<String> sink) {
212 _handle("", sink, true);
213 sink.close();
236 } 214 }
237 } 215 }
238 216
239 217
240 class _SingleByteDecoder implements StreamTransformer<List<int>, String> { 218 abstract class _SingleByteDecoder
241 StreamSubscription<List<int>> _subscription; 219 implements StreamTransformer<List<int>, String> {
242 StreamController<String> _controller; 220
243 final int _replacementChar; 221 final int _replacementChar;
244 222
245 _SingleByteDecoder(this._replacementChar); 223 _SingleByteDecoder(this._replacementChar);
246 224
247 Stream<String> bind(Stream<List<int>> stream) { 225 Stream<String> bind(Stream<List<int>> stream) {
248 _controller = new StreamController<String>( 226 return stream.map((List<int> data) {
249 onPauseStateChange: _pauseChanged, 227 var buffer = new List<int>.fixedLength(data.length);
250 onSubscriptionStateChange: _subscriptionChanged); 228 for (int i = 0; i < data.length; i++) {
251 _subscription = stream.listen( 229 int char = _decodeByte(data[i]);
252 (data) { 230 if (char < 0) char = _replacementChar;
253 var buffer = new List<int>.fixedLength(data.length); 231 buffer[i] = char;
254 for (int i = 0; i < data.length; i++) { 232 }
255 int char = _decodeByte(data[i]); 233 return new String.fromCharCodes(buffer);
256 if (char < 0) char = _replacementChar; 234 });
257 buffer[i] = char;
258 }
259 _controller.add(new String.fromCharCodes(buffer));
260 },
261 onDone: _controller.close,
262 onError: _controller.signalError);
263 return _controller.stream;
264 } 235 }
265 236
266 int _decodeByte(int byte); 237 int _decodeByte(int byte);
267
268 void _pauseChanged() {
269 if (_controller.isPaused) {
270 _subscription.pause();
271 } else {
272 _subscription.resume();
273 }
274 }
275
276 void _subscriptionChanged() {
277 if (!_controller.hasSubscribers) {
278 _subscription.cancel();
279 }
280 }
281 } 238 }
282 239
283 240
284 // Utility class for decoding ascii data delivered as a stream of 241 // Utility class for decoding ascii data delivered as a stream of
285 // bytes. 242 // bytes.
286 class _AsciiDecoder extends _SingleByteDecoder { 243 class _AsciiDecoder extends _SingleByteDecoder {
287 _AsciiDecoder(int replacementChar) : super(replacementChar); 244 _AsciiDecoder(int replacementChar) : super(replacementChar);
288 245
289 int _decodeByte(int byte) => ((byte & 0x7f) == byte) ? byte : -1; 246 int _decodeByte(int byte) => ((byte & 0x7f) == byte) ? byte : -1;
290 } 247 }
291 248
292 249
293 // Utility class for decoding Latin-1 data delivered as a stream of 250 // Utility class for decoding Latin-1 data delivered as a stream of
294 // bytes. 251 // bytes.
295 class _Latin1Decoder extends _SingleByteDecoder { 252 class _Latin1Decoder extends _SingleByteDecoder {
296 _Latin1Decoder(int replacementChar) : super(replacementChar); 253 _Latin1Decoder(int replacementChar) : super(replacementChar);
297 254
298 int _decodeByte(int byte) => ((byte & 0xFF) == byte) ? byte : -1; 255 int _decodeByte(int byte) => ((byte & 0xFF) == byte) ? byte : -1;
299 } 256 }
300 257
301 258
302 class _SingleByteEncoder implements StreamTransformer<String, List<int>> { 259 abstract class _SingleByteEncoder implements StreamTransformer<String, List<int> > {
303 StreamSubscription<String> _subscription;
304 StreamController<List<int>> _controller;
305
306 Stream<List<int>> bind(Stream<String> stream) { 260 Stream<List<int>> bind(Stream<String> stream) {
307 _controller = new StreamController<List<int>>( 261 return stream.map((String string) {
308 onPauseStateChange: _pauseChanged, 262 var bytes = _encode(string);
309 onSubscriptionStateChange: _subscriptionChanged); 263 if (bytes == null) {
310 _subscription = stream.listen( 264 throw new FormatException("Invalid character for encoding");
311 (string) { 265 }
312 var bytes = _encode(string); 266 return bytes;
313 if (bytes == null) { 267 });
314 _controller.signalError(new FormatException(
315 "Invalid character for encoding"));
316 _controller.close();
317 _subscription.cancel();
318 } else {
319 _controller.add(bytes);
320 }
321 },
322 onDone: _controller.close,
323 onError: _controller.signalError);
324 return _controller.stream;
325 } 268 }
326 269
327 List<int> _encode(String string); 270 List<int> _encode(String string);
328
329 void _pauseChanged() {
330 if (_controller.isPaused) {
331 _subscription.pause();
332 } else {
333 _subscription.resume();
334 }
335 }
336
337 void _subscriptionChanged() {
338 if (!_controller.hasSubscribers) {
339 _subscription.cancel();
340 }
341 }
342 } 271 }
343 272
344 273
345 // Utility class for encoding a string into an ASCII byte stream. 274 // Utility class for encoding a string into an ASCII byte stream.
346 class _AsciiEncoder extends _SingleByteEncoder { 275 class _AsciiEncoder extends _SingleByteEncoder {
347 List<int> _encode(String string) { 276 List<int> _encode(String string) {
348 var bytes = string.codeUnits; 277 var bytes = string.codeUnits;
349 for (var byte in bytes) { 278 for (var byte in bytes) {
350 if (byte > 127) return null; 279 if (byte > 127) return null;
351 } 280 }
(...skipping 21 matching lines...) Expand all
373 class _WindowsCodePageEncoder extends _SingleByteEncoder { 302 class _WindowsCodePageEncoder extends _SingleByteEncoder {
374 List<int> _encode(String string) => _encodeString(string); 303 List<int> _encode(String string) => _encodeString(string);
375 304
376 external static List<int> _encodeString(String string); 305 external static List<int> _encodeString(String string);
377 } 306 }
378 307
379 308
380 // Utility class for decoding Windows current code page data delivered 309 // Utility class for decoding Windows current code page data delivered
381 // as a stream of bytes. 310 // as a stream of bytes.
382 class _WindowsCodePageDecoder implements StreamTransformer<List<int>, String> { 311 class _WindowsCodePageDecoder implements StreamTransformer<List<int>, String> {
383 StreamSubscription<List<int>> _subscription;
384 StreamController<String> _controller;
385
386 Stream<String> bind(Stream<List<int>> stream) { 312 Stream<String> bind(Stream<List<int>> stream) {
387 _controller = new StreamController<String>( 313 return stream.map(_decodeBytes);
388 onPauseStateChange: _pauseChanged,
389 onSubscriptionStateChange: _subscriptionChanged);
390 _subscription = stream.listen(
391 (data) {
392 _controller.add(_decodeBytes(data));
393 },
394 onDone: _controller.close,
395 onError: _controller.signalError);
396 return _controller.stream;
397 } 314 }
398 315
399 external static String _decodeBytes(List<int> bytes); 316 external static String _decodeBytes(List<int> bytes);
400
401 void _pauseChanged() {
402 if (_controller.isPaused) {
403 _subscription.pause();
404 } else {
405 _subscription.resume();
406 }
407 }
408
409 void _subscriptionChanged() {
410 if (!_controller.hasSubscribers) {
411 _subscription.cancel();
412 }
413 }
414 } 317 }
OLDNEW
« no previous file with comments | « sdk/lib/async/stream.dart ('k') | tests/standalone/io/string_transformer_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698