]> granicus.if.org Git - php/commitdiff
Several deflate_* changes (more after the jump)
authorDaniel Lowrey <rdlowrey@php.net>
Wed, 22 Apr 2015 05:00:10 +0000 (23:00 -0600)
committerDaniel Lowrey <rdlowrey@php.net>
Fri, 24 Apr 2015 05:49:35 +0000 (23:49 -0600)
- Remove deflate_flush()
- Add ZLIB_FINISH constant for use with deflate_add()
- Use options array at parameter 2 of deflate_add() to insulate
  against future API changes
- Minor bug fixes
- deflate_init() and deflate_add() now always return FALSE in the
  event of an error

ext/zlib/zlib.c

index 55b6a4a22645cb347483a7fdd49498b28f55cb25..8cbc5b3dfa650680d06fe83e85d0095862d7fe26 100644 (file)
@@ -63,6 +63,17 @@ static void php_zlib_free(voidpf opaque, voidpf address)
 }
 /* }}} */
 
+/* {{{ Incremental deflate resource destructor */
+
+void deflate_rsrc_dtor(zend_resource *res)
+{
+       z_stream *ctx = zend_fetch_resource(res, NULL, le_deflate);
+       deflateEnd(ctx);
+       efree(ctx);
+}
+
+/* }}} */
+
 /* {{{ php_zlib_output_conflict_check() */
 static int php_zlib_output_conflict_check(const char *handler_name, size_t handler_name_len)
 {
@@ -733,34 +744,59 @@ 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);
-}
-
+/* {{{ proto resource deflate_init(int encoding[, array options])
+   Initialize an incremental deflate context using the specified encoding */
 PHP_FUNCTION(deflate_init)
 {
        z_stream *ctx;
-       int level = -1, encoding;
+       zend_long encoding, level = -1, memory = 8;
+       HashTable *options = 0;
+       zval *option_buffer, cast_option_buffer;
 
-       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &encoding, &level)) {
-               return;
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) {
+               RETURN_FALSE;
        }
 
+       if (options && (option_buffer = zend_symtable_str_find(options, "level", sizeof("level")-1)) != NULL) {
+               if (Z_TYPE_P(option_buffer) != IS_LONG) {
+                       ZVAL_DUP(&cast_option_buffer, option_buffer);
+                       convert_to_long(&cast_option_buffer);
+                       level = Z_LVAL(cast_option_buffer);
+                       zval_dtor(&cast_option_buffer);
+               } else {
+                       level = Z_LVAL_P(option_buffer);
+               }
+       }
        if (level < -1 || level > 9) {
                php_error_docref(NULL, E_WARNING, "compression level (%pd) must be within -1..9", level);
                RETURN_FALSE;
        }
 
+       if (options && (option_buffer = zend_symtable_str_find(options, "memory", sizeof("memory")-1)) != NULL) {
+               if (Z_TYPE_P(option_buffer) != IS_LONG) {
+                       ZVAL_DUP(&cast_option_buffer, option_buffer);
+                       convert_to_long(&cast_option_buffer);
+                       memory = Z_LVAL(cast_option_buffer);
+                       zval_dtor(&cast_option_buffer);
+               } else {
+                       memory = Z_LVAL_P(option_buffer);
+               }
+       }
+       if (memory < 1 || memory > 9) {
+               php_error_docref(NULL, E_WARNING, "compression memory level (%pd) must be within 1..9", memory);
+               RETURN_FALSE;
+       }
+
+       /* @TODO: in the future we may add "strategy" and "dictionary" options */
+
        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");
+                       php_error_docref(NULL, E_WARNING,
+                               "encoding mode must be ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE");
                        RETURN_FALSE;
        }
 
@@ -768,29 +804,35 @@ PHP_FUNCTION(deflate_init)
        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)) {
+       if (Z_OK == deflateInit2(ctx, level, Z_DEFLATED, encoding, memory, Z_DEFAULT_STRATEGY)) {
                RETURN_RES(zend_register_resource(ctx, le_deflate));
        } else {
                efree(ctx);
+               php_error_docref(NULL, E_WARNING, "failed allocating deflate context");
+               RETURN_FALSE;
        }
 }
+/* }}} */
 
+/* {{{ proto string deflate_add(resource context, string data[, int flush_mode = ZLIB_SYNC_FLUSH])
+   Incrementally deflate data in the specified context */
 PHP_FUNCTION(deflate_add)
 {
        zend_string *out;
        char *in_buf;
-       size_t in_len;
+       size_t in_len, out_size;
        zval *res;
        z_stream *ctx;
-       int flush_type = Z_SYNC_FLUSH;
+       zend_long flush_type = Z_SYNC_FLUSH;
+       int status;
 
        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;
+               php_error_docref(NULL, E_WARNING, "Invalid deflate resource");
+               RETURN_FALSE;
        }
 
        switch (flush_type) {
@@ -799,64 +841,49 @@ PHP_FUNCTION(deflate_add)
                case Z_SYNC_FLUSH:
                case Z_FULL_FLUSH:
                case Z_BLOCK:
+               case Z_FINISH:
                        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");
+                       php_error_docref(NULL, E_WARNING,
+                               "flush mode must be ZLIB_NO_FLUSH, ZLIB_PARTIAL_FLUSH, ZLIB_SYNC_FLUSH, ZLIB_FULL_FLUSH, ZLIB_BLOCK or ZLIB_FINISH");
+                       RETURN_FALSE;
        }
 
-       if (in_len <= 0) {
+       if (in_len <= 0 && flush_type != Z_FINISH) {
                RETURN_EMPTY_STRING();
        }
 
-       out = zend_string_alloc(PHP_ZLIB_BUFFER_SIZE_GUESS(ctx->total_in + in_len) - ctx->total_out, 0);
+       out_size = PHP_ZLIB_BUFFER_SIZE_GUESS(ctx->total_in + in_len);
+       out_size = (ctx->total_out >= out_size) ? 16 : (out_size - ctx->total_out);
+       out_size = (out_size < 16) ? 16 : out_size;
+       out = zend_string_alloc(out_size, 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);
+       status = deflate(ctx, flush_type);
+       switch (status) {
+               case Z_OK:
+                       out->len = (char *) ctx->next_out - out->val;
+                       out->val[out->len] = 0;
+                       RETURN_STR(out);
+                       break;
+               case Z_STREAM_END:
+                       out->len = (char *) ctx->next_out - out->val;
+                       out->val[out->len] = 0;
+                       deflateReset(ctx);
+                       RETURN_STR(out);
+                       break;
+               default:
+                       zend_string_release(out);
+                       php_error_docref(NULL, E_WARNING, "zlib error (%s)", zError(status));
+                       RETURN_FALSE;
        }
-
-       RETURN_FALSE; // should not happen
 }
+/* }}} */
 
 #ifdef COMPILE_DL_ZLIB
 #ifdef ZTS
@@ -977,11 +1004,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_deflate_add, 0, 0, 2)
        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[] */
 static const zend_function_entry php_zlib_functions[] = {
        PHP_FE(readgzfile,                                              arginfo_readgzfile)
@@ -1010,7 +1032,6 @@ static const zend_function_entry php_zlib_functions[] = {
        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
 };
@@ -1114,6 +1135,7 @@ static PHP_MINIT_FUNCTION(zlib)
        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_LONG_CONSTANT("ZLIB_FINISH", Z_FINISH, CONST_CS|CONST_PERSISTENT);
        REGISTER_INI_ENTRIES();
        return SUCCESS;
 }