]> granicus.if.org Git - php/commitdiff
Fixed bug #61038; "Z" and better behavior for unpack()
authortheanomaly.is@gmail.com <googleguy@googleguy-virtualbox.(none)>
Tue, 17 Apr 2012 11:31:36 +0000 (07:31 -0400)
committerGustavo André dos Santos Lopes <cataphract@php.net>
Tue, 17 Apr 2012 20:09:04 +0000 (21:09 +0100)
Added new "Z" argument to pack/unpack, now allowing "a" to return
data without stripping, and "A" strips all trailing white space,
while "Z" will strip everything after the first null.

NEWS
UPGRADING
ext/standard/pack.c
ext/standard/tests/strings/bug61038.phpt [new file with mode: 0644]
ext/standard/tests/strings/unpack_error.phpt

diff --git a/NEWS b/NEWS
index ecfaa9385d5ccb82d3b539911c73d88037e01c08..ff5a31d5c0d1334143081f01510f823fbfa848f5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -9,9 +9,11 @@ PHP                                                                        NEWS
   . Support constant array/string dereferencing. (Laruence)
 
 - Core:
+  . Fixed bug #61681 (Malformed grammar). (Nikita Popov, Etienne, Laruence).
+  . Fixed bug #61038 (unpack("a5", "str\0\0") does not work as expected).
+    (srgoogleguy, Gustavo)
   . Implemented FR #60738 (Allow 'set_error_handler' to handle NULL).
     (Laruence, Nikita Popov)
-  . Fixed bug #61681 (Malformed grammar). (Nikita Popov, Etienne, Laruence).
 
 - cURL:
   . Added support for CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOPT_APPEND, 
index d6d6e9bb736c25065c2559f0b471f78358ac4697..27d01cbe949308946313e87c9a6c7f81af2f1220 100755 (executable)
--- a/UPGRADING
+++ b/UPGRADING
@@ -46,6 +46,12 @@ PHP X.Y UPGRADE NOTES
 4. Changed Functions
 ========================================
 
