Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 #library("input_stream"); | 5 #library("input_stream"); |
| 6 | 6 |
| 7 #import("entry.dart"); | 7 #import("entry.dart"); |
| 8 #import("read_request.dart"); | 8 #import("read_request.dart"); |
| 9 #import("utils.dart"); | 9 #import("utils.dart"); |
| 10 | 10 |
| 11 // TODO(nweiz): ensure that the C struct associated with an input stream gets | |
| 12 // freed if the stream gets garbage collected before it's closed. | |
| 13 /** | 11 /** |
| 14 * A stream of [ArchiveEntry]s being read from an archive. | 12 * A stream of [ArchiveEntry]s being read from an archive. |
| 15 * | 13 * |
| 16 * This is accessible via [ArchiveReader]. | 14 * This is accessible via [ArchiveReader]. |
| 17 */ | 15 */ |
| 18 class ArchiveInputStream { | 16 class ArchiveInputStream { |
| 19 /** | 17 /** |
| 20 * The id of the underlying archive. | 18 * The id of the underlying archive. |
| 21 * | 19 * |
| 22 * This will be set to null once the input stream has finished reading from | 20 * This will be set to null once the input stream has finished reading from |
| 23 * the archive. | 21 * the archive. |
| 24 */ | 22 */ |
| 25 int _id; | 23 final Reference<int> _id; |
| 26 | 24 |
| 27 /** A [Completer] that will fire once the [_onEntry] callback is set. */ | 25 /** A [Completer] that will fire once the [_onEntry] callback is set. */ |
| 28 final Completer<Function> _onEntryCompleter; | 26 final Completer<Function> _onEntryCompleter; |
| 29 | 27 |
| 30 /** The callback to call when the input stream is closed. */ | 28 /** The callback to call when the input stream is closed. */ |
| 31 Function _onClosed; | 29 Function _onClosed; |
| 32 | 30 |
| 33 /** The callback to call when an error occurs. */ | 31 /** The callback to call when an error occurs. */ |
| 34 Function _onError; | 32 Function _onError; |
| 35 | 33 |
| 36 /** The entry that is currently eligible to read data from the archive. */ | 34 /** The entry that is currently eligible to read data from the archive. */ |
| 37 ArchiveEntry _currentEntry; | 35 ArchiveEntry _currentEntry; |
| 38 | 36 |
| 39 ArchiveInputStream(this._id) : _onEntryCompleter = new Completer<Function>() { | 37 ArchiveInputStream(int id) : _id = new Reference<int>(id), |
|
Bob Nystrom
2012/08/01 23:52:36
How about moving : to the next line and not indent
| |
| 38 _onEntryCompleter = new Completer<Function>() { | |
| 40 var future = _consumeHeaders(); | 39 var future = _consumeHeaders(); |
| 41 future.handleException((e) { | 40 future.handleException((e) { |
| 42 if (_onError != null) { | 41 if (_onError != null) { |
| 43 _onError(e, future.stackTrace); | 42 _onError(e, future.stackTrace); |
| 44 return true; | 43 return true; |
| 45 } else { | 44 } else { |
| 46 throw e; | 45 throw e; |
| 47 } | 46 } |
| 48 }); | 47 }); |
| 49 | 48 |
| 50 future.then((_) { | 49 future.then((_) { |
| 51 close(); | 50 close(); |
| 52 if (_onClosed != null) _onClosed(); | 51 if (_onClosed != null) _onClosed(); |
| 53 }); | 52 }); |
| 53 | |
| 54 attachFinalizer(this, (id) { | |
| 55 if (id.value != null) call(FREE, id.value).then(() {}); | |
| 56 }, _id); | |
| 54 } | 57 } |
| 55 | 58 |
| 56 /** Whether this stream has finished reading entries. */ | 59 /** Whether this stream has finished reading entries. */ |
| 57 bool get closed() => _id == null; | 60 bool get closed() => _id.value == null; |
| 58 | 61 |
| 59 /** | 62 /** |
| 60 * Sets a callback to call when a new entry is read from the archive. | 63 * Sets a callback to call when a new entry is read from the archive. |
| 61 * | 64 * |
| 62 * The [ArchiveEntry] that's read from an archive initially only contains | 65 * The [ArchiveEntry] that's read from an archive initially only contains |
| 63 * header information such as the filename and permissions. To get the actual | 66 * header information such as the filename and permissions. To get the actual |
| 64 * data contained in the entry, use [ArchiveEntry.openInputStream]. | 67 * data contained in the entry, use [ArchiveEntry.openInputStream]. |
| 65 * | 68 * |
| 66 * Since the entries are read in sequence from the archive, the data stream | 69 * Since the entries are read in sequence from the archive, the data stream |
| 67 * for one entry must be opened before the next entry is read from the | 70 * for one entry must be opened before the next entry is read from the |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 89 */ | 92 */ |
| 90 void set onError(void callback(e, stack)) { | 93 void set onError(void callback(e, stack)) { |
| 91 _onError = callback; | 94 _onError = callback; |
| 92 } | 95 } |
| 93 | 96 |
| 94 /** | 97 /** |
| 95 * Closes the input stream. No more entries will be emitted. | 98 * Closes the input stream. No more entries will be emitted. |
| 96 */ | 99 */ |
| 97 void close() { | 100 void close() { |
| 98 if (closed) return; | 101 if (closed) return; |
| 99 call(FREE, _id).then((_) {}); | 102 call(FREE, _id.value).then((_) {}); |
| 100 _id = null; | 103 _id.value = null; |
| 101 if (_currentEntry != null) _currentEntry.close(); | 104 if (_currentEntry != null) _currentEntry.close(); |
| 102 if (!_onEntryCompleter.future.isComplete) _onEntryCompleter.complete(null); | 105 if (!_onEntryCompleter.future.isComplete) _onEntryCompleter.complete(null); |
| 103 } | 106 } |
| 104 | 107 |
| 105 /** | 108 /** |
| 106 * Consumes and emits all [ArchiveEntries] in this archive. | 109 * Consumes and emits all [ArchiveEntries] in this archive. |
| 107 */ | 110 */ |
| 108 Future _consumeHeaders() { | 111 Future _consumeHeaders() { |
| 109 if (closed) return new Future.immediate(null); | 112 if (closed) return new Future.immediate(null); |
| 110 var data; | 113 var data; |
| 111 return call(NEXT_HEADER, _id).chain((_data) { | 114 return call(NEXT_HEADER, _id.value).chain((_data) { |
| 112 data = _data; | 115 data = _data; |
| 113 if (data == null) return new Future.immediate(null); | 116 if (data == null) return new Future.immediate(null); |
| 114 return _emit(new ArchiveEntry(_id, data)). | 117 return _emit(new ArchiveEntry(_id.value, data)). |
| 115 chain((_) => _consumeHeaders()); | 118 chain((_) => _consumeHeaders()); |
| 116 }); | 119 }); |
| 117 } | 120 } |
| 118 | 121 |
| 119 /** | 122 /** |
| 120 * Emits [entry] to the [onEntry] callback. Returns a [Future] that will | 123 * Emits [entry] to the [onEntry] callback. Returns a [Future] that will |
| 121 * complete once the callback's return value completes and the entry's data | 124 * complete once the callback's return value completes and the entry's data |
| 122 * has been fully consumed. | 125 * has been fully consumed. |
| 123 */ | 126 */ |
| 124 Future _emit(ArchiveEntry entry) { | 127 Future _emit(ArchiveEntry entry) { |
| 125 _currentEntry = entry; | 128 _currentEntry = entry; |
| 126 var future = _onEntryCompleter.future.chain((onEntry) { | 129 var future = _onEntryCompleter.future.chain((onEntry) { |
| 127 if (closed) return new Future.immediate(null); | 130 if (closed) return new Future.immediate(null); |
| 128 var result = onEntry(entry); | 131 var result = onEntry(entry); |
| 129 if (result is Future) return result; | 132 if (result is Future) return result; |
| 130 return new Future.immediate(null); | 133 return new Future.immediate(null); |
| 131 }).chain((_) { | 134 }).chain((_) { |
| 132 if (entry.isInputOpen) return entry.inputComplete; | 135 if (entry.isInputOpen) return entry.inputComplete; |
| 133 return new Future.immediate(null); | 136 return new Future.immediate(null); |
| 134 }); | 137 }); |
| 135 future.onComplete((_) { | 138 future.onComplete((_) { |
| 136 _currentEntry = null; | 139 _currentEntry = null; |
| 137 entry.close(); | 140 entry.close(); |
| 138 }); | 141 }); |
| 139 return future; | 142 return future; |
| 140 } | 143 } |
| 141 } | 144 } |
| OLD | NEW |