summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/zlib/zlib.c153
1 files changed, 150 insertions, 3 deletions
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 8cbc5b3dfa..13dfb311ee 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -47,6 +47,7 @@
#undef gztell
int le_deflate;
+int le_inflate;
ZEND_DECLARE_MODULE_GLOBALS(zlib);
@@ -63,7 +64,7 @@ static void php_zlib_free(voidpf opaque, voidpf address)
}
/* }}} */
-/* {{{ Incremental deflate resource destructor */
+/* {{{ Incremental deflate/inflate resource destructors */
void deflate_rsrc_dtor(zend_resource *res)
{
@@ -72,6 +73,13 @@ void deflate_rsrc_dtor(zend_resource *res)
efree(ctx);
}
+void inflate_rsrc_dtor(zend_resource *res)
+{
+ z_stream *ctx = zend_fetch_resource(res, NULL, le_inflate);
+ inflateEnd(ctx);
+ efree(ctx);
+}
+
/* }}} */
/* {{{ php_zlib_output_conflict_check() */
@@ -744,6 +752,132 @@ PHP_ZLIB_DECODE_FUNC(gzdecode, PHP_ZLIB_ENCODING_GZIP);
PHP_ZLIB_DECODE_FUNC(gzuncompress, PHP_ZLIB_ENCODING_DEFLATE);
/* }}} */
+/* {{{ proto resource inflate_init(int encoding)
+ Initialize an incremental inflate context with the specified encoding */
+PHP_FUNCTION(inflate_init)
+{
+ z_stream *ctx;
+ zend_long encoding;
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l", &encoding)) {
+ 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 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 == inflateInit2(ctx, encoding)) {
+ RETURN_RES(zend_register_resource(ctx, le_inflate));
+ } else {
+ efree(ctx);
+ php_error_docref(NULL, E_WARNING, "failed allocating zlib.inflate context");
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string inflate_add(resource context, string encoded_data[, int flush_mode = ZLIB_SYNC_FLUSH])
+ Incrementally inflate encoded data in the specified context */
+PHP_FUNCTION(inflate_add)
+{
+ zend_string *out;
+ char *in_buf;
+ size_t in_len, buffer_used = 0, CHUNK_SIZE = 8192;
+ zval *res;
+ z_stream *ctx;
+ 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_FALSE;
+ }
+
+ if (!(ctx = zend_fetch_resource_ex(res, NULL, le_inflate))) {
+ php_error_docref(NULL, E_WARNING, "Invalid zlib.inflate resource");
+ RETURN_FALSE;
+ }
+
+ switch (flush_type) {
+ case Z_NO_FLUSH:
+ case Z_PARTIAL_FLUSH:
+ case Z_SYNC_FLUSH:
+ case Z_FULL_FLUSH:
+ case Z_BLOCK:
+ case Z_FINISH:
+ break;
+
+ default:
+ 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 && flush_type != Z_FINISH) {
+ RETURN_EMPTY_STRING();
+ }
+
+ out = zend_string_alloc((in_len > CHUNK_SIZE) ? in_len : CHUNK_SIZE, 0);
+ ctx->next_in = (Bytef *) in_buf;
+ ctx->next_out = (Bytef *) out->val;
+ ctx->avail_in = in_len;
+ ctx->avail_out = out->len;
+
+ do {
+ status = inflate(ctx, flush_type);
+ buffer_used = out->len - ctx->avail_out;
+
+ switch (status) {
+ case Z_OK:
+ if (ctx->avail_out == 0) {
+ /* more output buffer space needed; realloc and try again */
+ out = zend_string_realloc(out, out->len + CHUNK_SIZE, 0);
+ ctx->avail_out = CHUNK_SIZE;
+ ctx->next_out = (Bytef *) out->val + buffer_used;
+ break;
+ } else {
+ goto complete;
+ }
+ case Z_STREAM_END:
+ inflateReset(ctx);
+ goto complete;
+ case Z_BUF_ERROR:
+ if (flush_type == Z_FINISH && ctx->avail_out == 0) {
+ /* more output buffer space needed; realloc and try again */
+ out = zend_string_realloc(out, out->len + CHUNK_SIZE, 0);
+ ctx->avail_out = CHUNK_SIZE;
+ ctx->next_out = (Bytef *) out->val + buffer_used;
+ break;
+ } else {
+ /* No more input data; we're finished */
+ goto complete;
+ }
+ default:
+ zend_string_release(out);
+ php_error_docref(NULL, E_WARNING, "%s", zError(status));
+ RETURN_FALSE;
+ }
+ } while (1);
+
+ complete: {
+ out = zend_string_realloc(out, buffer_used, 0);
+ out->val[buffer_used] = 0;
+ RETURN_STR(out);
+ }
+}
+/* }}} */
+
/* {{{ proto resource deflate_init(int encoding[, array options])
Initialize an incremental deflate context using the specified encoding */
PHP_FUNCTION(deflate_init)
@@ -808,7 +942,7 @@ PHP_FUNCTION(deflate_init)
RETURN_RES(zend_register_resource(ctx, le_deflate));
} else {
efree(ctx);
- php_error_docref(NULL, E_WARNING, "failed allocating deflate context");
+ php_error_docref(NULL, E_WARNING, "failed allocating zlib.deflate context");
RETURN_FALSE;
}
}
@@ -1004,6 +1138,16 @@ 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_EX(arginfo_inflate_init, 0, 0, 1)
+ ZEND_ARG_INFO(0, encoding)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_inflate_add, 0, 0, 2)
+ ZEND_ARG_INFO(0, resource)
+ ZEND_ARG_INFO(0, flush_behavior)
+ZEND_END_ARG_INFO()
+
+
/* {{{ php_zlib_functions[] */
static const zend_function_entry php_zlib_functions[] = {
PHP_FE(readgzfile, arginfo_readgzfile)
@@ -1030,8 +1174,10 @@ 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_init, arginfo_deflate_init)
PHP_FE(deflate_add, arginfo_deflate_add)
+ PHP_FE(inflate_init, arginfo_inflate_init)
+ PHP_FE(inflate_add, arginfo_inflate_add)
PHP_FE(ob_gzhandler, arginfo_ob_gzhandler)
PHP_FE_END
};
@@ -1122,6 +1268,7 @@ static PHP_MINIT_FUNCTION(zlib)
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);
+ le_inflate = zend_register_list_destructors_ex(inflate_rsrc_dtor, NULL, "zlib.inflate", 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);