diff options
| -rw-r--r-- | deflate.c | 119 | ||||
| -rw-r--r-- | test/example.c | 65 | ||||
| -rw-r--r-- | win32/zlib-ng.def | 2 | ||||
| -rw-r--r-- | zlib-ng.h | 40 | ||||
| -rw-r--r-- | zlib-ng.map | 2 |
5 files changed, 223 insertions, 5 deletions
@@ -1710,3 +1710,122 @@ void send_bits(deflate_state *s, int value, int length) { } } #endif + +#ifndef ZLIB_COMPAT +/* ========================================================================= + * Checks whether buffer size is sufficient and whether this parameter is a duplicate. + */ +static int deflateSetParamPre(zng_deflate_param_value **out, size_t min_size, zng_deflate_param_value *param) { + int buf_error = param->size < min_size; + + if (*out != NULL) { + (*out)->status = Z_BUF_ERROR; + buf_error = 1; + } + *out = param; + return buf_error; +} + +/* ========================================================================= */ +int ZEXPORT zng_deflateSetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count) { + size_t i; + deflate_state *s; + zng_deflate_param_value *new_level = NULL; + zng_deflate_param_value *new_strategy = NULL; + int param_buf_error; + int version_error = 0; + int buf_error = 0; + int stream_error = 0; + int ret; + + /* Initialize the statuses. */ + for (i = 0; i < count; i++) + params[i].status = Z_OK; + + /* Check whether the stream state is consistent. */ + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + + /* Check buffer sizes and detect duplicates. */ + for (i = 0; i < count; i++) { + switch (params[i].param) { + case Z_DEFLATE_LEVEL: + param_buf_error = deflateSetParamPre(&new_level, sizeof(int), ¶ms[i]); + break; + case Z_DEFLATE_STRATEGY: + param_buf_error = deflateSetParamPre(&new_strategy, sizeof(int), ¶ms[i]); + break; + default: + params[i].status = Z_VERSION_ERROR; + version_error = 1; + param_buf_error = 0; + break; + } + if (param_buf_error) { + params[i].status = Z_BUF_ERROR; + buf_error = 1; + } + } + /* Exit early if small buffers or duplicates are detected. */ + if (buf_error) + return Z_BUF_ERROR; + + /* Apply changes, remember if there were errors. */ + if (new_level != NULL || new_strategy != NULL) { + ret = PREFIX(deflateParams)(strm, new_level == NULL ? s->level : *(int *)new_level->buf, + new_strategy == NULL ? s->strategy : *(int *)new_strategy->buf); + if (ret != Z_OK) { + if (new_level != NULL) + new_level->status = Z_STREAM_ERROR; + if (new_strategy != NULL) + new_strategy->status = Z_STREAM_ERROR; + stream_error = 1; + } + } + + /* Report version errors only if there are no real errors. */ + return stream_error ? Z_STREAM_ERROR : (version_error ? Z_VERSION_ERROR : Z_OK); +} + +/* ========================================================================= */ +int ZEXPORT zng_deflateGetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count) { + deflate_state *s; + size_t i; + int buf_error = 0; + int version_error = 0; + + /* Initialize the statuses. */ + for (i = 0; i < count; i++) + params[i].status = Z_OK; + + /* Check whether the stream state is consistent. */ + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + + for (i = 0; i < count; i++) { + switch (params[i].param) { + case Z_DEFLATE_LEVEL: + if (params[i].size < sizeof(int)) + params[i].status = Z_BUF_ERROR; + else + *(int *)params[i].buf = s->level; + break; + case Z_DEFLATE_STRATEGY: + if (params[i].size < sizeof(int)) + params[i].status = Z_BUF_ERROR; + else + *(int *)params[i].buf = s->strategy; + break; + default: + params[i].status = Z_VERSION_ERROR; + version_error = 1; + break; + } + if (params[i].status == Z_BUF_ERROR) + buf_error = 1; + } + return buf_error ? Z_BUF_ERROR : (version_error ? Z_VERSION_ERROR : Z_OK); +} +#endif diff --git a/test/example.c b/test/example.c index 964a380d76..f826b1ab84 100644 --- a/test/example.c +++ b/test/example.c @@ -40,7 +40,7 @@ void test_compress (unsigned char *compr, z_size_t comprLen,unsigned char * void test_gzio (const char *fname, unsigned char *uncompr, z_size_t uncomprLen); void test_deflate (unsigned char *compr, size_t comprLen); void test_inflate (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen); -void test_large_deflate (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen); +void test_large_deflate (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen, int zng_params); void test_large_inflate (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen); void test_flush (unsigned char *compr, z_size_t *comprLen); void test_sync (unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen); @@ -241,10 +241,18 @@ static unsigned int diff; /* =========================================================================== * Test deflate() with large buffers and dynamic change of compression level */ -void test_large_deflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen) +void test_large_deflate(unsigned char *compr, size_t comprLen, unsigned char *uncompr, size_t uncomprLen, int zng_params) { PREFIX3(stream) c_stream; /* compression stream */ int err; +#ifndef ZLIB_COMPAT + int level = -1; + int strategy = -1; + zng_deflate_param_value params[] = { + { .param = Z_DEFLATE_LEVEL, .buf = &level, .size = sizeof(level) }, + { .param = Z_DEFLATE_STRATEGY, .buf = &strategy, .size = sizeof(strategy) }, + }; +#endif c_stream.zalloc = zalloc; c_stream.zfree = zfree; @@ -269,7 +277,27 @@ void test_large_deflate(unsigned char *compr, size_t comprLen, unsigned char *un } /* Feed in already compressed data and switch to no compression: */ - PREFIX(deflateParams)(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + if (zng_params) { +#ifndef ZLIB_COMPAT + zng_deflateGetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); + if (level != Z_BEST_SPEED) { + fprintf(stderr, "Expected compression level Z_BEST_SPEED, got %d\n", level); + exit(1); + } + if (strategy != Z_DEFAULT_STRATEGY) { + fprintf(stderr, "Expected compression strategy Z_DEFAULT_STRATEGY, got %d\n", strategy); + exit(1); + } + level = Z_NO_COMPRESSION; + strategy = Z_DEFAULT_STRATEGY; + zng_deflateSetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); +#else + fprintf(stderr, "test_large_deflate() called with zng_params=1 in compat mode\n"); + exit(1); +#endif + } else { + PREFIX(deflateParams)(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + } c_stream.next_in = compr; diff = (unsigned int)(c_stream.next_out - compr); c_stream.avail_in = diff; @@ -277,7 +305,29 @@ void test_large_deflate(unsigned char *compr, size_t comprLen, unsigned char *un CHECK_ERR(err, "deflate"); /* Switch back to compressing mode: */ - PREFIX(deflateParams)(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + if (zng_params) { +#ifndef ZLIB_COMPAT + level = -1; + strategy = -1; + zng_deflateGetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); + if (level != Z_NO_COMPRESSION) { + fprintf(stderr, "Expected compression level Z_NO_COMPRESSION, got %d\n", level); + exit(1); + } + if (strategy != Z_DEFAULT_STRATEGY) { + fprintf(stderr, "Expected compression strategy Z_DEFAULT_STRATEGY, got %d\n", strategy); + exit(1); + } + level = Z_BEST_COMPRESSION; + strategy = Z_FILTERED; + zng_deflateSetParams(&c_stream, params, sizeof(params) / sizeof(params[0])); +#else + fprintf(stderr, "test_large_deflate() called with zng_params=1 in compat mode\n"); + exit(1); +#endif + } else { + PREFIX(deflateParams)(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + } c_stream.next_in = uncompr; c_stream.avail_in = (unsigned int)uncomprLen; err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); @@ -535,8 +585,13 @@ int main(int argc, char *argv[]) test_deflate(compr, comprLen); test_inflate(compr, comprLen, uncompr, uncomprLen); - test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_deflate(compr, comprLen, uncompr, uncomprLen, 0); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + +#ifndef ZLIB_COMPAT + test_large_deflate(compr, comprLen, uncompr, uncomprLen, 1); test_large_inflate(compr, comprLen, uncompr, uncomprLen); +#endif test_flush(compr, &comprLen); test_sync(compr, comprLen, uncompr, uncomprLen); diff --git a/win32/zlib-ng.def b/win32/zlib-ng.def index fd1047f441..2525a861d6 100644 --- a/win32/zlib-ng.def +++ b/win32/zlib-ng.def @@ -17,6 +17,8 @@ EXPORTS zng_deflatePending zng_deflatePrime zng_deflateSetHeader + zng_deflateSetParams + zng_deflateGetParams zng_inflateSetDictionary zng_inflateGetDictionary zng_inflateSync @@ -1790,6 +1790,46 @@ ZEXTERN int ZEXPORT zng_gzgetc_(gzFile file); /* backward compatibility */ #endif /* WITH_GZFILEOP */ +typedef enum { + Z_DEFLATE_LEVEL = 0, /* compression level, represented as an int */ + Z_DEFLATE_STRATEGY = 1, /* compression strategy, represented as an int */ +} zng_deflate_param; + +typedef struct { + zng_deflate_param param; /* parameter ID */ + void *buf; /* parameter value */ + size_t size; /* parameter value size */ + int status; /* result of the last set/get call */ +} zng_deflate_param_value; + +ZEXTERN int ZEXPORT zng_deflateSetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count); +/* + Sets the values of the given zlib-ng deflate stream parameters. All the buffers are copied internally, so the + caller still owns them after this function returns. Returns Z_OK if success. + + If the size of at least one of the buffers is too small to hold the entire value of the corresponding parameter, + or if the same parameter is specified multiple times, Z_BUF_ERROR is returned. The caller may inspect status fields + in order to determine which of the parameters caused this error. No other changes are performed. + + If the stream state is inconsistent or if at least one of the values cannot be updated, Z_STREAM_ERROR is + returned. The caller may inspect status fields in order to determine which of the parameters caused this error. + Parameters, whose status field is equal to Z_OK, have been applied successfully. If all status fields are not equal + to Z_STREAM_ERROR, then the error was caused by a stream state inconsistency. + + If there are no other errors, but at least one parameter is not supported by the current zlib-ng version, + Z_VERSION_ERROR is returned. The caller may inspect status fields in order to determine which of the parameters + caused this error. +*/ + +ZEXTERN int ZEXPORT zng_deflateGetParams(zng_stream *strm, zng_deflate_param_value *params, size_t count); +/* + Copies the values of the given zlib-ng deflate stream parameters into the user-provided buffers. Returns Z_OK if + success, Z_VERSION_ERROR if at least one parameter is not supported by the current zlib-ng version, Z_STREAM_ERROR + if the stream state is inconsistent, and Z_BUF_ERROR if the size of at least one buffer is too small to hold the + entire value of the corresponding parameter. +*/ + + /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular diff --git a/zlib-ng.map b/zlib-ng.map index 107d069583..29744f5b22 100644 --- a/zlib-ng.map +++ b/zlib-ng.map @@ -19,6 +19,7 @@ ZLIB_NG_1.9.9 { zng_deflateCopy; zng_deflateEnd; zng_deflateGetDictionary; + zng_deflateGetParams; zng_deflateInit_; zng_deflateInit2_; zng_deflateParams; @@ -28,6 +29,7 @@ ZLIB_NG_1.9.9 { zng_deflateResetKeep; zng_deflateSetDictionary; zng_deflateSetHeader; + zng_deflateSetParams; zng_deflateTune; zng_get_crc_table; zng_inflate; |
