| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 // Interface for decoders decoding binary data into string data. The | 5 // Interface for decoders decoding binary data into string data. The |
| 6 // decoder keeps track of line breaks during decoding. | 6 // decoder keeps track of line breaks during decoding. |
| 7 interface _StringDecoder { | 7 interface _StringDecoder { |
| 8 // Add more binary data to be decoded. The ownership of the buffer | 8 // Add more binary data to be decoded. The ownership of the buffer |
| 9 // is transfered to the decoder and the caller most not modify it any more. | 9 // is transfered to the decoder and the caller most not modify it any more. |
| 10 int write(List<int> buffer); | 10 int write(List<int> buffer); |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 } else if (_encoding == "ASCII") { | 225 } else if (_encoding == "ASCII") { |
| 226 _decoder = new _AsciiDecoder(); | 226 _decoder = new _AsciiDecoder(); |
| 227 } else { | 227 } else { |
| 228 throw new StreamException("Unsupported encoding $_encoding"); | 228 throw new StreamException("Unsupported encoding $_encoding"); |
| 229 } | 229 } |
| 230 _input.dataHandler = _dataHandler; | 230 _input.dataHandler = _dataHandler; |
| 231 _input.closeHandler = _closeHandler; | 231 _input.closeHandler = _closeHandler; |
| 232 } | 232 } |
| 233 | 233 |
| 234 String read() { | 234 String read() { |
| 235 // If there is buffered data return that first. | 235 String result = _decoder.decoded; |
| 236 var decodedString = _decoder.decoded; | 236 _checkInstallDataHandler(); |
| 237 if (decodedString !== null) { | 237 return result; |
| 238 if (_inputClosed && _decoder.isEmpty()) { | |
| 239 _streamClosed(); | |
| 240 } | |
| 241 return decodedString; | |
| 242 } else if (_inputClosed) { | |
| 243 _streamClosed(); | |
| 244 return null; | |
| 245 } else { | |
| 246 _readData(); | |
| 247 return _decoder.decoded; | |
| 248 } | |
| 249 } | 238 } |
| 250 | 239 |
| 251 String readLine() { | 240 String readLine() { |
| 252 if (_closed) return null; | 241 String decodedLine = _decoder.decodedLine; |
| 253 | 242 if (decodedLine == null) { |
| 254 if (_decoder.lineBreaks == 0) { | 243 if (_inputClosed) { |
| 255 _readData(); | 244 // Last line might not have a line separator. |
| 245 decodedLine = _decoder.decoded; |
| 246 if (decodedLine != null && |
| 247 decodedLine[decodedLine.length - 1] == '\r') { |
| 248 decodedLine = decodedLine.substring(0, decodedLine.length - 1); |
| 249 } |
| 250 } |
| 256 } | 251 } |
| 257 var decodedLine = _decoder.decodedLine; | 252 _checkInstallDataHandler(); |
| 258 if (decodedLine !== null) { | 253 return decodedLine; |
| 259 if (_inputClosed && _decoder.isEmpty()) { | |
| 260 _streamClosed(); | |
| 261 } | |
| 262 return decodedLine; | |
| 263 } | |
| 264 if (_inputClosed) { | |
| 265 decodedLine = _decoder.decoded; | |
| 266 if (decodedLine[decodedLine.length - 1] == '\r') { | |
| 267 decodedLine = decodedLine.substring(0, decodedLine.length - 1); | |
| 268 } | |
| 269 _streamClosed(); | |
| 270 return decodedLine; | |
| 271 } | |
| 272 return null; | |
| 273 } | 254 } |
| 274 | 255 |
| 275 String get encoding() => _encoding; | 256 String get encoding() => _encoding; |
| 276 | 257 |
| 277 bool get closed() => _closed; | 258 bool get closed() => _inputClosed && _decoder.isEmpty(); |
| 278 | 259 |
| 279 void set dataHandler(void callback()) { | 260 void set dataHandler(void callback()) { |
| 280 _clientDataHandler = callback; | 261 _clientDataHandler = callback; |
| 281 _clientLineHandler = null; | 262 _clientLineHandler = null; |
| 263 _checkInstallDataHandler(); |
| 264 _checkScheduleCallback(); |
| 282 } | 265 } |
| 283 | 266 |
| 284 void set lineHandler(void callback()) { | 267 void set lineHandler(void callback()) { |
| 285 _clientLineHandler = callback; | 268 _clientLineHandler = callback; |
| 286 _clientDataHandler = null; | 269 _clientDataHandler = null; |
| 270 _checkInstallDataHandler(); |
| 271 _checkScheduleCallback(); |
| 287 } | 272 } |
| 288 | 273 |
| 289 void set closeHandler(void callback()) { | 274 void set closeHandler(void callback()) { |
| 290 _clientCloseHandler = callback; | 275 _clientCloseHandler = callback; |
| 291 } | 276 } |
| 292 | 277 |
| 293 void _dataHandler() { | 278 void _dataHandler() { |
| 294 _readData(); | 279 _readData(); |
| 295 if (!_decoder.isEmpty() && _clientDataHandler !== null) { | 280 if (!_decoder.isEmpty() && _clientDataHandler !== null) { |
| 296 _clientDataHandler(); | 281 _clientDataHandler(); |
| 297 } | 282 } |
| 298 if (_decoder.lineBreaks > 0 && _clientLineHandler !== null) { | 283 if (_decoder.lineBreaks > 0 && _clientLineHandler !== null) { |
| 299 _clientLineHandler(); | 284 _clientLineHandler(); |
| 300 } | 285 } |
| 286 _checkScheduleCallback(); |
| 287 _checkInstallDataHandler(); |
| 301 } | 288 } |
| 302 | 289 |
| 303 void _closeHandler() { | 290 void _closeHandler() { |
| 304 _inputClosed = true; | 291 _inputClosed = true; |
| 305 if (!_decoder.isEmpty()) { | 292 if (_decoder.isEmpty() && _clientCloseHandler != null) { |
| 306 // If there is still data buffered call the data handler. | 293 _clientCloseHandler(); |
| 307 if (_clientDataHandler !== null) _clientDataHandler(); | 294 _closed = true; |
| 308 if (_clientLineHandler !== null) _clientLineHandler(); | |
| 309 } else { | 295 } else { |
| 310 _closed = true; | 296 _checkScheduleCallback(); |
| 311 if (_clientCloseHandler !== null) _clientCloseHandler(); | |
| 312 } | 297 } |
| 313 } | 298 } |
| 314 | 299 |
| 315 void _readData() { | 300 void _readData() { |
| 316 List<int> data = _input.read(); | 301 List<int> data = _input.read(); |
| 317 if (data !== null) { | 302 if (data !== null) { |
| 318 _decoder.write(data); | 303 _decoder.write(data); |
| 319 } | 304 } |
| 320 } | 305 } |
| 321 | 306 |
| 322 void _streamClosed() { | 307 void _checkInstallDataHandler() { |
| 323 _closed = true; | 308 if (_inputClosed || |
| 309 (_clientDataHandler === null && _clientLineHandler === null)) { |
| 310 _input.dataHandler = null; |
| 311 } else if (_clientDataHandler !== null) { |
| 312 if (_decoder.isEmpty()) { |
| 313 _input.dataHandler = _dataHandler; |
| 314 } else { |
| 315 _input.dataHandler = null; |
| 316 } |
| 317 } else { |
| 318 assert(_clientLineHandler !== null); |
| 319 if (_decoder.lineBreaks == 0) { |
| 320 _input.dataHandler = _dataHandler; |
| 321 } else { |
| 322 _input.dataHandler = null; |
| 323 } |
| 324 } |
| 325 } |
| 324 | 326 |
| 325 // TODO(sgjesse): Find a better way of scheduling callbacks from | 327 // TODO(sgjesse): Find a better way of scheduling callbacks from |
| 326 // the event loop. | 328 // the event loop. |
| 329 void _checkScheduleCallback() { |
| 330 void issueDataCallback(Timer timer) { |
| 331 _scheduledDataCallback = null; |
| 332 if (_clientDataHandler !== null) { |
| 333 _clientDataHandler(); |
| 334 _checkScheduleCallback(); |
| 335 } |
| 336 } |
| 337 |
| 338 void issueLineCallback(Timer timer) { |
| 339 _scheduledLineCallback = null; |
| 340 if (_clientLineHandler !== null) { |
| 341 _clientLineHandler(); |
| 342 _checkScheduleCallback(); |
| 343 } |
| 344 } |
| 345 |
| 327 void issueCloseCallback(Timer timer) { | 346 void issueCloseCallback(Timer timer) { |
| 328 if (_clientCloseHandler !== null) _clientCloseHandler(); | 347 _scheduledCloseCallback = null; |
| 348 if (!_closed) { |
| 349 if (_clientCloseHandler !== null) _clientCloseHandler(); |
| 350 _closed = true; |
| 351 } |
| 329 } | 352 } |
| 330 new Timer(issueCloseCallback, 0, false); | 353 |
| 354 if (!_closed) { |
| 355 // Schedule data callback if string data available. |
| 356 if (_clientDataHandler != null && |
| 357 !_decoder.isEmpty() && |
| 358 _scheduledDataCallback == null) { |
| 359 if (_scheduledLineCallback != null) _scheduledLineCallback.cancel(); |
| 360 _scheduledDataCallback = new Timer(issueDataCallback, 0, false); |
| 361 } |
| 362 |
| 363 // Schedule line callback if a line is available. |
| 364 if (_clientLineHandler != null && |
| 365 (_decoder.lineBreaks > 0 || (!_decoder.isEmpty() && _inputClosed)) && |
| 366 _scheduledLineCallback == null) { |
| 367 if (_scheduledDataCallback != null) _scheduledDataCallback.cancel(); |
| 368 _scheduledLineCallback = new Timer(issueLineCallback, 0, false); |
| 369 } |
| 370 |
| 371 // Schedule close callback if no more data and input is closed. |
| 372 if (_decoder.isEmpty() && |
| 373 _inputClosed && |
| 374 _scheduledCloseCallback == null) { |
| 375 _scheduledCloseCallback = new Timer(issueCloseCallback, 0, false); |
| 376 } |
| 377 } |
| 331 } | 378 } |
| 332 | 379 |
| 333 InputStream _input; | 380 InputStream _input; |
| 334 String _encoding; | 381 String _encoding; |
| 335 _StringDecoder _decoder; | 382 _StringDecoder _decoder; |
| 336 bool _inputClosed = false; // Is the underlying input stream closed? | 383 bool _inputClosed = false; // Is the underlying input stream closed? |
| 337 bool _closed = false; // Is this stream closed. | 384 bool _closed = false; // Is this stream closed. |
| 338 bool _eof = false; // Has all data been read from the decoder? | 385 bool _eof = false; // Has all data been read from the decoder? |
| 339 var _clientDataHandler; | 386 Timer _scheduledDataCallback; |
| 340 var _clientLineHandler; | 387 Timer _scheduledLineCallback; |
| 341 var _clientCloseHandler; | 388 Timer _scheduledCloseCallback; |
| 389 Function _clientDataHandler; |
| 390 Function _clientLineHandler; |
| 391 Function _clientCloseHandler; |
| 342 } | 392 } |
| OLD | NEW |