/* * 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" #define OPKG_OPK_GZIP_BUFFER_SIZE 8192 struct opkg_opk_gzip_state { FILE *input_file; unsigned char input_buffer[OPKG_OPK_GZIP_BUFFER_SIZE]; z_stream stream; }; static int _opkg_opk_gzip_init(struct opkg_opk_gzip_state *state) { state->stream.zalloc = Z_NULL; state->stream.zfree = Z_NULL; state->stream.opaque = Z_NULL; if (inflateInit(&state->stream) != Z_OK) { return OPKG_OPK_ERROR; } return OPKG_OPK_OK; } int opkg_opk_gzip_init_from_file(struct opkg_opk_gzip_state *state, const char *file_name) { state->input_file = fopen(file_name, "rb"); if (state->input_file == NULL) { return OPKG_OPK_ERROR; } state->stream.next_in = Z_NULL; state->stream.avail_in = 0; if (_opkg_opk_gzip_init(state) < OPKG_OPK_OK) { fclose(state->input_file); return OPKG_OPK_ERROR; } return OPKG_OPK_OK; } int opkg_opk_gzip_init_from_memory(struct opkg_opk_gzip_state *state, unsigned char *input, size_t input_size) { state->input_file = NULL; state->stream.next_in = input; state->stream.avail_in = input_size; return _opkg_opk_gzip_init(state); } static int _opkg_opk_gzip_next_record_from_file(struct opkg_opk_gzip_state *state) { for (;;) { if (feof(state->input_file)) { fclose(state->input_file); state->input_file = NULL; inflateEnd(&state->stream); return OPKG_OPK_OK; } if (state->stream.avail_in == 0) { state->stream.avail_in = fread(state->input_buffer, 1, OPKG_OPK_GZIP_BUFFER_SIZE, state->input_file); if (ferror(state->input_file)) { fclose(state->input_file); state->input_file = NULL; inflateEnd(&state->stream); return OPKG_OPK_ERROR; } state->stream.next_in = state->input_buffer; } if (state->stream.avail_out == 0) { return OPKG_OPK_OK; } switch (inflate(&state->stream, Z_SYNC_FLUSH)) { case Z_OK: case Z_STREAM_END: case Z_BUF_ERROR: break; default: fclose(state->input_file); state->input_file = NULL; inflateEnd(&state->stream); return OPKG_OPK_ERROR; } } } static int _opkg_opk_gzip_next_record_from_memory(struct opkg_opk_gzip_state *state) { switch (inflate(&state->stream, Z_SYNC_FLUSH)) { case Z_OK: return OPKG_OPK_OK; case Z_STREAM_END: return OPKG_OPK_END; default: inflateEnd(&state->stream); return OPKG_OPK_ERROR; } } int opkg_opk_gzip_next_record(struct opkg_opk_gzip_state *state, void *record) { state->stream.next_out = record; state->stream.avail_out = 512; if (state->input_file != NULL) { return _opkg_opk_gzip_next_record_from_file(state); } else { return _opkg_opk_gzip_next_record_from_memory(state); } }