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

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

Issue 12313127: Fix subscription handling in stream decoder (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Added missing file Created 7 years, 9 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
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
162 StreamSubscription<String> _subscription;
163 StreamController<String> _controller;
164 String _carry; 161 String _carry;
165 162
166 Stream<String> bind(Stream<String> stream) { 163 void handle(String data, StreamSink<String> sink, bool isClosing) {
floitsch 2013/02/26 14:47:26 make it private.
Søren Gjesse 2013/02/26 15:23:33 Done.
167 _controller = new StreamController<String>( 164 if (_carry != null) {
168 onPauseStateChange: _pauseChanged, 165 data = _carry.concat(data);
169 onSubscriptionStateChange: _subscriptionChanged); 166 _carry = null;
170 167 }
171 void handle(String data, bool isClosing) { 168 int startPos = 0;
172 if (_carry != null) { 169 int pos = 0;
173 data = _carry.concat(data); 170 while (pos < data.length) {
174 _carry = null; 171 int skip = 0;
175 } 172 int char = data.codeUnitAt(pos);
176 int startPos = 0; 173 if (char == _LF) {
177 int pos = 0; 174 skip = 1;
178 while (pos < data.length) { 175 } else if (char == _CR) {
179 int skip = 0; 176 skip = 1;
180 int char = data.codeUnitAt(pos); 177 if (pos + 1 < data.length) {
181 if (char == _LF) { 178 if (data.codeUnitAt(pos + 1) == _LF) {
182 skip = 1; 179 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 } 180 }
193 } 181 } else if (!isClosing) {
194 if (skip > 0) { 182 _carry = data.substring(startPos);
195 _buffer.add(data.substring(startPos, pos)); 183 return;
196 _controller.add(_buffer.toString());
197 _buffer.clear();
198 startPos = pos = pos + skip;
199 } else {
200 pos++;
201 } 184 }
202 } 185 }
203 if (pos != startPos) { 186 if (skip > 0) {
204 // Add remaining
205 _buffer.add(data.substring(startPos, pos)); 187 _buffer.add(data.substring(startPos, pos));
206 } 188 sink.add(_buffer.toString());
207 if (isClosing && !_buffer.isEmpty) {
208 _controller.add(_buffer.toString());
209 _buffer.clear(); 189 _buffer.clear();
190 startPos = pos = pos + skip;
191 } else {
192 pos++;
210 } 193 }
211 } 194 }
212 195 if (pos != startPos) {
213 _subscription = stream.listen( 196 // Add remaining
214 (data) => handle(data, false), 197 _buffer.add(data.substring(startPos, pos));
215 onDone: () { 198 }
216 // Handle remaining data (mainly _carry). 199 if (isClosing && !_buffer.isEmpty) {
217 handle("", true); 200 sink.add(_buffer.toString());
218 _controller.close(); 201 _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 } 202 }
230 } 203 }
231 204
232 void _subscriptionChanged() { 205 void handleData(String data, StreamSink<String> sink) {
233 if (!_controller.hasSubscribers) { 206 handle(data, sink, false);
234 _subscription.cancel(); 207 }
235 } 208
209 void handleDone(StreamSink<String> sink) {
210 handle("", sink, true);
floitsch 2013/02/26 14:47:26 sink.close()
Søren Gjesse 2013/02/26 15:23:33 Thanks.
236 } 211 }
237 } 212 }
238 213
239 214
240 class _SingleByteDecoder implements StreamTransformer<List<int>, String> { 215 class _SingleByteDecoder extends StreamEventTransformer<List<int>, String> {
241 StreamSubscription<List<int>> _subscription;
242 StreamController<String> _controller;
243 final int _replacementChar; 216 final int _replacementChar;
244 217
245 _SingleByteDecoder(this._replacementChar); 218 _SingleByteDecoder(this._replacementChar);
246 219
247 Stream<String> bind(Stream<List<int>> stream) { 220 void handleData(List<int> data, StreamSink<String> sink) {
248 _controller = new StreamController<String>( 221 var buffer = new List<int>.fixedLength(data.length);
249 onPauseStateChange: _pauseChanged, 222 for (int i = 0; i < data.length; i++) {
250 onSubscriptionStateChange: _subscriptionChanged); 223 int char = _decodeByte(data[i]);
251 _subscription = stream.listen( 224 if (char < 0) char = _replacementChar;
252 (data) { 225 buffer[i] = char;
253 var buffer = new List<int>.fixedLength(data.length); 226 }
254 for (int i = 0; i < data.length; i++) { 227 sink.add(new String.fromCharCodes(buffer));
255 int char = _decodeByte(data[i]);
256 if (char < 0) char = _replacementChar;
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 } 228 }
265 229
266 int _decodeByte(int byte); 230 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 } 231 }
282 232
283 233
284 // Utility class for decoding ascii data delivered as a stream of 234 // Utility class for decoding ascii data delivered as a stream of
285 // bytes. 235 // bytes.
286 class _AsciiDecoder extends _SingleByteDecoder { 236 class _AsciiDecoder extends _SingleByteDecoder {
287 _AsciiDecoder(int replacementChar) : super(replacementChar); 237 _AsciiDecoder(int replacementChar) : super(replacementChar);
288 238
289 int _decodeByte(int byte) => ((byte & 0x7f) == byte) ? byte : -1; 239 int _decodeByte(int byte) => ((byte & 0x7f) == byte) ? byte : -1;
290 } 240 }
291 241
292 242
293 // Utility class for decoding Latin-1 data delivered as a stream of 243 // Utility class for decoding Latin-1 data delivered as a stream of
294 // bytes. 244 // bytes.
295 class _Latin1Decoder extends _SingleByteDecoder { 245 class _Latin1Decoder extends _SingleByteDecoder {
296 _Latin1Decoder(int replacementChar) : super(replacementChar); 246 _Latin1Decoder(int replacementChar) : super(replacementChar);
297 247
298 int _decodeByte(int byte) => ((byte & 0xFF) == byte) ? byte : -1; 248 int _decodeByte(int byte) => ((byte & 0xFF) == byte) ? byte : -1;
299 } 249 }
300 250
301 251
302 class _SingleByteEncoder implements StreamTransformer<String, List<int>> { 252 class _SingleByteEncoder extends StreamEventTransformer<String, List<int>> {
303 StreamSubscription<String> _subscription; 253 void handleData(String data, StreamSink<List<int>> sink) {
304 StreamController<List<int>> _controller; 254 var bytes = _encode(data);
305 255 if (bytes == null) {
306 Stream<List<int>> bind(Stream<String> stream) { 256 throw new FormatException("Invalid character for encoding");
307 _controller = new StreamController<List<int>>( 257 sink.close();
308 onPauseStateChange: _pauseChanged, 258 } else {
309 onSubscriptionStateChange: _subscriptionChanged); 259 sink.add(bytes);
310 _subscription = stream.listen( 260 }
311 (string) {
312 var bytes = _encode(string);
313 if (bytes == null) {
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 } 261 }
326 262
327 List<int> _encode(String string); 263 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 } 264 }
343 265
344 266
345 // Utility class for encoding a string into an ASCII byte stream. 267 // Utility class for encoding a string into an ASCII byte stream.
346 class _AsciiEncoder extends _SingleByteEncoder { 268 class _AsciiEncoder extends _SingleByteEncoder {
347 List<int> _encode(String string) { 269 List<int> _encode(String string) {
348 var bytes = string.codeUnits; 270 var bytes = string.codeUnits;
349 for (var byte in bytes) { 271 for (var byte in bytes) {
350 if (byte > 127) return null; 272 if (byte > 127) return null;
351 } 273 }
(...skipping 20 matching lines...) Expand all
372 // single byte encoder, to avoid copying boilerplate. 294 // single byte encoder, to avoid copying boilerplate.
373 class _WindowsCodePageEncoder extends _SingleByteEncoder { 295 class _WindowsCodePageEncoder extends _SingleByteEncoder {
374 List<int> _encode(String string) => _encodeString(string); 296 List<int> _encode(String string) => _encodeString(string);
375 297
376 external static List<int> _encodeString(String string); 298 external static List<int> _encodeString(String string);
377 } 299 }
378 300
379 301
380 // Utility class for decoding Windows current code page data delivered 302 // Utility class for decoding Windows current code page data delivered
381 // as a stream of bytes. 303 // as a stream of bytes.
382 class _WindowsCodePageDecoder implements StreamTransformer<List<int>, String> { 304 class _WindowsCodePageDecoder extends StreamEventTransformer<List<int>, String> {
383 StreamSubscription<List<int>> _subscription; 305 void handleData(List<int> data, StreamSink<String> sink) {
384 StreamController<String> _controller; 306 sink.add(_decodeBytes(data));
385
386 Stream<String> bind(Stream<List<int>> stream) {
387 _controller = new StreamController<String>(
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 } 307 }
398 308
399 external static String _decodeBytes(List<int> bytes); 309 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 } 310 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698