summaryrefslogtreecommitdiff
path: root/neozip/gzlib.c
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 19:56:09 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 19:56:09 +0300
commit7fb132859fda54aa96bc9dd46d302b343eeb5a02 (patch)
treeb43ae77d7451fb470a260c03349a1caf2846c5e5 /neozip/gzlib.c
parentb1e34e861b5d732afe828d58aad2c638135061fd (diff)
parentc2712b8a345191f6ed79558c089777df94590087 (diff)
downloadProject-Tick-7fb132859fda54aa96bc9dd46d302b343eeb5a02.tar.gz
Project-Tick-7fb132859fda54aa96bc9dd46d302b343eeb5a02.zip
Add 'neozip/' from commit 'c2712b8a345191f6ed79558c089777df94590087'
git-subtree-dir: neozip git-subtree-mainline: b1e34e861b5d732afe828d58aad2c638135061fd git-subtree-split: c2712b8a345191f6ed79558c089777df94590087
Diffstat (limited to 'neozip/gzlib.c')
-rw-r--r--neozip/gzlib.c591
1 files changed, 591 insertions, 0 deletions
diff --git a/neozip/gzlib.c b/neozip/gzlib.c
new file mode 100644
index 0000000000..05f46d9610
--- /dev/null
+++ b/neozip/gzlib.c
@@ -0,0 +1,591 @@
+/* gzlib.c -- zlib functions common to reading and writing gzip files
+ * Copyright (C) 2004-2024 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zbuild.h"
+#include "zutil.h"
+#include "zutil_p.h"
+#include "gzguts.h"
+
+#if defined(_WIN32)
+# define LSEEK _lseeki64
+#else
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+# define LSEEK lseek64
+#else
+# define LSEEK lseek
+#endif
+#endif
+
+/* Local functions */
+static gzFile gz_state_init(void);
+static void gz_reset(gz_state *);
+static gzFile gz_open(const void *, int, const char *);
+
+/* Initialize struct for gzFile state */
+static gzFile gz_state_init(void) {
+ /* allocate gzFile structure to return */
+ gz_state *state = (gz_state *)zng_alloc(sizeof(gz_state));
+ if (state == NULL)
+ return NULL;
+
+ state->strm.zalloc = NULL;
+ state->strm.zfree = NULL;
+ state->strm.opaque = NULL;
+ state->strm.next_in = NULL;
+
+ state->size = 0;
+ state->want = GZBUFSIZE;
+ state->in = NULL;
+ state->out = NULL;
+ state->direct = 0;
+ state->mode = GZ_NONE;
+ state->level = Z_DEFAULT_COMPRESSION;
+ state->strategy = Z_DEFAULT_STRATEGY;
+ state->msg = NULL;
+ return (gzFile)state;
+}
+
+void Z_INTERNAL gz_state_free(gz_state *state) {
+ zng_free(state);
+}
+
+/* Reset gzip file state */
+static void gz_reset(gz_state *state) {
+ state->x.have = 0; /* no output data available */
+ if (state->mode == GZ_READ) { /* for reading ... */
+ state->eof = 0; /* not at end of file */
+ state->past = 0; /* have not read past end yet */
+ state->how = LOOK; /* look for gzip header */
+ }
+ else /* for writing ... */
+ state->reset = 0; /* no deflateReset pending */
+ state->seek = 0; /* no seek request pending */
+ PREFIX(gz_error)(state, Z_OK, NULL); /* clear error */
+ state->x.pos = 0; /* no uncompressed data yet */
+ state->strm.avail_in = 0; /* no input data yet */
+}
+
+/* Allocate in/out buffers for gzFile */
+int Z_INTERNAL gz_buffer_alloc(gz_state *state) {
+ int want = state->want;
+ int in_size = want, out_size = want;
+
+ if (state->mode == GZ_WRITE) {
+ in_size = want * 2; // double input buffer for compression (ref: gzprintf)
+ if (state->direct)
+ out_size = 0; // output buffer not needed in write + direct mode
+ } else if (state->mode == GZ_READ) {
+ out_size = want * 2; // double output buffer for decompression
+ }
+
+ state->buffers = (unsigned char *)zng_alloc_aligned((in_size + out_size), 64);
+ state->in = state->buffers;
+ if (out_size) {
+ state->out = state->buffers + (in_size); // Outbuffer goes after inbuffer
+ }
+
+ /* Return error if memory allocation failed */
+ if (state->in == NULL || (out_size && state->out == NULL)) {
+ gz_buffer_free(state);
+ PREFIX(gz_error)(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+
+ state->size = want; // mark state as initialized
+ return 0;
+}
+
+void Z_INTERNAL gz_buffer_free(gz_state *state) {
+ zng_free_aligned(state->buffers);
+ state->buffers = NULL;
+ state->out = NULL;
+ state->in = NULL;
+ state->size = 0;
+}
+
+/* Open a gzip file either by name or file descriptor. */
+static gzFile gz_open(const void *path, int fd, const char *mode) {
+ gz_state *state;
+ size_t len;
+ int oflag;
+#ifdef O_CLOEXEC
+ int cloexec = 0;
+#endif
+#ifdef O_EXCL
+ int exclusive = 0;
+#endif
+
+ /* check input */
+ if (path == NULL)
+ return NULL;
+
+ /* Initialize gzFile state */
+ state = (gz_state *)gz_state_init();
+ if (state == NULL)
+ return NULL;
+
+ /* interpret mode */
+ while (*mode) {
+ if (*mode >= '0' && *mode <= '9') {
+ state->level = *mode - '0';
+ } else {
+ switch (*mode) {
+ case 'r':
+ state->mode = GZ_READ;
+ break;
+#ifndef NO_GZCOMPRESS
+ case 'w':
+ state->mode = GZ_WRITE;
+ break;
+ case 'a':
+ state->mode = GZ_APPEND;
+ break;
+#endif
+ case '+': /* can't read and write at the same time */
+ gz_state_free(state);
+ return NULL;
+ case 'b': /* ignore -- will request binary anyway */
+ break;
+#ifdef O_CLOEXEC
+ case 'e':
+ cloexec = 1;
+ break;
+#endif
+#ifdef O_EXCL
+ case 'x':
+ exclusive = 1;
+ break;
+#endif
+ case 'f':
+ state->strategy = Z_FILTERED;
+ break;
+ case 'h':
+ state->strategy = Z_HUFFMAN_ONLY;
+ break;
+ case 'R':
+ state->strategy = Z_RLE;
+ break;
+ case 'F':
+ state->strategy = Z_FIXED;
+ break;
+ case 'T':
+ state->direct = 1;
+ break;
+ default: /* could consider as an error, but just ignore */
+ {}
+ }
+ }
+ mode++;
+ }
+
+ /* must provide an "r", "w", or "a" */
+ if (state->mode == GZ_NONE) {
+ gz_state_free(state);
+ return NULL;
+ }
+
+ /* can't force transparent read */
+ if (state->mode == GZ_READ) {
+ if (state->direct) {
+ gz_state_free(state);
+ return NULL;
+ }
+ state->direct = 1; /* for empty file */
+ }
+
+ /* save the path name for error messages */
+#ifdef WIDECHAR
+ if (fd == -2) {
+ len = wcstombs(NULL, (const wchar_t *)path, 0);
+ if (len == (size_t)-1)
+ len = 0;
+ } else
+#endif
+ len = strlen((const char *)path);
+ state->path = malloc(len + 1);
+ if (state->path == NULL) {
+ gz_state_free(state);
+ return NULL;
+ }
+#ifdef WIDECHAR
+ if (fd == -2)
+ if (len) {
+ wcstombs(state->path, (const wchar_t *)path, len + 1);
+ } else {
+ *(state->path) = 0;
+ }
+ else
+#endif
+ (void)snprintf(state->path, len + 1, "%s", (const char *)path);
+
+ /* compute the flags for open() */
+ oflag =
+#ifdef O_LARGEFILE
+ O_LARGEFILE |
+#endif
+#ifdef O_BINARY
+ O_BINARY |
+#endif
+#ifdef O_CLOEXEC
+ (cloexec ? O_CLOEXEC : 0) |
+#endif
+ (state->mode == GZ_READ ?
+ O_RDONLY :
+ (O_WRONLY | O_CREAT |
+#ifdef O_EXCL
+ (exclusive ? O_EXCL : 0) |
+#endif
+ (state->mode == GZ_WRITE ?
+ O_TRUNC :
+ O_APPEND)));
+
+ /* open the file with the appropriate flags (or just use fd) */
+ state->fd = fd > -1 ? fd : (
+#if defined(_WIN32)
+ fd == -2 ? _wopen((const wchar_t *)path, oflag, 0666) :
+#elif __CYGWIN__
+ fd == -2 ? open(state->path, oflag, 0666) :
+#endif
+ open((const char *)path, oflag, 0666));
+ if (state->fd == -1) {
+ free(state->path);
+ gz_state_free(state);
+ return NULL;
+ }
+ if (state->mode == GZ_APPEND) {
+ LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */
+ state->mode = GZ_WRITE; /* simplify later checks */
+ }
+
+ /* save the current position for rewinding (only if reading) */
+ if (state->mode == GZ_READ) {
+ state->start = LSEEK(state->fd, 0, SEEK_CUR);
+ if (state->start == -1) state->start = 0;
+ }
+
+ /* initialize stream */
+ gz_reset(state);
+
+ /* return stream */
+ return (gzFile)state;
+}
+
+/* -- see zlib.h -- */
+gzFile Z_EXPORT PREFIX(gzopen)(const char *path, const char *mode) {
+ return gz_open(path, -1, mode);
+}
+
+#ifdef ZLIB_COMPAT
+gzFile Z_EXPORT PREFIX4(gzopen)(const char *path, const char *mode) {
+ return gz_open(path, -1, mode);
+}
+#endif
+
+/* -- see zlib.h -- */
+gzFile Z_EXPORT PREFIX(gzdopen)(int fd, const char *mode) {
+ gzFile gz;
+ char path[32]; /* identifier for error messages */
+
+ if (fd == -1)
+ return NULL;
+ (void)snprintf(path, 32, "<fd:%d>", fd); /* for debugging */
+ gz = gz_open(path, fd, mode);
+ return gz;
+}
+
+/* -- see zlib.h -- */
+#ifdef WIDECHAR
+gzFile Z_EXPORT PREFIX(gzopen_w)(const wchar_t *path, const char *mode) {
+ return gz_open(path, -2, mode);
+}
+#endif
+
+z_int32_t Z_EXPORT PREFIX(gzclose)(gzFile file) {
+#ifndef NO_GZCOMPRESS
+ gz_state *state;
+
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_state *)file;
+
+ return state->mode == GZ_READ ? PREFIX(gzclose_r)(file) : PREFIX(gzclose_w)(file);
+#else
+ return PREFIX(gzclose_r)(file);
+#endif
+}
+
+/* -- see zlib.h -- */
+z_int32_t Z_EXPORT PREFIX(gzbuffer)(gzFile file, z_uint32_t size) {
+ gz_state *state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_state *)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* make sure we haven't already allocated memory */
+ if (state->size != 0)
+ return -1;
+
+ /* check and set requested size */
+ if ((size << 1) < size)
+ return -1; /* need to be able to double it */
+ if (size < 8)
+ size = 8; /* needed to behave well with flushing */
+ state->want = size;
+ return 0;
+}
+
+/* -- see zlib.h -- */
+z_int32_t Z_EXPORT PREFIX(gzrewind)(gzFile file) {
+ gz_state *state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_state *)file;
+
+ /* check that we're reading and that there's no error */
+ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return -1;
+
+ /* back up and start over */
+ if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
+ return -1;
+ gz_reset(state);
+ return 0;
+}
+
+/* -- see zlib.h -- */
+z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) {
+ unsigned n;
+ z_off64_t ret;
+ gz_state *state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_state *)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* check that there's no error */
+ if (state->err != Z_OK && state->err != Z_BUF_ERROR)
+ return -1;
+
+ /* can only seek from start or relative to current position */
+ if (whence != SEEK_SET && whence != SEEK_CUR)
+ return -1;
+
+ /* normalize offset to a SEEK_CUR specification */
+ if (whence == SEEK_SET)
+ offset -= state->x.pos;
+ else if (state->seek)
+ offset += state->skip;
+ state->seek = 0;
+
+ /* if within raw area while reading, just go there */
+ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) {
+ ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
+ if (ret == -1)
+ return -1;
+ state->x.have = 0;
+ state->eof = 0;
+ state->past = 0;
+ state->seek = 0;
+ PREFIX(gz_error)(state, Z_OK, NULL);
+ state->strm.avail_in = 0;
+ state->x.pos += offset;
+ return state->x.pos;
+ }
+
+ /* calculate skip amount, rewinding if needed for back seek when reading */
+ if (offset < 0) {
+ if (state->mode != GZ_READ) /* writing -- can't go backwards */
+ return -1;
+ offset += state->x.pos;
+ if (offset < 0) /* before start of file! */
+ return -1;
+ if (PREFIX(gzrewind)(file) == -1) /* rewind, then skip to offset */
+ return -1;
+ }
+
+ /* if reading, skip what's in output buffer (one less gzgetc() check) */
+ if (state->mode == GZ_READ) {
+ n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have;
+ state->x.have -= n;
+ state->x.next += n;
+ state->x.pos += n;
+ offset -= n;
+ }
+
+ /* request skip (if not zero) */
+ if (offset) {
+ state->seek = 1;
+ state->skip = offset;
+ }
+ return state->x.pos + offset;
+}
+
+/* -- see zlib.h -- */
+#ifdef ZLIB_COMPAT
+z_off_t Z_EXPORT PREFIX(gzseek)(gzFile file, z_off_t offset, int whence) {
+ z_off64_t ret;
+
+ ret = PREFIX4(gzseek)(file, (z_off64_t)offset, whence);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+#endif
+
+/* -- see zlib.h -- */
+z_off64_t Z_EXPORT PREFIX4(gztell)(gzFile file) {
+ gz_state *state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_state *)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* return position */
+ return state->x.pos + (state->seek ? state->skip : 0);
+}
+
+/* -- see zlib.h -- */
+#ifdef ZLIB_COMPAT
+z_off_t Z_EXPORT PREFIX(gztell)(gzFile file) {
+
+ z_off64_t ret;
+
+ ret = PREFIX4(gztell)(file);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+#endif
+
+/* -- see zlib.h -- */
+z_off64_t Z_EXPORT PREFIX4(gzoffset)(gzFile file) {
+ z_off64_t offset;
+ gz_state *state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_state *)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* compute and return effective offset in file */
+ offset = LSEEK(state->fd, 0, SEEK_CUR);
+ if (offset == -1)
+ return -1;
+ if (state->mode == GZ_READ) /* reading */
+ offset -= state->strm.avail_in; /* don't count buffered input */
+ return offset;
+}
+
+/* -- see zlib.h -- */
+#ifdef ZLIB_COMPAT
+z_off_t Z_EXPORT PREFIX(gzoffset)(gzFile file) {
+ z_off64_t ret;
+
+ ret = PREFIX4(gzoffset)(file);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+#endif
+
+/* -- see zlib.h -- */
+z_int32_t Z_EXPORT PREFIX(gzeof)(gzFile file) {
+ gz_state *state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return 0;
+ state = (gz_state *)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return 0;
+
+ /* return end-of-file state */
+ return state->mode == GZ_READ ? state->past : 0;
+}
+
+/* -- see zlib.h -- */
+const char * Z_EXPORT PREFIX(gzerror)(gzFile file, z_int32_t *errnum) {
+ gz_state *state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return NULL;
+ state = (gz_state *)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return NULL;
+
+ /* return error information */
+ if (errnum != NULL)
+ *errnum = state->err;
+ return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg);
+}
+
+/* -- see zlib.h -- */
+void Z_EXPORT PREFIX(gzclearerr)(gzFile file) {
+ gz_state *state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return;
+ state = (gz_state *)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return;
+
+ /* clear error and end-of-file */
+ if (state->mode == GZ_READ) {
+ state->eof = 0;
+ state->past = 0;
+ }
+ PREFIX(gz_error)(state, Z_OK, NULL);
+}
+
+/* Create an error message in allocated memory and set state->err and
+ state->msg accordingly. Free any previous error message already there. Do
+ not try to free or allocate space if the error is Z_MEM_ERROR (out of
+ memory). Simply save the error message as a static string. If there is an
+ allocation failure constructing the error message, then convert the error to
+ out of memory. */
+void Z_INTERNAL PREFIX(gz_error)(gz_state *state, int err, const char *msg) {
+ /* free previously allocated message and clear */
+ if (state->msg != NULL) {
+ if (state->err != Z_MEM_ERROR)
+ free(state->msg);
+ state->msg = NULL;
+ }
+
+ /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
+ if (err != Z_OK && err != Z_BUF_ERROR)
+ state->x.have = 0;
+
+ /* set error code, and if no message, then done */
+ state->err = err;
+ if (msg == NULL)
+ return;
+
+ /* for an out of memory error, return literal string when requested */
+ if (err == Z_MEM_ERROR)
+ return;
+
+ /* construct error message with path */
+ if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
+ state->err = Z_MEM_ERROR;
+ return;
+ }
+ (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg);
+}
+
+#ifdef ZLIB_COMPAT
+unsigned Z_INTERNAL gz_intmax(void) {
+ return INT_MAX;
+}
+#endif