diff options
Diffstat (limited to 'src/gunzip.c')
-rw-r--r-- | src/gunzip.c | 98 |
1 files changed, 89 insertions, 9 deletions
diff --git a/src/gunzip.c b/src/gunzip.c index af906d1..2c4387e 100644 --- a/src/gunzip.c +++ b/src/gunzip.c @@ -30,7 +30,7 @@ struct apk_gzip_istream { void *cbctx; }; -static size_t gz_read(void *stream, void *ptr, size_t size) +static size_t gzi_read(void *stream, void *ptr, size_t size) { struct apk_gzip_istream *gis = container_of(stream, struct apk_gzip_istream, is); @@ -78,11 +78,13 @@ static size_t gz_read(void *stream, void *ptr, size_t size) EVP_DigestUpdate(&gis->mdctx, gis->mdblock, (void *)gis->zs.next_in - gis->mdblock); gis->mdblock = gis->zs.next_in; - gis->cb(gis->cbctx, &gis->mdctx, - APK_MPART_BOUNDARY); + if (gis->cb(gis->cbctx, &gis->mdctx, + APK_MPART_BOUNDARY)) { + gis->z_err = Z_STREAM_END; + break; + } } inflateEnd(&gis->zs); - if (inflateInit2(&gis->zs, 15+32) != Z_OK) return -1; gis->z_err = Z_OK; @@ -95,7 +97,7 @@ static size_t gz_read(void *stream, void *ptr, size_t size) return size - gis->zs.avail_out; } -static void gz_close(void *stream) +static void gzi_close(void *stream) { struct apk_gzip_istream *gis = container_of(stream, struct apk_gzip_istream, is); @@ -117,11 +119,11 @@ struct apk_istream *apk_bstream_gunzip_mpart(struct apk_bstream *bs, gis = malloc(sizeof(struct apk_gzip_istream)); if (gis == NULL) - return NULL; + goto err; *gis = (struct apk_gzip_istream) { - .is.read = gz_read, - .is.close = gz_close, + .is.read = gzi_read, + .is.close = gzi_close, .bs = bs, .z_err = 0, .cb = cb, @@ -130,7 +132,7 @@ struct apk_istream *apk_bstream_gunzip_mpart(struct apk_bstream *bs, if (inflateInit2(&gis->zs, 15+32) != Z_OK) { free(gis); - return NULL; + goto err; } if (gis->cb != NULL) { @@ -139,5 +141,83 @@ struct apk_istream *apk_bstream_gunzip_mpart(struct apk_bstream *bs, } return &gis->is; +err: + bs->close(bs, NULL); + return NULL; +} + +struct apk_gzip_ostream { + struct apk_ostream os; + struct apk_ostream *output; + z_stream zs; + unsigned char buffer[8*1024]; +}; + +static size_t gzo_write(void *stream, const void *ptr, size_t size) +{ + struct apk_gzip_ostream *gos = (struct apk_gzip_ostream *) stream; + size_t have; + int r; + + gos->zs.avail_in = size; + gos->zs.next_in = (void *) ptr; + while (gos->zs.avail_in) { + gos->zs.avail_out = sizeof(gos->buffer); + gos->zs.next_out = gos->buffer; + r = deflate(&gos->zs, Z_NO_FLUSH); + if (r == Z_STREAM_ERROR) + return -1; + have = sizeof(gos->buffer) - gos->zs.avail_out; + if (have != 0) { + r = gos->output->write(gos->output, gos->buffer, have); + if (r != have) + return -1; + } + } + + return size; +} + +static void gzo_close(void *stream) +{ + struct apk_gzip_ostream *gos = (struct apk_gzip_ostream *) stream; + size_t have; + + deflate(&gos->zs, Z_FINISH); + have = sizeof(gos->buffer) - gos->zs.avail_out; + gos->output->write(gos->output, gos->buffer, have); + gos->output->close(gos->output); + + deflateEnd(&gos->zs); + free(stream); +} + +struct apk_ostream *apk_ostream_gzip(struct apk_ostream *output) +{ + struct apk_gzip_ostream *gos; + + if (output == NULL) + return NULL; + + gos = malloc(sizeof(struct apk_gzip_ostream)); + if (gos == NULL) + goto err; + + *gos = (struct apk_gzip_ostream) { + .os.write = gzo_write, + .os.close = gzo_close, + .output = output, + }; + + if (deflateInit2(&gos->zs, 9, Z_DEFLATED, 15 | 16, 8, + Z_DEFAULT_STRATEGY) != Z_OK) { + free(gos); + goto err; + } + + return &gos->os; +err: + output->close(output); + return NULL; } |