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

Side by Side Diff: utils/archive/input_stream.dart

Issue 10842002: Add the beginnings of a Dart wrapper for libarchive. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Merge Created 8 years, 4 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 | « utils/archive/entry.dart ('k') | utils/archive/messaging.h » ('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) 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
3 // BSD-style license that can be found in the LICENSE file.
4
5 #library("input_stream");
6
7 #import("entry.dart");
8 #import("read_request.dart");
9 #import("utils.dart");
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 /**
14 * A stream of [ArchiveEntry]s being read from an archive.
15 *
16 * This is accessible via [ArchiveReader].
17 */
18 class ArchiveInputStream {
19 /**
20 * The id of the underlying archive.
21 *
22 * This will be set to null once the input stream has finished reading from
23 * the archive.
24 */
25 int _id;
26
27 /** A [Completer] that will fire once the [_onEntry] callback is set. */
28 final Completer<Function> _onEntryCompleter;
29
30 /** The callback to call when the input stream is closed. */
31 Function _onClosed;
32
33 /** The callback to call when an error occurs. */
34 Function _onError;
35
36 /** The entry that is currently eligible to read data from the archive. */
37 ArchiveEntry _currentEntry;
38
39 ArchiveInputStream(this._id) : _onEntryCompleter = new Completer<Function>() {
40 var future = _consumeHeaders();
41 future.handleException((e) {
42 if (_onError != null) {
43 _onError(e, future.stackTrace);
44 return true;
45 } else {
46 throw e;
47 }
48 });
49
50 future.then((_) {
51 close();
52 if (_onClosed != null) _onClosed();
53 });
54 }
55
56 /** Whether this stream has finished reading entries. */
57 bool get closed() => _id == null;
58
59 /**
60 * Sets a callback to call when a new entry is read from the archive.
61 *
62 * The [ArchiveEntry] that's read from an archive initially only contains
63 * header information such as the filename and permissions. To get the actual
64 * data contained in the entry, use [ArchiveEntry.openInputStream].
65 *
66 * 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
68 * archive. The next entry will not be read until the return value of
69 * [callback] has completed.
70 *
71 * If [callback] calls [ArchiveEntry.openInputStream] before it returns, or if
72 * it doesn't want to read the contents of [entry], it can return null.
73 */
74 void set onEntry(Future callback(ArchiveEntry entry)) {
75 _onEntryCompleter.complete(callback);
76 }
77
78 /**
79 * Sets a callback to call when the input stream is done emitting entries.
80 */
81 void set onClosed(void callback()) {
82 _onClosed = callback;
83 }
84
85 /**
86 * Sets a callback to call if an error occurs while extracting the archive.
87 *
88 * [e] is the error that occured and [stack] is the stack trace of the error.
89 */
90 void set onError(void callback(e, stack)) {
91 _onError = callback;
92 }
93
94 /**
95 * Closes the input stream. No more entries will be emitted.
96 */
97 void close() {
98 if (closed) return;
99 call(FREE, _id).then((_) {});
100 _id = null;
101 if (_currentEntry != null) _currentEntry.close();
102 if (!_onEntryCompleter.future.isComplete) _onEntryCompleter.complete(null);
103 }
104
105 /**
106 * Consumes and emits all [ArchiveEntries] in this archive.
107 */
108 Future _consumeHeaders() {
109 if (closed) return new Future.immediate(null);
110 var data;
111 return call(NEXT_HEADER, _id).chain((_data) {
112 data = _data;
113 if (data == null) return new Future.immediate(null);
114 return _emit(new ArchiveEntry(_id, data)).
115 chain((_) => _consumeHeaders());
116 });
117 }
118
119 /**
120 * 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
122 * has been fully consumed.
123 */
124 Future _emit(ArchiveEntry entry) {
125 _currentEntry = entry;
126 var future = _onEntryCompleter.future.chain((onEntry) {
127 if (closed) return new Future.immediate(null);
128 var result = onEntry(entry);
129 if (result is Future) return result;
130 return new Future.immediate(null);
131 }).chain((_) {
132 if (entry.isInputOpen) return entry.inputComplete;
133 return new Future.immediate(null);
134 });
135 future.onComplete((_) {
136 _currentEntry = null;
137 entry.close();
138 });
139 return future;
140 }
141 }
OLDNEW
« no previous file with comments | « utils/archive/entry.dart ('k') | utils/archive/messaging.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698