summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gzip.c134
-rw-r--r--src/gzip.h40
-rw-r--r--src/local.mk2
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