+- pack()/unpack() had the following changes, which bring it more in line
+  with Perl's behavior:
+  - Implemented format character "Z": NUL-padded string
+  - "a" now does not remove trailing NUL characters on unpack() anymore
+  - "A" will now strip all trailing ASCII whitespace on unpack() (it used to
+    remove only trailing spaces.
 
 ========================================
 5. New Functions
index faf0a2b2999d89dcde9e5f9d06779f5019ff8d27..c2fa28f6dd5baeb22392fe995bcb37e126b1d961 100644 (file)
@@ -99,7 +99,7 @@ static void php_pack(zval **val, int size, int *map, char *output)
 /* }}} */
 
 /* pack() idea stolen from Perl (implemented formats behave the same as there)
- * Implemented formats are A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
+ * Implemented formats are Z, A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
  */
 /* {{{ proto string pack(string format, mixed arg1 [, mixed arg2 [, mixed ...]])
    Takes one or more arguments and packs them into a binary string according to the format argument */
@@ -170,6 +170,7 @@ PHP_FUNCTION(pack)
                        /* Always uses one arg */
                        case 'a': 
                        case 'A': 
+                       case 'Z': 
                        case 'h': 
                        case 'H':
                                if (currentarg >= num_args) {
@@ -250,6 +251,7 @@ PHP_FUNCTION(pack)
 
                        case 'a': 
                        case 'A':
+                       case 'Z':
                        case 'c': 
                        case 'C':
                        case 'x':
@@ -315,7 +317,8 @@ PHP_FUNCTION(pack)
                switch ((int) code) {
                        case 'a': 
                        case 'A': 
-                               memset(&output[outputpos], (code == 'a') ? '\0' : ' ', arg);
+                       case 'Z': 
+                               memset(&output[outputpos], (code == 'a' || code == 'Z') ? '\0' : ' ', arg);
                                val = argv[currentarg++];
                                if (Z_ISREF_PP(val)) {
                                        SEPARATE_ZVAL(val);
@@ -511,7 +514,7 @@ static long php_unpack(char *data, int size, int issigned, int *map)
  * chars1, chars2, and ints.
  * Numeric pack types will return numbers, a and A will return strings,
  * f and d will return doubles.
- * Implemented formats are A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
+ * Implemented formats are Z, A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
  */
 /* {{{ proto array unpack(string format, string input)
    Unpack binary string into named array elements according to format argument */
@@ -586,6 +589,7 @@ PHP_FUNCTION(unpack)
 
                        case 'a': 
                        case 'A':
+                       case 'Z':
                                size = arg;
                                arg = 1;
                                break;
@@ -662,9 +666,24 @@ PHP_FUNCTION(unpack)
 
                        if ((inputpos + size) <= inputlen) {
                                switch ((int) type) {
-                                       case 'a': 
+                                       case 'a': {
+                                               /* a will not strip any trailing whitespace or null padding */
+                                               char pad = ' ';
+                                               int len = inputlen - inputpos;  /* Remaining string */
+
+                                               /* If size was given take minimum of len and size */
+                                               if ((size >= 0) && (len > size)) {
+                                                       len = size;
+                                               }
+
+                                               size = len;
+
+                                               add_assoc_stringl(return_value, n, &input[inputpos], len, 1);
+                                               break;
+                                       }
                                        case 'A': {
-                                               char pad = (type == 'a') ? '\0' : ' ';
+                                               /* A will strip any trailing whitespace */
+                                               char padn = '\0'; char pads = ' '; char padt = '\t'; char padc = '\r'; char padl = '\n';
                                                int len = inputlen - inputpos;  /* Remaining string */
 
                                                /* If size was given take minimum of len and size */
@@ -674,15 +693,45 @@ PHP_FUNCTION(unpack)
 
                                                size = len;
 
-                                               /* Remove padding chars from unpacked data */
+                                               /* Remove trailing white space and nulls chars from unpacked data */
                                                while (--len >= 0) {
-                                                       if (input[inputpos + len] != pad)
+                                                       if (input[inputpos + len] != padn
+                                                               && input[inputpos + len] != pads
+                                                               && input[inputpos + len] != padt
+                                                               && input[inputpos + len] != padc
+                                                               && input[inputpos + len] != padl
+                                                       )
                                                                break;
                                                }
 
                                                add_assoc_stringl(return_value, n, &input[inputpos], len + 1, 1);
                                                break;
                                        }
+                                       /* New option added for Z to remain in-line with the Perl implementation */
+                                       case 'Z': {
+                                               /* Z will strip everything after the first null character */
+                                               char pad = '\0';
+                                               int len = inputlen - inputpos;  /* Remaining string */
+
+                                               /* If size was given take minimum of len and size */
+                                               if ((size >= 0) && (len > size)) {
+                                                       len = size;
+                                               }
+
+                                               size = len;
+
+                                               /* Remove everything after the first null */
+                                               int s = 0;
+                                               while (s++ <= len) {
+                                                       if (input[inputpos + s] == pad)
+                                                               break;
+                                               }
+                                               len = s;
+
+                                               add_assoc_stringl(return_value, n, &input[inputpos], len, 1);
+                                               break;
+                                       }
+
                                        
                                        case 'h': 
                                        case 'H': {
diff --git a/ext/standard/tests/strings/bug61038.phpt b/ext/standard/tests/strings/bug61038.phpt
new file mode 100644 (file)
index 0000000..10fcef8
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+BugFix #61038
+--FILE--
+<?php
+       var_dump(unpack("Z4", pack("Z4", "foo")));
+       var_dump(unpack("a4", pack("a4", "foo")));
+       var_dump(unpack("A4", pack("A4", "foo")));
+       var_dump(unpack("a9", pack("a*", "foo\x00bar\x00 ")));
+       var_dump(unpack("A9", pack("a*", "foo\x00bar\x00 ")));
+       var_dump(unpack("Z9", pack("a*", "foo\x00bar\x00 ")));
+?>
+--EXPECTF--
+array(1) {
+  [1]=>
+  string(3) "foo"
+}
+array(1) {
+  [1]=>
+  string(4) "foo%c"
+}
+array(1) {
+  [1]=>
+  string(3) "foo"
+}
+array(1) {
+  [1]=>
+  string(9) "foo%cbar%c "
+}
+array(1) {
+  [1]=>
+  string(7) "foo%cbar"
+}
+array(1) {
+  [1]=>
+  string(3) "foo"
+}
+
index 43b2df1c0a12d2134383412fa6d7eac891d822a0..1ef97ccbaf8299ce5617e048fe31a5edb01054cc 100644 (file)
@@ -19,7 +19,7 @@ var_dump(unpack("I", pack("I", 65534), $extra_arg));
 
 echo "\n-- Testing unpack() function with invalid format character --\n";
 $extra_arg = 10;
-var_dump(unpack("Z", pack("I", 65534)));
+var_dump(unpack("G", pack("I", 65534)));
 ?>
 ===DONE===
 --EXPECTF--
@@ -37,6 +37,6 @@ NULL
 
 -- Testing unpack() function with invalid format character --
 
-Warning: unpack(): Invalid format type Z in %s on line %d
+Warning: unpack(): Invalid format type G in %s on line %d
 bool(false)
 ===DONE===