Fixed bug #33070 (Improved performance of bzdecompress() by several orders

of magnitude).
This commit is contained in:
Ilia Alshanetsky 2005-06-05 18:04:20 +00:00
parent c28f59a1d5
commit a13aaa8aef

View file

@ -40,9 +40,6 @@
#define PHP_BZ_ERRSTR 1 #define PHP_BZ_ERRSTR 1
#define PHP_BZ_ERRBOTH 2 #define PHP_BZ_ERRBOTH 2
/* Blocksize of the decompression buffer */
#define PHP_BZ_DECOMPRESS_SIZE 4096
function_entry bz2_functions[] = { function_entry bz2_functions[] = {
PHP_FE(bzopen, NULL) PHP_FE(bzopen, NULL)
PHP_FE(bzread, NULL) PHP_FE(bzread, NULL)
@ -441,56 +438,49 @@ PHP_FUNCTION(bzcompress)
Decompresses BZip2 compressed data */ Decompresses BZip2 compressed data */
PHP_FUNCTION(bzdecompress) PHP_FUNCTION(bzdecompress)
{ {
zval **source, /* Source data to decompress */ char *source, *dest;
**zsmall; /* (Optional) user specified small */ int source_len, error;
char *dest; /* Destination buffer, initially allocated */ long small = 0;
int error, /* Error container */ unsigned int size = 0;
iter = 1, /* Iteration count for the compression loop */ bz_stream bzs;
size, /* Current size to realloc the dest buffer to */
dest_len = PHP_BZ_DECOMPRESS_SIZE, /* Size of the destination length */ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &source, &source_len, &small)) {
small = 0, /* The actual small */ RETURN_FALSE;
argc = ZEND_NUM_ARGS(); /* Argument count */
if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &source, &zsmall) == FAILURE) {
WRONG_PARAM_COUNT;
} }
convert_to_string_ex(source); bzs.bzalloc = NULL;
bzs.bzfree = NULL;
/* optional small argument handling */
if (argc > 1) { if (BZ2_bzDecompressInit(&bzs, 0, small) != BZ_OK) {
convert_to_long_ex(zsmall); RETURN_FALSE;
small = Z_LVAL_PP(zsmall);
} }
/* Depending on the size of the source buffer, either allocate bzs.next_in = source;
the length of the source buffer or the a default decompression bzs.avail_in = source_len;
size */
dest = emalloc(PHP_BZ_DECOMPRESS_SIZE > Z_STRLEN_PP(source) ? PHP_BZ_DECOMPRESS_SIZE : Z_STRLEN_PP(source));
/* (de)Compression Loop */ /* in most cases bz2 offers at least 2:1 compression, so we use that as our base */
do { bzs.avail_out = source_len * 2;
/* Handle the (re)allocation of the buffer */ bzs.next_out = dest = emalloc(bzs.avail_out + 1);
size = dest_len * iter;
if (iter > 1) {
dest = erealloc(dest, size);
}
++iter;
/* Perform the decompression */
error = BZ2_bzBuffToBuffDecompress(dest, &size, Z_STRVAL_PP(source), Z_STRLEN_PP(source), small, 0);
} while (error == BZ_OUTBUFF_FULL);
if (error != BZ_OK) { while ((error = BZ2_bzDecompress(&bzs)) == BZ_OK && bzs.avail_in > 0) {
efree(dest); /* compression is better then 2:1, need to allocate more memory */
RETURN_LONG(error); bzs.avail_out = source_len;
} else { size = (bzs.total_out_hi32 << 32) + bzs.total_out_lo32;
/* we might have allocated a little to much, so erealloc the buffer dest = erealloc(dest, size + bzs.avail_out + 1);
down to size, before returning it */ bzs.next_out = dest + size;
}
if (error == BZ_STREAM_END || error == BZ_OK) {
size = (bzs.total_out_hi32 << 32) + bzs.total_out_lo32;
dest = erealloc(dest, size + 1); dest = erealloc(dest, size + 1);
dest[size] = 0; dest[size] = '\0';
RETURN_STRINGL(dest, size, 0); RETVAL_STRINGL(dest, size, 0);
} else { /* real error */
efree(dest);
RETVAL_LONG(error);
} }
BZ2_bzDecompressEnd(&bzs);
} }
/* }}} */ /* }}} */