summaryrefslogtreecommitdiff
path: root/ext/zlib/zlib.c
diff options
context:
space:
mode:
authorBob Weinand <bobwei9@hotmail.com>2015-02-27 17:24:32 +0100
committerDaniel Lowrey <rdlowrey@php.net>2015-04-22 06:04:13 -0600
commite0e1d99c719a228d4702d3b71eb4ae8dfc47d539 (patch)
treea31d70b7ea45c1abe333ba18f7916d7ec57aa1f8 /ext/zlib/zlib.c
parented102533116d7771bf2f8fd5d0e4f345b38b1da5 (diff)
downloadphp-git-e0e1d99c719a228d4702d3b71eb4ae8dfc47d539.tar.gz
Add incremental zlib deflate API
Diffstat (limited to 'ext/zlib/zlib.c')
-rw-r--r--ext/zlib/zlib.c153
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;
}