diff options
author | Bob Weinand <bobwei9@hotmail.com> | 2015-02-27 17:24:32 +0100 |
---|---|---|
committer | Daniel Lowrey <rdlowrey@php.net> | 2015-04-22 06:04:13 -0600 |
commit | e0e1d99c719a228d4702d3b71eb4ae8dfc47d539 (patch) | |
tree | a31d70b7ea45c1abe333ba18f7916d7ec57aa1f8 /ext/zlib/zlib.c | |
parent | ed102533116d7771bf2f8fd5d0e4f345b38b1da5 (diff) | |
download | php-git-e0e1d99c719a228d4702d3b71eb4ae8dfc47d539.tar.gz |
Add incremental zlib deflate API
Diffstat (limited to 'ext/zlib/zlib.c')
-rw-r--r-- | ext/zlib/zlib.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 64eac450cd..55b6a4a226 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -46,6 +46,8 @@ #undef gzseek #undef gztell +int le_deflate; + ZEND_DECLARE_MODULE_GLOBALS(zlib); /* {{{ Memory management wrappers */ @@ -731,6 +733,131 @@ PHP_ZLIB_DECODE_FUNC(gzdecode, PHP_ZLIB_ENCODING_GZIP); PHP_ZLIB_DECODE_FUNC(gzuncompress, PHP_ZLIB_ENCODING_DEFLATE); /* }}} */ +void deflate_rsrc_dtor(zend_resource *res) +{ + z_stream *ctx = zend_fetch_resource(res, NULL, le_deflate); + deflateEnd(ctx); + efree(ctx); +} + +PHP_FUNCTION(deflate_init) +{ + z_stream *ctx; + int level = -1, encoding; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &encoding, &level)) { + return; + } + + if (level < -1 || level > 9) { + php_error_docref(NULL, E_WARNING, "compression level (%pd) must be within -1..9", level); + RETURN_FALSE; + } + + switch (encoding) { + case PHP_ZLIB_ENCODING_RAW: + case PHP_ZLIB_ENCODING_GZIP: + case PHP_ZLIB_ENCODING_DEFLATE: + break; + default: + php_error_docref(NULL, E_WARNING, "encoding mode must be either ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE"); + RETURN_FALSE; + } + + ctx = ecalloc(1, sizeof(php_zlib_context)); + ctx->zalloc = php_zlib_alloc; + ctx->zfree = php_zlib_free; + + if (Z_OK == deflateInit2(ctx, level, Z_DEFLATED, encoding, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) { + RETURN_RES(zend_register_resource(ctx, le_deflate)); + } else { + efree(ctx); + } +} + +PHP_FUNCTION(deflate_add) +{ + zend_string *out; + char *in_buf; + size_t in_len; + zval *res; + z_stream *ctx; + int flush_type = Z_SYNC_FLUSH; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &res, &in_buf, &in_len, &flush_type)) { + return; + } + + if (!(ctx = zend_fetch_resource_ex(res, NULL, le_deflate))) { + zend_error(E_WARNING, "Invalid type of resource passed"); + return; + } + + switch (flush_type) { + case Z_NO_FLUSH: + case Z_PARTIAL_FLUSH: + case Z_SYNC_FLUSH: + case Z_FULL_FLUSH: + case Z_BLOCK: + break; + + default: + php_error_docref(NULL, E_WARNING, "flushing mode must be either ZLIB_NO_FLUSH, ZLIB_PARTIAL_FLUSH, ZLIB_SYNC_FLUSH, ZLIB_FULL_FLUSH or ZLIB_BLOCK"); + } + + if (in_len <= 0) { + RETURN_EMPTY_STRING(); + } + + out = zend_string_alloc(PHP_ZLIB_BUFFER_SIZE_GUESS(ctx->total_in + in_len) - ctx->total_out, 0); + + ctx->next_in = (Bytef *) in_buf; + ctx->next_out = (Bytef *) out->val; + ctx->avail_in = in_len; + ctx->avail_out = out->len; + + if (deflate(ctx, flush_type) == Z_OK) { + out->len = (char *) ctx->next_out - out->val; + out->val[out->len] = 0; + + RETURN_STR(out); + } + + RETURN_FALSE; // should not happen +} + +PHP_FUNCTION(deflate_flush) +{ + zend_string *out; + zval *res; + z_stream *ctx; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "r", &res)) { + return; + } + + if (!(ctx = zend_fetch_resource_ex(res, NULL, le_deflate))) { + zend_error(E_WARNING, "Invalid type of resource passed"); + return; + } + + out = zend_string_alloc(PHP_ZLIB_BUFFER_SIZE_GUESS(ctx->total_in) - ctx->total_out, 0); + + ctx->next_in = (Bytef *) res; // random valid pointer + ctx->next_out = (Bytef *) out->val; + ctx->avail_in = 0; + ctx->avail_out = out->len; + + if (deflate(ctx, Z_FINISH) == Z_STREAM_END) { + out->len = (char *) ctx->next_out - out->val; + out->val[out->len] = 0; + + RETURN_STR(out); + } + + RETURN_FALSE; // should not happen +} + #ifdef COMPILE_DL_ZLIB #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE(); @@ -838,6 +965,21 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_gzgets, 0, 0, 1) ZEND_ARG_INFO(0, fp) ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_deflate_init, 0, 0, 1) + ZEND_ARG_INFO(0, encoding) + ZEND_ARG_INFO(0, level) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_deflate_add, 0, 0, 2) + ZEND_ARG_INFO(0, resource) + ZEND_ARG_INFO(0, add) + ZEND_ARG_INFO(0, flush_behavior) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_deflate_flush, 0) + ZEND_ARG_INFO(0, resource) +ZEND_END_ARG_INFO() /* }}} */ /* {{{ php_zlib_functions[] */ @@ -866,6 +1008,9 @@ static const zend_function_entry php_zlib_functions[] = { PHP_FE(zlib_encode, arginfo_zlib_encode) PHP_FE(zlib_decode, arginfo_zlib_decode) PHP_FE(zlib_get_coding_type, arginfo_zlib_get_coding_type) + PHP_FE(deflate_init, arginfo_deflate_init) + PHP_FE(deflate_add, arginfo_deflate_add) + PHP_FE(deflate_flush, arginfo_deflate_flush) PHP_FE(ob_gzhandler, arginfo_ob_gzhandler) PHP_FE_END }; @@ -955,12 +1100,20 @@ static PHP_MINIT_FUNCTION(zlib) php_output_handler_conflict_register(ZEND_STRL("ob_gzhandler"), php_zlib_output_conflict_check); php_output_handler_conflict_register(ZEND_STRL(PHP_ZLIB_OUTPUT_HANDLER_NAME), php_zlib_output_conflict_check); + le_deflate = zend_register_list_destructors_ex(deflate_rsrc_dtor, NULL, "zlib.deflate", module_number); + REGISTER_LONG_CONSTANT("FORCE_GZIP", PHP_ZLIB_ENCODING_GZIP, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("FORCE_DEFLATE", PHP_ZLIB_ENCODING_DEFLATE, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("ZLIB_ENCODING_RAW", PHP_ZLIB_ENCODING_RAW, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("ZLIB_ENCODING_GZIP", PHP_ZLIB_ENCODING_GZIP, CONST_CS|CONST_PERSISTENT); REGISTER_LONG_CONSTANT("ZLIB_ENCODING_DEFLATE", PHP_ZLIB_ENCODING_DEFLATE, CONST_CS|CONST_PERSISTENT); + + REGISTER_LONG_CONSTANT("ZLIB_NO_FLUSH", Z_NO_FLUSH, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ZLIB_PARTIAL_FLUSH", Z_PARTIAL_FLUSH, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ZLIB_SYNC_FLUSH", Z_SYNC_FLUSH, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ZLIB_FULL_FLUSH", Z_FULL_FLUSH, CONST_CS|CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ZLIB_BLOCK", Z_BLOCK, CONST_CS|CONST_PERSISTENT); REGISTER_INI_ENTRIES(); return SUCCESS; } |