/* * Copyright (C) 2023 Patrick McDermott * * This file is part of opkg-opkg. * * opkg-opkg 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. * * opkg-opkg 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 opkg-opkg. If not, see . */ #include #include #include "defs.h" #include "gzip.h" #include "ustar.h" #define OPKG_OPK_GZIP_WINDOW_BITS_ (15 + 16) struct opkg_opk_gzip { int (*read)(void *, char **, size_t *); void *user_data; z_stream stream; }; struct opkg_opk_gzip * opkg_opk_gzip_init(opkg_opk_gzip_read_func *read, void *user_data) { struct opkg_opk_gzip *gzip; gzip = malloc(sizeof(*gzip)); if (gzip == NULL) { return NULL; } gzip->read = read; gzip->user_data = user_data; gzip->stream.next_in = Z_NULL; gzip->stream.avail_in = 0; gzip->stream.zalloc = Z_NULL; gzip->stream.zfree = Z_NULL; gzip->stream.opaque = Z_NULL; if (inflateInit2(&gzip->stream, OPKG_OPK_GZIP_WINDOW_BITS_) != Z_OK) { free(gzip); return NULL; } return gzip; } int opkg_opk_gzip_read(struct opkg_opk_gzip *gzip, void *record) { int end; gzip->stream.next_out = record; gzip->stream.avail_out = OPKG_OPK_USTAR_RECORD_SIZE; for (;;) { end = 0; if (gzip->stream.avail_in == 0) { /* Input buffer is empty and needs refilled. */ switch (gzip->read(gzip->user_data, &gzip->stream.next_in, &gzip->stream.avail_in)) { case OPKG_OPK_OK: break; case OPKG_OPK_END: end = 1; break; case OPKG_OPK_ERROR: default: return OPKG_OPK_ERROR; } } switch (inflate(&gzip->stream, Z_SYNC_FLUSH)) { case Z_OK: break; case Z_BUF_ERROR: if (end == 1) { return OPKG_OPK_ERROR; } break; case Z_STREAM_END: if (gzip->stream.avail_out != 0) { /* Premature end */ return OPKG_OPK_ERROR; } return OPKG_OPK_END; default: return OPKG_OPK_ERROR; } if (gzip->stream.avail_out == 0) { /* Output buffer is filled and ready for use. */ return OPKG_OPK_OK; } } } void opkg_opk_gzip_free(struct opkg_opk_gzip *gzip) { inflateEnd(&gzip->stream); free(gzip); }