summaryrefslogtreecommitdiffstats
path: root/src/gunzip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gunzip.c')
-rw-r--r--src/gunzip.c98
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;
}