diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gzip.c | 134 | ||||
-rw-r--r-- | src/gzip.h | 40 | ||||
-rw-r--r-- | src/local.mk | 2 |
3 files changed, 176 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <zlib.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_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); + } +} diff --git a/src/gzip.h b/src/gzip.h new file mode 100644 index 0000000..5a3b2c7 --- /dev/null +++ b/src/gzip.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 Patrick McDermott + * + * This file is part of opkg-opk. + * + * opkg-opk 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-opk 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-opk. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef OPKG_OPK_GZIP_H_ +#define OPKG_OPK_GZIP_H_ + +struct opkg_opk_gzip_state; + +#define OPKG_OPK_GZIP_OK 0 +#define OPKG_OPK_GZIP_END 1 +#define OPKG_OPK_GZIP_ERROR -1 + +int +opkg_opk_gzip_init_from_file(struct opkg_opk_gzip_state *state, + const char *file_name); + +int +opkg_opk_gzip_init_from_memory(struct opkg_opk_gzip_state *state, + unsigned char *input, size_t input_size); + +int +opkg_opk_gzip_next_record(struct opkg_opk_gzip_state *state, void *record); + +#endif /* OPKG_OPK_GZIP_H_ */ diff --git a/src/local.mk b/src/local.mk index cda7604..18c6181 100644 --- a/src/local.mk +++ b/src/local.mk @@ -1,2 +1,4 @@ opkg_opk_SOURCES += \ + %reldir%/gzip.c \ + %reldir%/gzip.h \ %reldir%/main.c |