From 026161027dda2add2a5082d3de230069501b5b82 Mon Sep 17 00:00:00 2001 From: Patrick McDermott Date: Wed, 12 Apr 2023 22:55:14 -0400 Subject: gzip: Implement --- (limited to 'src/gzip.c') diff --git a/src/gzip.c b/src/gzip.c new file mode 100644 index 0000000..328f33a --- /dev/null +++ b/src/gzip.c @@ -0,0 +1,134 @@ +/* + * 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 "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_GZIP_ERROR; + } + return OPKG_OPK_GZIP_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_GZIP_ERROR; + } + state->stream.next_in = Z_NULL; + state->stream.avail_in = 0; + if (_opkg_opk_gzip_init(state) < OPKG_OPK_GZIP_OK) { + fclose(state->input_file); + return OPKG_OPK_GZIP_ERROR; + } + return OPKG_OPK_GZIP_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_GZIP_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_GZIP_ERROR; + } + state->stream.next_in = state->input_buffer; + } + if (state->stream.avail_out == 0) { + return OPKG_OPK_GZIP_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_GZIP_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_GZIP_OK; + case Z_STREAM_END: + return OPKG_OPK_GZIP_END; + default: + inflateEnd(&state->stream); + return OPKG_OPK_GZIP_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); + } +} -- cgit v0.9.1