summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Lowrey <rdlowrey@php.net>2015-04-21 23:00:10 -0600
committerDaniel Lowrey <rdlowrey@php.net>2015-04-23 23:49:35 -0600
commitdaecc326188d7d3ced05e42f0c07ded4e9b130aa (patch)
tree4b216b85f51bf5e93938a9bb1a391f5944f8a058
parente0e1d99c719a228d4702d3b71eb4ae8dfc47d539 (diff)
downloadphp-git-daecc326188d7d3ced05e42f0c07ded4e9b130aa.tar.gz
Several deflate_* changes (more after the jump)
- 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
-rw-r--r--ext/zlib/zlib.c150
1 files changed, 86 insertions, 64 deletions
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 55b6a4a226..8cbc5b3dfa 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -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;
}