
- added invoke-library syntax.ss, primdata.ss, 8.ms, root-experr*, libraries.stex, release_notes.stex - updated the date release_notes.stex - libraries contained within a whole program or library are now marked pending before their invoke code is run so that invoke cycles are reported as such rather than as attempts to invoke while still loading. compile.ss, syntax.ss, primdata.ss, 7.ms, root-experr* - the library manager now protects against unbound references from separately compiled libraries or programs to identifiers ostensibly but not actually exported by (invisible) libraries that exist only locally within a whole program. this is done by marking the invisibility of the library in the library-info and propagating it to libdesc records; the latter is checked upon library import, visit, and invoke as well as by verify-loadability. the import and visit code of each invisible no longer complains about invisibility since it shouldn't be reachable. syntax.ss, compile.ss, expand-lang.ss, 7.ms, 8.ms, root-experr*, patch* - documented that compile-whole-xxx's linearization of the library initialization code based on static dependencies might not work for dynamic dependencies. system.stex - optimized bignum right shifts so the code (1) doesn't look at shifted-off bigits if the bignum is positive, since it doesn't need to know in that case if any bits are set; (2) doesn't look at shifted-off bigits if the bignum is negative if it determines that at least one bit is set in the bits shifted off the low-order partially retained bigit; (3) quits looking, if it must look, for one bits as soon as it finds one; (4) looks from both ends under the assumption that set bits, if any, are most likely to be found toward the high or low end of the bignum rather than just in the middle; and (5) doesn't copy the retained bigits and then shift; rather shifts as it copies. This leads to dramatic improvements when the shift count is large and often significant improvements otherwise. number.c, 5_3.ms, release_notes.stex - threaded tc argument through to all calls to S_bignum and S_trunc_rem so they don't have to call get_thread_context() when it might already have been called. alloc.c, number.c, fasl.c, print.c, prim5.c, externs.h - added an expand-primitive handler to partially inline integer?. cpnanopass.ss - added some special cases for basic arithmetic operations (+, -, *, /, quotient, remainder, and the div/div0/mod/mod0 operations) to avoid doing unnecessary work for large bignums when the result will be zero (e.g,. multiplying by 0), the same as one of the inputs (e.g., adding 0 or multiplying by 1), or the additive inverse of one of the inputs (e.g., subtracting from 0, dividing by -1). This can have a major beneficial affect when operating on large bignums in the cases handled. also converted some uses of / into integer/ where going through the former would just add overhead without the possibility of optimization. 5_3.ss, number.c, externs.h, prim5.c, 5_3.ms, root-experr, patch*, release_notes.stex - added a queue to hold pending signals for which handlers have been registered via register-signal-handler so up to 63 (configurable in the source code) unhandled signals are buffered before the handler has to start dropping them. cmacros.ss, library.ss, prims.ss, primdata.ss, schsig.c, externs.h, prim5.c, thread.c, gc.c, unix.ms, system.stex, release_notes.stex - bytevector-compress now selects the level of compression based on the compress-level parameter. Prior to this it always used a default setting for compression. the compress-level parameter can now take on the new minimum in addition to low, medium, high, and maximum. minimum is presently treated the same as low except in the case of lz4 bytevector compression, where it results in the use of LZ4_compress_default rather than the slower but more effective LZ4_compress_HC. cmacros,ss, back.ss, compress_io.c, new_io.c, externs.h, bytevector.ms, mats/Mf-base, root-experr* io.stex, objects.stex, release_notes.stex original commit: 72d90e4c67849908da900d0b6249a1dedb5f8c7f
673 lines
18 KiB
C
673 lines
18 KiB
C
/* compress-io.c
|
|
* Copyright 1984-2019 Cisco Systems, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/* Dispatch to zlib or LZ4 */
|
|
|
|
#include "system.h"
|
|
#include "zlib.h"
|
|
#include "lz4.h"
|
|
#include "lz4frame.h"
|
|
#include "lz4hc.h"
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
#ifdef WIN32
|
|
#include <io.h>
|
|
# define WIN32_IZE(id) _ ## id
|
|
# define GLZ_O_BINARY O_BINARY
|
|
#else
|
|
# define WIN32_IZE(id) id
|
|
# define GLZ_O_BINARY 0
|
|
#endif
|
|
|
|
/* the value of LZ4_OUTPUT_PORT_IN_BUFFER_SIZE was determined
|
|
through experimentation on an intel linux server and an intel
|
|
osx laptop. smaller sizes result in significantly worse compression
|
|
of object files, and larger sizes don't have much beneficial effect.
|
|
don't increase the output-port in-buffer size unless you're sure
|
|
it reduces object-file size or reduces compression time
|
|
significantly. don't decrease it unless you're sure it doesn't
|
|
increase object-file size significnatly. one buffer of size
|
|
LZ4_OUTPUT_PORT_IN_BUFFER_SIZE is allocated per lz4-compressed
|
|
output port. another buffer of a closely related size is allocated
|
|
per thread. */
|
|
#define LZ4_OUTPUT_PORT_IN_BUFFER_SIZE (1 << 18)
|
|
|
|
/* the values we choose for LZ4_INPUT_PORT_IN_BUFFER_SIZE and
|
|
LZ4_INPUT_PORT_OUT_BUFFER_SIZE don't seem to make much difference
|
|
in decompression speed, so we keep them fairly small. one buffer
|
|
of size LZ4_INPUT_PORT_IN_BUFFER_SIZE and one buffer of size
|
|
LZ4_INPUT_PORT_OUT_BUFFER_SIZE are allocated per lz4-compressed
|
|
input port. */
|
|
#define LZ4_INPUT_PORT_IN_BUFFER_SIZE (1 << 12)
|
|
#define LZ4_INPUT_PORT_OUT_BUFFER_SIZE (1 << 14)
|
|
|
|
typedef struct lz4File_out_r {
|
|
LZ4F_preferences_t preferences;
|
|
INT fd;
|
|
INT out_buffer_size;
|
|
INT in_pos;
|
|
INT err;
|
|
size_t stream_pos;
|
|
char in_buffer[LZ4_OUTPUT_PORT_IN_BUFFER_SIZE];
|
|
} lz4File_out;
|
|
|
|
typedef struct lz4File_in_r {
|
|
INT fd;
|
|
LZ4F_dctx *dctx;
|
|
INT in_pos, in_len, out_pos, out_len;
|
|
INT frame_ended;
|
|
INT err;
|
|
size_t stream_pos;
|
|
off_t init_pos;
|
|
char in_buffer[LZ4_INPUT_PORT_IN_BUFFER_SIZE];
|
|
char out_buffer[LZ4_INPUT_PORT_OUT_BUFFER_SIZE];
|
|
} lz4File_in;
|
|
|
|
typedef struct sized_buffer_r {
|
|
INT size;
|
|
char buffer[0];
|
|
} sized_buffer;
|
|
|
|
/* local functions */
|
|
static glzFile glzdopen_output_gz(INT fd, INT compress_level);
|
|
static glzFile glzdopen_output_lz4(INT fd, INT compress_level);
|
|
static glzFile glzdopen_input_gz(INT fd);
|
|
static glzFile glzdopen_input_lz4(INT fd, off_t init_pos);
|
|
static INT glzread_lz4(lz4File_in *lz4, void *buffer, UINT count);
|
|
static INT glzemit_lz4(lz4File_out *lz4, void *buffer, UINT count);
|
|
static INT glzwrite_lz4(lz4File_out *lz4, void *buffer, UINT count);
|
|
|
|
INT S_zlib_compress_level(INT compress_level) {
|
|
switch (compress_level) {
|
|
case COMPRESS_MIN:
|
|
case COMPRESS_LOW:
|
|
return Z_BEST_SPEED;
|
|
case COMPRESS_MEDIUM:
|
|
return (Z_BEST_SPEED + Z_BEST_COMPRESSION) / 2;
|
|
case COMPRESS_HIGH:
|
|
return (Z_BEST_SPEED + (3 * Z_BEST_COMPRESSION)) / 4;
|
|
case COMPRESS_MAX:
|
|
return Z_BEST_COMPRESSION;
|
|
default:
|
|
S_error1("S_zlib_compress_level", "unexpected compress level ~s", Sinteger(compress_level));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static glzFile glzdopen_output_gz(INT fd, INT compress_level) {
|
|
gzFile gz;
|
|
glzFile glz;
|
|
INT as_append;
|
|
INT level;
|
|
|
|
#ifdef WIN32
|
|
as_append = 0;
|
|
#else
|
|
as_append = fcntl(fd, F_GETFL) & O_APPEND;
|
|
#endif
|
|
|
|
if ((gz = gzdopen(fd, as_append ? "ab" : "wb")) == Z_NULL) return Z_NULL;
|
|
|
|
level = S_zlib_compress_level(compress_level);
|
|
|
|
gzsetparams(gz, level, Z_DEFAULT_STRATEGY);
|
|
|
|
if ((glz = malloc(sizeof(struct glzFile_r))) == NULL) {
|
|
(void)gzclose(gz);
|
|
return Z_NULL;
|
|
}
|
|
glz->fd = fd;
|
|
glz->inputp = 0;
|
|
glz->format = COMPRESS_GZIP;
|
|
glz->gz = gz;
|
|
return glz;
|
|
}
|
|
|
|
INT S_lz4_compress_level(INT compress_level) {
|
|
switch (compress_level) {
|
|
case COMPRESS_MIN:
|
|
case COMPRESS_LOW:
|
|
return 1;
|
|
case COMPRESS_MEDIUM:
|
|
return LZ4HC_CLEVEL_MIN;
|
|
case COMPRESS_HIGH:
|
|
return (LZ4HC_CLEVEL_MIN + LZ4HC_CLEVEL_MAX) / 2;
|
|
case COMPRESS_MAX:
|
|
return LZ4HC_CLEVEL_MAX;
|
|
default:
|
|
S_error1("S_lz4_compress_level", "unexpected compress level ~s", Sinteger(compress_level));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static glzFile glzdopen_output_lz4(INT fd, INT compress_level) {
|
|
glzFile glz;
|
|
lz4File_out *lz4;
|
|
INT level;
|
|
|
|
level = S_lz4_compress_level(compress_level);
|
|
|
|
if ((lz4 = malloc(sizeof(lz4File_out))) == NULL) return Z_NULL;
|
|
memset(&lz4->preferences, 0, sizeof(LZ4F_preferences_t));
|
|
lz4->preferences.compressionLevel = level;
|
|
lz4->fd = fd;
|
|
lz4->out_buffer_size = (INT)LZ4F_compressFrameBound(LZ4_OUTPUT_PORT_IN_BUFFER_SIZE, &lz4->preferences);
|
|
lz4->in_pos = 0;
|
|
lz4->err = 0;
|
|
lz4->stream_pos = 0;
|
|
|
|
if ((glz = malloc(sizeof(struct glzFile_r))) == NULL) {
|
|
free(lz4);
|
|
return Z_NULL;
|
|
}
|
|
glz->fd = fd;
|
|
glz->inputp = 0;
|
|
glz->format = COMPRESS_LZ4;
|
|
glz->lz4_out = lz4;
|
|
return glz;
|
|
}
|
|
|
|
glzFile S_glzdopen_output(INT fd, INT compress_format, INT compress_level) {
|
|
switch (compress_format) {
|
|
case COMPRESS_GZIP:
|
|
return glzdopen_output_gz(fd, compress_level);
|
|
case COMPRESS_LZ4:
|
|
return glzdopen_output_lz4(fd, compress_level);
|
|
default:
|
|
S_error1("glzdopen_output", "unexpected compress format ~s", Sinteger(compress_format));
|
|
return Z_NULL;
|
|
}
|
|
}
|
|
|
|
static glzFile glzdopen_input_gz(INT fd) {
|
|
gzFile gz;
|
|
glzFile glz;
|
|
|
|
if ((gz = gzdopen(fd, "rb")) == Z_NULL) return Z_NULL;
|
|
|
|
if ((glz = malloc(sizeof(struct glzFile_r))) == NULL) {
|
|
(void)gzclose(gz);
|
|
return Z_NULL;
|
|
}
|
|
glz->fd = fd;
|
|
glz->inputp = 1;
|
|
glz->format = COMPRESS_GZIP;
|
|
glz->gz = gz;
|
|
return glz;
|
|
}
|
|
|
|
static glzFile glzdopen_input_lz4(INT fd, off_t init_pos) {
|
|
glzFile glz;
|
|
LZ4F_dctx *dctx;
|
|
LZ4F_errorCode_t r;
|
|
lz4File_in *lz4;
|
|
|
|
r = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
|
|
if (LZ4F_isError(r))
|
|
return Z_NULL;
|
|
|
|
if ((lz4 = malloc(sizeof(lz4File_in))) == NULL) {
|
|
(void)LZ4F_freeDecompressionContext(dctx);
|
|
return Z_NULL;
|
|
}
|
|
lz4->fd = fd;
|
|
lz4->dctx = dctx;
|
|
lz4->in_pos = 0;
|
|
lz4->in_len = 0;
|
|
lz4->out_len = 0;
|
|
lz4->out_pos = 0;
|
|
lz4->frame_ended = 0;
|
|
lz4->err = 0;
|
|
lz4->stream_pos = 0;
|
|
lz4->init_pos = init_pos;
|
|
|
|
if ((glz = malloc(sizeof(struct glzFile_r))) == NULL) {
|
|
(void)LZ4F_freeDecompressionContext(lz4->dctx);
|
|
free(lz4);
|
|
return Z_NULL;
|
|
}
|
|
glz->fd = fd;
|
|
glz->inputp = 1;
|
|
glz->format = COMPRESS_LZ4;
|
|
glz->lz4_in = lz4;
|
|
return glz;
|
|
}
|
|
|
|
glzFile S_glzdopen_input(INT fd) {
|
|
INT r, pos = 0;
|
|
unsigned char buffer[4];
|
|
off_t init_pos;
|
|
|
|
/* check for LZ4 magic number, otherwise defer to gzdopen */
|
|
|
|
if ((init_pos = WIN32_IZE(lseek)(fd, 0, SEEK_CUR)) == -1) return Z_NULL;
|
|
|
|
while (pos < 4) {
|
|
r = WIN32_IZE(read)(fd, (char*)buffer + pos, 4 - pos);
|
|
if (r == 0)
|
|
break;
|
|
else if (r > 0)
|
|
pos += r;
|
|
#ifdef EINTR
|
|
else if (errno == EINTR)
|
|
continue;
|
|
#endif
|
|
else
|
|
break; /* error reading */
|
|
}
|
|
|
|
if (pos > 0) {
|
|
if (WIN32_IZE(lseek)(fd, init_pos, SEEK_SET) == -1) return Z_NULL;
|
|
}
|
|
|
|
if ((pos == 4)
|
|
&& (buffer[0] == 0x04)
|
|
&& (buffer[1] == 0x22)
|
|
&& (buffer[2] == 0x4d)
|
|
&& (buffer[3] == 0x18))
|
|
return glzdopen_input_lz4(fd, init_pos);
|
|
|
|
return glzdopen_input_gz(fd);
|
|
}
|
|
|
|
glzFile S_glzopen_input(const char *path) {
|
|
INT fd;
|
|
|
|
fd = WIN32_IZE(open)(path, O_RDONLY | GLZ_O_BINARY);
|
|
|
|
if (fd == -1)
|
|
return Z_NULL;
|
|
else
|
|
return S_glzdopen_input(fd);
|
|
}
|
|
|
|
#ifdef WIN32
|
|
glzFile S_glzopen_input_w(const wchar_t *path) {
|
|
INT fd;
|
|
|
|
fd = _wopen(path, O_RDONLY | GLZ_O_BINARY);
|
|
|
|
if (fd == -1)
|
|
return Z_NULL;
|
|
else
|
|
return S_glzdopen_input(fd);
|
|
}
|
|
#endif
|
|
|
|
IBOOL S_glzdirect(glzFile glz) {
|
|
if (glz->format == COMPRESS_GZIP)
|
|
return gzdirect(glz->gz);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
INT S_glzclose(glzFile glz) {
|
|
INT r = Z_OK, saved_errno = 0;
|
|
switch (glz->format) {
|
|
case COMPRESS_GZIP:
|
|
r = gzclose(glz->gz);
|
|
break;
|
|
case COMPRESS_LZ4:
|
|
if (glz->inputp) {
|
|
lz4File_in *lz4 = glz->lz4_in;
|
|
while (1) {
|
|
INT r = WIN32_IZE(close)(lz4->fd);
|
|
#ifdef EINTR
|
|
if (r < 0 && errno == EINTR) continue;
|
|
#endif
|
|
if (r == 0) { saved_errno = errno; }
|
|
break;
|
|
}
|
|
(void)LZ4F_freeDecompressionContext(lz4->dctx);
|
|
free(lz4);
|
|
} else {
|
|
lz4File_out *lz4 = glz->lz4_out;
|
|
if (lz4->in_pos != 0) {
|
|
r = glzemit_lz4(lz4, lz4->in_buffer, lz4->in_pos);
|
|
if (r >= 0) r = Z_OK; else { r = Z_ERRNO; saved_errno = errno; }
|
|
}
|
|
while (1) {
|
|
int r1 = WIN32_IZE(close)(lz4->fd);
|
|
#ifdef EINTR
|
|
if (r1 < 0 && errno == EINTR) continue;
|
|
#endif
|
|
if (r == Z_OK && r1 < 0) { r = Z_ERRNO; saved_errno = errno; }
|
|
break;
|
|
}
|
|
free(lz4);
|
|
}
|
|
break;
|
|
default:
|
|
S_error1("S_glzclose", "unexpected compress format ~s", Sinteger(glz->format));
|
|
}
|
|
free(glz);
|
|
if (saved_errno) errno = saved_errno;
|
|
return r;
|
|
}
|
|
|
|
static INT glzread_lz4(lz4File_in *lz4, void *buffer, UINT count) {
|
|
while (lz4->out_pos == lz4->out_len) {
|
|
INT in_avail;
|
|
|
|
in_avail = lz4->in_len - lz4->in_pos;
|
|
if (!in_avail) {
|
|
while (1) {
|
|
in_avail = WIN32_IZE(read)(lz4->fd, lz4->in_buffer, LZ4_INPUT_PORT_IN_BUFFER_SIZE);
|
|
if (in_avail >= 0) {
|
|
lz4->in_len = in_avail;
|
|
lz4->in_pos = 0;
|
|
break;
|
|
#ifdef EINTR
|
|
} else if (errno == EINTR) {
|
|
/* try again */
|
|
#endif
|
|
} else {
|
|
lz4->err = Z_ERRNO;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (in_avail > 0) {
|
|
size_t amt, out_len = LZ4_INPUT_PORT_OUT_BUFFER_SIZE, in_len = in_avail;
|
|
|
|
/* For a large enough result buffer, try to decompress directly
|
|
to that buffer: */
|
|
if (count >= (out_len >> 1)) {
|
|
size_t direct_out_len = count;
|
|
|
|
if (lz4->frame_ended && lz4->in_buffer[lz4->in_pos] == 0)
|
|
return 0; /* count 0 after frame as stream terminator */
|
|
|
|
amt = LZ4F_decompress(lz4->dctx,
|
|
buffer, &direct_out_len,
|
|
lz4->in_buffer + lz4->in_pos, &in_len,
|
|
NULL);
|
|
lz4->frame_ended = (amt == 0);
|
|
|
|
if (LZ4F_isError(amt)) {
|
|
lz4->err = Z_STREAM_ERROR;
|
|
return -1;
|
|
}
|
|
|
|
lz4->in_pos += (INT)in_len;
|
|
|
|
if (direct_out_len) {
|
|
lz4->stream_pos += direct_out_len;
|
|
return (INT)direct_out_len;
|
|
}
|
|
|
|
in_len = in_avail - in_len;
|
|
}
|
|
|
|
if (in_len > 0) {
|
|
if (lz4->frame_ended && lz4->in_buffer[lz4->in_pos] == 0)
|
|
return 0; /* count 0 after frame as stream terminator */
|
|
|
|
amt = LZ4F_decompress(lz4->dctx,
|
|
lz4->out_buffer, &out_len,
|
|
lz4->in_buffer + lz4->in_pos, &in_len,
|
|
NULL);
|
|
lz4->frame_ended = (amt == 0);
|
|
|
|
if (LZ4F_isError(amt)) {
|
|
lz4->err = Z_STREAM_ERROR;
|
|
return -1;
|
|
}
|
|
|
|
lz4->in_pos += (INT)in_len;
|
|
lz4->out_len = (INT)out_len;
|
|
lz4->out_pos = 0;
|
|
}
|
|
} else {
|
|
/* EOF on read */
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lz4->out_pos < lz4->out_len) {
|
|
UINT amt = lz4->out_len - lz4->out_pos;
|
|
if (amt > count) amt = count;
|
|
memcpy(buffer, lz4->out_buffer + lz4->out_pos, amt);
|
|
lz4->out_pos += amt;
|
|
lz4->stream_pos += amt;
|
|
return amt;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
INT S_glzread(glzFile glz, void *buffer, UINT count) {
|
|
switch (glz->format) {
|
|
case COMPRESS_GZIP:
|
|
return gzread(glz->gz, buffer, count);
|
|
case COMPRESS_LZ4:
|
|
return glzread_lz4(glz->lz4_in, buffer, count);
|
|
default:
|
|
S_error1("S_glzread", "unexpected compress format ~s", Sinteger(glz->format));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static INT glzemit_lz4(lz4File_out *lz4, void *buffer, UINT count) {
|
|
ptr tc = get_thread_context();
|
|
sized_buffer *cached_out_buffer;
|
|
char *out_buffer;
|
|
INT out_len, out_pos;
|
|
INT r = 0;
|
|
|
|
/* allocate one out_buffer (per thread) since we don't need one for each file.
|
|
the buffer is freed by destroy_thread. */
|
|
if ((cached_out_buffer = LZ4OUTBUFFER(tc)) == NULL || cached_out_buffer->size < lz4->out_buffer_size) {
|
|
if (cached_out_buffer != NULL) free(cached_out_buffer);
|
|
if ((LZ4OUTBUFFER(tc) = cached_out_buffer = malloc(sizeof(sized_buffer) + lz4->out_buffer_size)) == NULL) return -1;
|
|
cached_out_buffer->size = lz4->out_buffer_size;
|
|
}
|
|
out_buffer = cached_out_buffer->buffer;
|
|
|
|
out_len = (INT)LZ4F_compressFrame(out_buffer, lz4->out_buffer_size,
|
|
buffer, count,
|
|
&lz4->preferences);
|
|
if (LZ4F_isError(out_len)) {
|
|
lz4->err = Z_STREAM_ERROR;
|
|
return -1;
|
|
}
|
|
|
|
out_pos = 0;
|
|
while (out_pos < out_len) {
|
|
r = WIN32_IZE(write)(lz4->fd, out_buffer + out_pos, out_len - out_pos);
|
|
if (r >= 0)
|
|
out_pos += r;
|
|
#ifdef EINTR
|
|
else if (errno == EINTR)
|
|
continue;
|
|
#endif
|
|
else
|
|
break;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
static INT glzwrite_lz4(lz4File_out *lz4, void *buffer, UINT count) {
|
|
UINT amt; INT r;
|
|
|
|
if ((amt = LZ4_OUTPUT_PORT_IN_BUFFER_SIZE - lz4->in_pos) > count) amt = count;
|
|
|
|
if (amt == LZ4_OUTPUT_PORT_IN_BUFFER_SIZE) {
|
|
/* full buffer coming from input...skip the memcpy */
|
|
if ((r = glzemit_lz4(lz4, buffer, LZ4_OUTPUT_PORT_IN_BUFFER_SIZE)) < 0) return 0;
|
|
} else {
|
|
memcpy(lz4->in_buffer + lz4->in_pos, buffer, amt);
|
|
if ((lz4->in_pos += amt) == LZ4_OUTPUT_PORT_IN_BUFFER_SIZE) {
|
|
lz4->in_pos = 0;
|
|
if ((r = glzemit_lz4(lz4, lz4->in_buffer, LZ4_OUTPUT_PORT_IN_BUFFER_SIZE)) < 0) return 0;
|
|
}
|
|
}
|
|
|
|
lz4->stream_pos += amt;
|
|
return amt;
|
|
}
|
|
|
|
INT S_glzwrite(glzFile glz, void *buffer, UINT count) {
|
|
switch (glz->format) {
|
|
case COMPRESS_GZIP:
|
|
return gzwrite(glz->gz, buffer, count);
|
|
case COMPRESS_LZ4:
|
|
return glzwrite_lz4(glz->lz4_out, buffer, count);
|
|
default:
|
|
S_error1("S_glzwrite", "unexpected compress format ~s", Sinteger(glz->format));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
long S_glzseek(glzFile glz, long offset, INT whence) {
|
|
switch (glz->format) {
|
|
case COMPRESS_GZIP:
|
|
return gzseek(glz->gz, offset, whence);
|
|
case COMPRESS_LZ4:
|
|
if (glz->inputp) {
|
|
lz4File_in *lz4 = glz->lz4_in;
|
|
if (whence == SEEK_CUR)
|
|
offset += (long)lz4->stream_pos;
|
|
if (offset < 0)
|
|
offset = 0;
|
|
if ((size_t)offset < lz4->stream_pos) {
|
|
/* rewind and read from start */
|
|
if (WIN32_IZE(lseek)(lz4->fd, lz4->init_pos, SEEK_SET) < 0) {
|
|
lz4->err = Z_ERRNO;
|
|
return -1;
|
|
}
|
|
LZ4F_resetDecompressionContext(lz4->dctx);
|
|
lz4->in_pos = 0;
|
|
lz4->in_len = 0;
|
|
lz4->out_len = 0;
|
|
lz4->out_pos = 0;
|
|
lz4->err = 0;
|
|
lz4->stream_pos = 0;
|
|
}
|
|
while ((size_t)offset > lz4->stream_pos) {
|
|
static char buffer[1024];
|
|
size_t amt = (size_t)offset - lz4->stream_pos;
|
|
if (amt > sizeof(buffer)) amt = sizeof(buffer);
|
|
if (glzread_lz4(lz4, buffer, (UINT)amt) < 0)
|
|
return -1;
|
|
}
|
|
return (long)lz4->stream_pos;
|
|
} else {
|
|
lz4File_out *lz4 = glz->lz4_out;
|
|
if (whence == SEEK_CUR)
|
|
offset += (long)lz4->stream_pos;
|
|
if (offset >= 0) {
|
|
while ((size_t)offset > lz4->stream_pos) {
|
|
size_t amt = (size_t)offset - lz4->stream_pos;
|
|
if (amt > 8) amt = 8;
|
|
if (glzwrite_lz4(lz4, "\0\0\0\0\0\0\0\0", (UINT)amt) < 0)
|
|
return -1;
|
|
}
|
|
}
|
|
return (long)lz4->stream_pos;
|
|
}
|
|
default:
|
|
S_error1("S_glzseek", "unexpected compress format ~s", Sinteger(glz->format));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
INT S_glzgetc(glzFile glz) {
|
|
switch (glz->format) {
|
|
case COMPRESS_GZIP:
|
|
return gzgetc(glz->gz);
|
|
case COMPRESS_LZ4:
|
|
{
|
|
unsigned char buffer[1];
|
|
INT r;
|
|
r = S_glzread(glz, buffer, 1);
|
|
if (r == 1)
|
|
return buffer[0];
|
|
else
|
|
return -1;
|
|
}
|
|
default:
|
|
S_error1("S_glzgetc", "unexpected compress format ~s", Sinteger(glz->format));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
INT S_glzungetc(INT c, glzFile glz) {
|
|
switch (glz->format) {
|
|
case COMPRESS_GZIP:
|
|
return gzungetc(c, glz->gz);
|
|
case COMPRESS_LZ4:
|
|
{
|
|
lz4File_in *lz4 = glz->lz4_in;
|
|
if (lz4->out_len == 0)
|
|
lz4->out_len = lz4->out_pos = 1;
|
|
if (lz4->out_pos) {
|
|
lz4->out_pos--;
|
|
lz4->out_buffer[lz4->out_pos] = c;
|
|
lz4->stream_pos--;
|
|
return c;
|
|
} else {
|
|
/* support ungetc only just after a getc, in which case there
|
|
should have been room */
|
|
return -1;
|
|
}
|
|
}
|
|
default:
|
|
S_error1("S_glzungetc", "unexpected compress format ~s", Sinteger(glz->format));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
INT S_glzrewind(glzFile glz) {
|
|
return S_glzseek(glz, 0, SEEK_SET);
|
|
}
|
|
|
|
void S_glzerror(glzFile glz, INT *errnum) {
|
|
switch (glz->format) {
|
|
case COMPRESS_GZIP:
|
|
(void)gzerror(glz->gz, errnum);
|
|
break;
|
|
case COMPRESS_LZ4:
|
|
if (glz->inputp)
|
|
*errnum = glz->lz4_in->err;
|
|
else
|
|
*errnum = glz->lz4_out->err;
|
|
break;
|
|
default:
|
|
S_error1("S_glzerror", "unexpected compress format ~s", Sinteger(glz->format));
|
|
*errnum = 0;
|
|
}
|
|
}
|
|
|
|
void S_glzclearerr(glzFile glz) {
|
|
switch (glz->format) {
|
|
case COMPRESS_GZIP:
|
|
gzclearerr(glz->gz);
|
|
break;
|
|
case COMPRESS_LZ4:
|
|
if (glz->inputp)
|
|
glz->lz4_in->err = 0;
|
|
else
|
|
glz->lz4_out->err = 0;
|
|
break;
|
|
default:
|
|
S_error1("S_glzerror", "unexpected compress format ~s", Sinteger(glz->format));
|
|
}
|
|
}
|