/* shared functions */
void Z_INTERNAL gz_error(gz_state *, int, const char *);
+int Z_INTERNAL gz_buffer_alloc(gz_state *state);
+void Z_INTERNAL gz_buffer_free(gz_state *state);
+void Z_INTERNAL gz_state_free(gz_state *state);
+
#ifdef ZLIB_COMPAT
unsigned Z_INTERNAL gz_intmax(void);
#endif
#endif
/* Local functions */
+static gzFile gz_state_init();
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() {
+ /* 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 */
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 in_mult = 1, out_mult = 1;
+ int skip_outbuff = (state->mode == GZ_WRITE && state->direct);
+
+ if (state->mode == GZ_WRITE)
+ in_mult = 2; // double imput buffer for compression (ref: gzprintf)
+ else if (state->mode == GZ_READ)
+ out_mult = 2; // double output buffer for decompression
+
+ state->in = (unsigned char *)zng_alloc(state->want * in_mult);
+ /* Don't need output buffer if compressing with state->direct set */
+ if ( !skip_outbuff ) {
+ state->out = (unsigned char *)zng_alloc(state->want * out_mult);
+ }
+
+ /* Return error if memory allocation failed */
+ if (state->in == NULL || (!skip_outbuff && state->out == NULL) ) {
+ gz_buffer_free(state);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+
+ state->size = state->want; // mark state as initialized
+
+ return 0;
+}
+
+void Z_INTERNAL gz_buffer_free(gz_state *state) {
+ zng_free(state->out);
+ zng_free(state->in);
+ 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;
if (path == NULL)
return NULL;
- /* allocate gzFile structure to return */
- state = (gz_state *)zng_alloc(sizeof(gz_state));
+ /* Initialize gzFile state */
+ state = (gz_state *)gz_state_init();
if (state == NULL)
return NULL;
- state->size = 0; /* no buffers allocated yet */
- state->want = GZBUFSIZE; /* requested buffer size */
- state->msg = NULL; /* no error message yet */
/* interpret mode */
- state->mode = GZ_NONE;
- state->level = Z_DEFAULT_COMPRESSION;
- state->strategy = Z_DEFAULT_STRATEGY;
- state->direct = 0;
while (*mode) {
if (*mode >= '0' && *mode <= '9') {
state->level = *mode - '0';
break;
#endif
case '+': /* can't read and write at the same time */
- zng_free(state);
+ gz_state_free(state);
return NULL;
case 'b': /* ignore -- will request binary anyway */
break;
/* must provide an "r", "w", or "a" */
if (state->mode == GZ_NONE) {
- zng_free(state);
+ gz_state_free(state);
return NULL;
}
/* can't force transparent read */
if (state->mode == GZ_READ) {
if (state->direct) {
- zng_free(state);
+ gz_state_free(state);
return NULL;
}
state->direct = 1; /* for empty file */
len = strlen((const char *)path);
state->path = (char *)malloc(len + 1);
if (state->path == NULL) {
- zng_free(state);
+ gz_state_free(state);
return NULL;
}
#ifdef WIDECHAR
open((const char *)path, oflag, 0666));
if (state->fd == -1) {
free(state->path);
- zng_free(state);
+ gz_state_free(state);
return NULL;
}
if (state->mode == GZ_APPEND) {
/* -- see zlib.h -- */
gzFile Z_EXPORT PREFIX(gzdopen)(int fd, const char *mode) {
- char *path; /* identifier for error messages */
gzFile gz;
+ char path[32]; /* identifier for error messages */
- if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
+ if (fd == -1)
return NULL;
- (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */
+ (void)snprintf(path, 32, "<fd:%d>", fd); /* for debugging */
gz = gz_open(path, fd, mode);
- free(path);
return gz;
}
static int gz_look(gz_state *state) {
PREFIX3(stream) *strm = &(state->strm);
- /* allocate read buffers and inflate memory */
if (state->size == 0) {
- /* allocate buffers */
- state->in = (unsigned char *)zng_alloc(state->want);
- state->out = (unsigned char *)zng_alloc(state->want << 1);
- if (state->in == NULL || state->out == NULL) {
- zng_free(state->out);
- zng_free(state->in);
- gz_error(state, Z_MEM_ERROR, "out of memory");
+ /* Allocate gz buffers */
+ if (gz_buffer_alloc(state) != 0) {
return -1;
}
- state->size = state->want;
-
- /* allocate inflate memory */
- state->strm.zalloc = NULL;
- state->strm.zfree = NULL;
- state->strm.opaque = NULL;
- state->strm.avail_in = 0;
- state->strm.next_in = NULL;
+
+ /* Initialize inflate state */
if (PREFIX(inflateInit2)(&(state->strm), MAX_WBITS + 16) != Z_OK) { /* gunzip */
- zng_free(state->out);
- zng_free(state->in);
- state->size = 0;
+ gz_buffer_free(state);
gz_error(state, Z_MEM_ERROR, "out of memory");
return -1;
}
/* free memory and close file */
if (state->size) {
PREFIX(inflateEnd)(&(state->strm));
- zng_free(state->out);
- zng_free(state->in);
+ gz_buffer_free(state);
}
err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
gz_error(state, Z_OK, NULL);
int ret;
PREFIX3(stream) *strm = &(state->strm);
- /* allocate input buffer (double size for gzprintf) */
- state->in = (unsigned char *)zng_alloc(state->want << 1);
- if (state->in == NULL) {
- gz_error(state, Z_MEM_ERROR, "out of memory");
+ /* Allocate gz buffers */
+ if (gz_buffer_alloc(state) != 0)
return -1;
- }
- memset(state->in, 0, state->want << 1);
- /* only need output buffer and deflate state if compressing */
+ /* only need deflate state if compressing */
if (!state->direct) {
- /* allocate output buffer */
- state->out = (unsigned char *)zng_alloc(state->want);
- if (state->out == NULL) {
- zng_free(state->in);
- gz_error(state, Z_MEM_ERROR, "out of memory");
- return -1;
- }
-
/* allocate deflate memory, set up for gzip compression */
- strm->zalloc = NULL;
- strm->zfree = NULL;
- strm->opaque = NULL;
ret = PREFIX(deflateInit2)(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
if (ret != Z_OK) {
- zng_free(state->out);
- zng_free(state->in);
+ gz_buffer_free(state);
gz_error(state, Z_MEM_ERROR, "out of memory");
return -1;
}
strm->next_in = NULL;
- }
- /* mark state as initialized */
- state->size = state->want;
-
- /* initialize write buffer if compressing */
- if (!state->direct) {
+ /* initialize write buffer */
strm->avail_out = state->size;
strm->next_out = state->out;
state->x.next = strm->next_out;
if (state->size) {
if (!state->direct) {
(void)PREFIX(deflateEnd)(&(state->strm));
- zng_free(state->out);
}
- zng_free(state->in);
+ gz_buffer_free(state);
}
gz_error(state, Z_OK, NULL);
free(state->path);
if (close(state->fd) == -1)
ret = Z_ERRNO;
- zng_free(state);
+ gz_state_free(state);
return ret;
}
Z_UNUSED(opaque);
zng_free(ptr);
}
+
+/* Provide aligned allocations, only used by gz* code */
+void Z_INTERNAL *zng_alloc_aligned(unsigned size, unsigned align) {
+ uintptr_t return_ptr, original_ptr;
+ uint32_t alloc_size, align_diff;
+ void *ptr;
+
+ /* Allocate enough memory for proper alignment and to store the original memory pointer */
+ alloc_size = sizeof(void *) + size + align;
+ ptr = zng_alloc(alloc_size);
+ if (!ptr)
+ return NULL;
+
+ /* Calculate return pointer address with space enough to store original pointer */
+ align_diff = align - ((uintptr_t)ptr % align);
+ return_ptr = (uintptr_t)ptr + align_diff;
+ if (align_diff < sizeof(void *))
+ return_ptr += align;
+
+ /* Store the original pointer for free() */
+ original_ptr = return_ptr - sizeof(void *);
+ memcpy((void *)original_ptr, &ptr, sizeof(void *));
+
+ /* Return properly aligned pointer in allocation */
+ return (void *)return_ptr;
+}
+
+void Z_INTERNAL zng_free_aligned(void *ptr) {
+ if (!ptr)
+ return;
+
+ /* Calculate offset to original memory allocation pointer */
+ void *original_ptr = (void *)((uintptr_t)ptr - sizeof(void *));
+ void *free_ptr = *(void **)original_ptr;
+
+ /* Free original memory allocation */
+ zng_free(free_ptr);
+}
void Z_INTERNAL *PREFIX(zcalloc)(void *opaque, unsigned items, unsigned size);
void Z_INTERNAL PREFIX(zcfree)(void *opaque, void *ptr);
+void Z_INTERNAL *zng_alloc_aligned(unsigned size, unsigned align);
+void Z_INTERNAL zng_free_aligned(void *ptr);
typedef void *zng_calloc_func(void *opaque, unsigned items, unsigned size);
typedef void zng_cfree_func(void *opaque, void *ptr);