/* 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 . */ 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; } }