--- /dev/null
+/* This file is part of Cinaest.
+ *
+ * Copyright (C) 2009 Philipp Zabel
+ *
+ * Cinaest is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cinaest is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cinaest. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using GLib;
+using ZLib;
+
+class GzipInputStream : FilterInputStream {
+ // 256KB buffer size
+ const int CHUNK = 256*1024;
+
+ InflateStream strm;
+ public uchar[] buf_in;
+
+ public GzipInputStream (GLib.InputStream _base_stream) {
+ base_stream = _base_stream;
+ strm = InflateStream.full (15 | 32);
+ }
+
+ construct {
+ buf_in = new uchar[CHUNK];
+ }
+
+ public async override ssize_t read_async (void *buffer, size_t count, int io_priority, Cancellable? cancellable) throws Error {
+ int ret = Status.OK;
+ ssize_t n;
+
+ if (strm.avail_in == 0) {
+ n = yield base_stream.read_async (buf_in, CHUNK, io_priority, cancellable);
+ strm.avail_in = (uint) n;
+ if (strm.avail_in == 0)
+ return -1;
+ strm.next_in = buf_in;
+ }
+
+ strm.avail_out = (int) count;
+ strm.next_out = buffer;
+
+ ret = strm.inflate (Flush.NONE);
+ assert (ret != Status.STREAM_ERROR);
+ if (ret == Status.NEED_DICT)
+ ret = Status.DATA_ERROR;
+ switch (ret) {
+ case Status.DATA_ERROR:
+ case Status.MEM_ERROR:
+ throw new IOError.FAILED("Error in gzip stream");
+ }
+
+ return (ssize_t) count - strm.avail_out;
+ }
+
+ public override ssize_t read_fn (void *buffer, size_t count, Cancellable? cancellable) throws Error {
+ int ret = Status.OK;
+
+ if (strm.avail_in == 0) {
+ strm.avail_in = (int) base_stream.read (buf_in, CHUNK, cancellable);
+ if (strm.avail_in == 0)
+ return -1;
+ strm.next_in = buf_in;
+ }
+
+ strm.avail_out = (int) count;
+ strm.next_out = buffer;
+
+ ret = strm.inflate (Flush.NONE);
+ assert (ret != Status.STREAM_ERROR);
+ if (ret == Status.NEED_DICT)
+ ret = Status.DATA_ERROR;
+ switch (ret) {
+ case Status.DATA_ERROR:
+ case Status.MEM_ERROR:
+ return -1;
+ }
+
+ return (ssize_t) count - strm.avail_out;
+ }
+
+ public ulong total_in () {
+ return strm.total_in;
+ }
+}