diff options
author | Timo Teras <timo.teras@iki.fi> | 2008-11-07 17:11:08 +0200 |
---|---|---|
committer | Timo Teras <timo.teras@iki.fi> | 2008-11-07 17:11:08 +0200 |
commit | aef0f036f08f8949e4e2a5b84c9199ef8ec40595 (patch) | |
tree | 423ba9a4e5db4b8b38b6ccf2578c8c205ff7db4d /src/gunzip.c | |
parent | 6967c28b96784d474e6c2f50b075895d89f9ce02 (diff) | |
download | apk-tools-aef0f036f08f8949e4e2a5b84c9199ef8ec40595.tar.bz2 apk-tools-aef0f036f08f8949e4e2a5b84c9199ef8ec40595.tar.xz |
use zlib internally to decompress
Diffstat (limited to 'src/gunzip.c')
-rw-r--r-- | src/gunzip.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/gunzip.c b/src/gunzip.c new file mode 100644 index 0000000..f488fa4 --- /dev/null +++ b/src/gunzip.c @@ -0,0 +1,93 @@ +/* gunzip.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi> + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. See http://www.gnu.org/ for details. + */ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <malloc.h> +#include <zlib.h> + +#include "apk_defines.h" +#include "apk_io.h" + +struct apk_gzip_istream { + struct apk_istream is; + struct apk_bstream *bs; + z_stream zs; + int z_err; +}; + +static size_t gz_read(void *stream, void *ptr, size_t size) +{ + struct apk_gzip_istream *gis = + container_of(stream, struct apk_gzip_istream, is); + + if (gis->z_err == Z_DATA_ERROR || gis->z_err == Z_ERRNO) + return -1; + if (gis->z_err == Z_STREAM_END) + return 0; + + if (ptr == NULL) + return apk_istream_skip(&gis->is, size); + + gis->zs.avail_out = size; + gis->zs.next_out = ptr; + + while (gis->zs.avail_out != 0 && gis->z_err == Z_OK) { + if (gis->zs.avail_in == 0) { + gis->zs.avail_in = gis->bs->read(gis->bs, (void **) &gis->zs.next_in); + if (gis->zs.avail_in < 0) { + gis->z_err = Z_DATA_ERROR; + return size - gis->zs.avail_out; + } + } + + gis->z_err = inflate(&gis->zs, Z_NO_FLUSH); + } + + if (gis->z_err != Z_OK && gis->z_err != Z_STREAM_END) + return -1; + + return size - gis->zs.avail_out; +} + +static void gz_close(void *stream) +{ + struct apk_gzip_istream *gis = + container_of(stream, struct apk_gzip_istream, is); + + inflateEnd(&gis->zs); + free(gis); +} + +struct apk_istream *apk_gunzip_bstream(struct apk_bstream *bs) +{ + struct apk_gzip_istream *gis; + + gis = malloc(sizeof(struct apk_gzip_istream)); + if (gis == NULL) + return NULL; + + *gis = (struct apk_gzip_istream) { + .is.read = gz_read, + .is.splice = apk_istream_splice, + .is.close = gz_close, + .bs = bs, + .z_err = 0, + }; + + if (inflateInit2(&gis->zs, 15+32) != Z_OK) { + free(gis); + return NULL; + } + + return &gis->is; +} + |