diff options
author | Stefan Roehrich <sr@php.net> | 2002-03-12 13:23:58 +0000 |
---|---|---|
committer | Stefan Roehrich <sr@php.net> | 2002-03-12 13:23:58 +0000 |
commit | edcb5813db43c86dbe415c861c47207aa457cfa2 (patch) | |
tree | bdd6c64431184ecd9df24813fc0c44271499c6ad | |
parent | cede952f6a51eb0923e51d22481cd03481c51b9b (diff) | |
download | php-git-edcb5813db43c86dbe415c861c47207aa457cfa2.tar.gz |
(PHP gzencode) Reimplementation of gzencode(). Now works as documented
(gzencode(string data [, int level [, int encoding_mode]])),
should fix #15930.
@- The second parameter of gzencode() now is the compression level like
@ in the documentation. The encoding mode is a third (optional) parameter.
# Rework of gzencode(), output should be closer to real gzip output.
# I think in the old version there could be some problems with
# this function and output compression, should be fixed, too.
-rw-r--r-- | ext/zlib/tests/003.phpt | 4 | ||||
-rw-r--r-- | ext/zlib/zlib.c | 112 |
2 files changed, 93 insertions, 23 deletions
diff --git a/ext/zlib/tests/003.phpt b/ext/zlib/tests/003.phpt index 322996fa75..254a4563ad 100644 --- a/ext/zlib/tests/003.phpt +++ b/ext/zlib/tests/003.phpt @@ -9,8 +9,8 @@ gzencode()/base64_encode() $original = str_repeat("hallo php",4096); $packed=gzencode($original); echo strlen($packed)." ".strlen($original)."\n"; -if (strcmp(base64_encode($packed),"H4sIAAAAAAAAA+zGoQ0AQAgEsFV+NdwJEthf/R6kVU11z9tsRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERETu5gMAAP//AwDlQAe9AJAAAA==")==0) echo "Strings are equal"; +if (strcmp(base64_encode($packed),"H4sIAAAAAAAAA+3GoQ0AQAgEsFV+NdwJEthf/R6kVU11z9tsRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERETu5gPlQAe9AJAAAA==")==0) echo "Strings are equal"; ?> --EXPECT-- -124 36864 +118 36864 Strings are equal diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 02889609c7..fdb54ca76e 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -76,6 +76,8 @@ #define OS_CODE 0x03 /* FIXME */ #define CODING_GZIP 1 #define CODING_DEFLATE 2 +#define GZIP_HEADER_LENGTH 10 +#define GZIP_FOOTER_LENGTH 8 /* True globals, no need for thread safety */ static int le_zp; @@ -761,7 +763,7 @@ PHP_FUNCTION(gzcompress) convert_to_long_ex(zlimit); limit = Z_LVAL_PP(zlimit); if((limit<0)||(limit>9)) { - php_error(E_WARNING,"gzcompress: compression level must be whithin 0..9"); + php_error(E_WARNING,"gzcompress: compression level must be within 0..9"); RETURN_FALSE; } break; @@ -870,7 +872,7 @@ PHP_FUNCTION(gzdeflate) convert_to_long_ex(zlimit); level = Z_LVAL_PP(zlimit); if((level<0)||(level>9)) { - php_error(E_WARNING,"gzdeflate: compression level must be whithin 0..9"); + php_error(E_WARNING,"gzdeflate: compression level must be within 0..9"); RETURN_FALSE; } break; @@ -1124,36 +1126,104 @@ int php_deflate_string(const char *str, uint str_length, char **newstr, uint *ne } /* }}} */ -/* {{{ proto string gzencode(string data [, int encoding_mode]) +/* {{{ proto string gzencode(string data [, int level [, int encoding_mode]]) GZ encode a string */ PHP_FUNCTION(gzencode) { - zval **zv_coding, **zv_string; - int coding; + char *data, *s2; + int data_len; + int level = Z_DEFAULT_COMPRESSION, coding = CODING_GZIP; + int status; + z_stream stream; - switch(ZEND_NUM_ARGS()) { - case 1: - if (zend_get_parameters_ex(1, &zv_string)==FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &data, &data_len, &level, &coding) == FAILURE) { + return; + } + + if((level<-1)||(level>9)) { + php_error(E_WARNING,"gzencode: compression level must be within -1..9"); + RETURN_FALSE; + } + + if((coding!=CODING_GZIP)&&(coding!=CODING_DEFLATE)) { + php_error(E_WARNING,"gzencode: encoding mode must be FORCE_GZIP or FORCE_DEFLATE"); + RETURN_FALSE; + } + + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + stream.next_in = (Bytef*) data; + stream.avail_in = data_len; + + stream.avail_out = stream.avail_in + (stream.avail_in/1000) + 15 + 1; /* room for \0 */ + s2 = (char *) emalloc(stream.avail_out+GZIP_HEADER_LENGTH+(coding==CODING_GZIP?GZIP_FOOTER_LENGTH:0)); + if(!s2) + RETURN_FALSE; + + /* add gzip file header */ + s2[0] = gz_magic[0]; + s2[1] = gz_magic[1]; + s2[2] = Z_DEFLATED; + s2[3] = s2[4] = s2[5] = s2[6] = s2[7] = s2[8] = 0; /* time set to 0 */ + s2[9] = OS_CODE; + + stream.next_out = &(s2[GZIP_HEADER_LENGTH]); + + switch (coding) { + case CODING_GZIP: + /* windowBits is passed < 0 to suppress zlib header & trailer */ + if ((status = deflateInit2(&stream, level, Z_DEFLATED, + -MAX_WBITS, MAX_MEM_LEVEL, + Z_DEFAULT_STRATEGY)) + != Z_OK) { + php_error(E_WARNING,"gzencode: %s", zError(status)); RETURN_FALSE; } - convert_to_string_ex(zv_string); - coding = 1; + break; - case 2: - if (zend_get_parameters_ex(2, &zv_string, &zv_coding)==FAILURE) { + case CODING_DEFLATE: + if ((status = deflateInit(&stream, level)) != Z_OK) { + php_error(E_WARNING,"gzencode: %s", zError(status)); RETURN_FALSE; } - convert_to_string_ex(zv_string); - convert_to_long_ex(zv_coding); - coding = Z_LVAL_PP(zv_coding); - break; - default: - ZEND_WRONG_PARAM_COUNT(); - break; + break; } - if (php_deflate_string(Z_STRVAL_PP(zv_string), Z_STRLEN_PP(zv_string), &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value), coding, 1, 1 TSRMLS_CC)==SUCCESS) { - Z_TYPE_P(return_value) = IS_STRING; + + status = deflate(&stream, Z_FINISH); + if (status != Z_STREAM_END) { + deflateEnd(&stream); + if (status == Z_OK) { + status = Z_BUF_ERROR; + } } else { + status = deflateEnd(&stream); + } + + if (status==Z_OK) { + s2 = erealloc(s2,stream.total_out+GZIP_HEADER_LENGTH+(coding==CODING_GZIP?GZIP_FOOTER_LENGTH:0)+1); /* resize to buffer to the "right" size */ + if (coding == CODING_GZIP) { + char *trailer = s2+(stream.total_out+GZIP_HEADER_LENGTH); + uLong crc = crc32(0L, Z_NULL, 0); + + crc = crc32(crc, (const Bytef *) data, data_len); + + /* write crc & stream.total_in in LSB order */ + trailer[0] = (char) crc & 0xFF; + trailer[1] = (char) (crc >> 8) & 0xFF; + trailer[2] = (char) (crc >> 16) & 0xFF; + trailer[3] = (char) (crc >> 24) & 0xFF; + trailer[4] = (char) stream.total_in & 0xFF; + trailer[5] = (char) (stream.total_in >> 8) & 0xFF; + trailer[6] = (char) (stream.total_in >> 16) & 0xFF; + trailer[7] = (char) (stream.total_in >> 24) & 0xFF; + trailer[8] = '\0'; + } + RETURN_STRINGL(s2, stream.total_out+GZIP_HEADER_LENGTH+(coding==CODING_GZIP?GZIP_FOOTER_LENGTH:0), 0); + } else { + efree(s2); + php_error(E_WARNING,"gzencode: %s",zError(status)); RETURN_FALSE; } } |