Hello!

I have two patches for zlib.c, but before commiting, I would like to
hear some comments.

First patch (should fix bug #14939):

I could reproduce #14939 even with a simple C program, so I think,
it's rather a very unusual behaviour of the zlib library which seems
to want to read a little bit more than it needs (we are using an
undocumented function (which everybody seems to use), so I don't want
to call it a bug ...).

But I'm unsure, if the fix is really correct. If the input of
gzinflate() comes directly from gzdeflate(), I'm allowed to read this
additional byte, because gzdeflate() added a trailing \0 like many
"string" operations which deal with binary strings. But are there
circumstances where there isn't this trailing \0 (and I'm dealing with
deflated data)?

(I think, with this patch it can't get worse as the actual situation,
because this additional byte is only used in the (very rare)
circumstances where the zlib library wants to read it. I could
reproduce this with strings of 'a' of length about 15, not much more
and not much less).

Second patch (related to bug #15930):

There was an error in the documentation, the gzencode() function was
misdocumented to have a second optional level parameter, but this was
an encoding mode, not the compression level. I fixed this and added an
additional parameter level, so that you can now give the compression
level.

But how should I add it? The problem is, if you use it with the
required and one optional parameter, should it behave like in the
documentation (gzencode($data [, $level [, $mode]])) or like the (old)
source (gzencode($data [, $mode [, $level]])) ? What do you think?

In my patch I used the form gzencode($data [, $level [, $mode]]),
because I think, the mode parameter isn't really needed. I also think
that there were some problems with the old gzencode() function, it
isn't clear to me, why it should have worked reliably in conjunction
with output compression, so I rewrote this routine. I tried to keep
the old behaviour, so you can give a mode of FORCE_DEFLATE and then
you get a normal zlib deflated string plus the gzip file header but
without the trailing checksum.

Can you please test it a little bit and if nobody objects, I'll commit
it to HEAD.

(Derick: these are two bug fixes, please tell me, if I should commit
them to PHP_4_2_0).

  Stefan

-- 
Stefan Röhrich               [EMAIL PROTECTED], [EMAIL PROTECTED]
                                 http://www.roehri.ch/~sr/
--- /home/sr/cvs/php/php4/ext/zlib/zlib.c       Thu Mar  7 16:38:26 2002
+++ ext/zlib/zlib.c     Thu Mar  7 23:15:48 2002
@@ -967,7 +967,7 @@
                if(! s2) { if(s1) efree(s1); RETURN_FALSE; }
 
                stream.next_in = (Bytef*) Z_STRVAL_PP(data);
-               stream.avail_in = (uInt) Z_STRLEN_PP(data);
+               stream.avail_in = (uInt) Z_STRLEN_PP(data) + 1; /* there is room for 
+\0 */
 
                stream.next_out = s2;
                stream.avail_out = (uInt) length;
--- /home/sr/cvs/php/php4/ext/zlib/zlib.c       Thu Mar  7 16:38:26 2002
+++ ext/zlib/zlib.c     Sun Mar 10 13:22:42 2002
@@ -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;
@@ -1124,36 +1126,104 @@
 }
 /* }}} */
 
-/* {{{ 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 whithin 
+-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;
        }
 }

-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to