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

Unified 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, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « utils/archive/entry.dart ('k') | utils/archive/messaging.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: utils/archive/input_stream.dart
diff --git a/utils/archive/input_stream.dart b/utils/archive/input_stream.dart
new file mode 100644
index 0000000000000000000000000000000000000000..4ccb00034bda4a5de72d09ab3de773d360c2093a
--- /dev/null
+++ b/utils/archive/input_stream.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#library("input_stream");
+
+#import("entry.dart");
+#import("read_request.dart");
+#import("utils.dart");
+
+// TODO(nweiz): ensure that the C struct associated with an input stream gets
+// freed if the stream gets garbage collected before it's closed.
+/**
+ * A stream of [ArchiveEntry]s being read from an archive.
+ *
+ * This is accessible via [ArchiveReader].
+ */
+class ArchiveInputStream {
+ /**
+ * The id of the underlying archive.
+ *
+ * This will be set to null once the input stream has finished reading from
+ * the archive.
+ */
+ int _id;
+
+ /** A [Completer] that will fire once the [_onEntry] callback is set. */
+ final Completer<Function> _onEntryCompleter;
+
+ /** The callback to call when the input stream is closed. */
+ Function _onClosed;
+
+ /** The callback to call when an error occurs. */
+ Function _onError;
+
+ /** The entry that is currently eligible to read data from the archive. */
+ ArchiveEntry _currentEntry;
+
+ ArchiveInputStream(this._id) : _onEntryCompleter = new Completer<Function>() {
+ var future = _consumeHeaders();
+ future.handleException((e) {
+ if (_onError != null) {
+ _onError(e, future.stackTrace);
+ return true;
+ } else {
+ throw e;
+ }
+ });
+
+ future.then((_) {
+ close();
+ if (_onClosed != null) _onClosed();
+ });
+ }
+
+ /** Whether this stream has finished reading entries. */
+ bool get closed() => _id == null;
+
+ /**
+ * Sets a callback to call when a new entry is read from the archive.
+ *
+ * The [ArchiveEntry] that's read from an archive initially only contains
+ * header information such as the filename and permissions. To get the actual
+ * data contained in the entry, use [ArchiveEntry.openInputStream].
+ *
+ * Since the entries are read in sequence from the archive, the data stream
+ * for one entry must be opened before the next entry is read from the
+ * archive. The next entry will not be read until the return value of
+ * [callback] has completed.
+ *
+ * If [callback] calls [ArchiveEntry.openInputStream] before it returns, or if
+ * it doesn't want to read the contents of [entry], it can return null.
+ */
+ void set onEntry(Future callback(ArchiveEntry entry)) {
+ _onEntryCompleter.complete(callback);
+ }
+
+ /**
+ * Sets a callback to call when the input stream is done emitting entries.
+ */
+ void set onClosed(void callback()) {
+ _onClosed = callback;
+ }
+
+ /**
+ * Sets a callback to call if an error occurs while extracting the archive.
+ *
+ * [e] is the error that occured and [stack] is the stack trace of the error.
+ */
+ void set onError(void callback(e, stack)) {
+ _onError = callback;
+ }
+
+ /**
+ * Closes the input stream. No more entries will be emitted.
+ */
+ void close() {
+ if (closed) return;
+ call(FREE, _id).then((_) {});
+ _id = null;
+ if (_currentEntry != null) _currentEntry.close();
+ if (!_onEntryCompleter.future.isComplete) _onEntryCompleter.complete(null);
+ }
+
+ /**
+ * Consumes and emits all [ArchiveEntries] in this archive.
+ */
+ Future _consumeHeaders() {
+ if (closed) return new Future.immediate(null);
+ var data;
+ return call(NEXT_HEADER, _id).chain((_data) {
+ data = _data;
+ if (data == null) return new Future.immediate(null);
+ return _emit(new ArchiveEntry(_id, data)).
+ chain((_) => _consumeHeaders());
+ });
+ }
+
+ /**
+ * Emits [entry] to the [onEntry] callback. Returns a [Future] that will
+ * complete once the callback's return value completes and the entry's data
+ * has been fully consumed.
+ */
+ Future _emit(ArchiveEntry entry) {
+ _currentEntry = entry;
+ var future = _onEntryCompleter.future.chain((onEntry) {
+ if (closed) return new Future.immediate(null);
+ var result = onEntry(entry);
+ if (result is Future) return result;
+ return new Future.immediate(null);
+ }).chain((_) {
+ if (entry.isInputOpen) return entry.inputComplete;
+ return new Future.immediate(null);
+ });
+ future.onComplete((_) {
+ _currentEntry = null;
+ entry.close();
+ });
+ return future;
+ }
+}
« 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