]> granicus.if.org Git - php/commitdiff
Add incremental zlib deflate API
authorBob Weinand <bobwei9@hotmail.com>
Fri, 27 Feb 2015 16:24:32 +0000 (17:24 +0100)
committerDaniel Lowrey <rdlowrey@php.net>
Wed, 22 Apr 2015 12:04:13 +0000 (06:04 -0600)
ext/zlib/zlib.c

index 64eac450cdc38783f64796f61be235e2de136b04..55b6a4a22645cb347483a7fdd49498b28f55cb25 100644 (file)
@@ -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;
 }