com php-src: Fixed bug #61038; "Z" and better behavior for unpack(): NEWS UPGRADING ext/standard/pack.c ext/standard/tests/strings/bug61038.phpt
ext/standard/tests/strings/unpack_error.phpt
| From: | Gustavo André dos Santos Lopes | Date: | Tue, 17 Apr 2012 11:31:36 +0000 |
| Subject: | com php-src: Fixed bug #61038; "Z" and better behavior for unpack(): NEWS UPGRADING ext/standard/pack.c ext/standard/tests/strings/bug61038.phpt ext/standard/tests/strings/unpack_error.phpt |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-68804@lists.php.net to get a copy of this message | ||
Commit: 4968fa644b0849321e1761e52b8db15dd46f9b75
Author: theanomaly..is@gmail.com <googleguy@googleguy-virtualbox.(none)> Tue, 17
Apr 2012 07:31:36 -0400
Committer: Gustavo André dos Santos Lopes <cataphract@php.net> Tue, 17 Apr 2012 21:09:04
+0100
Parents: 417e9cfe1b26249a49e5834d2ee7d495be1ad45e
Branches: master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=4968fa644b0849321e1761e52b8db15dd46f9b75
Log:
Fixed bug #61038; "Z" and better behavior for unpack()
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.
Bugs:
https://bugs.php.net/61038
Changed paths:
M NEWS
M UPGRADING
M ext/standard/pack.c
A ext/standard/tests/strings/bug61038.phpt
M ext/standard/tests/strings/unpack_error.phpt
Diff:
diff --git a/NEWS b/NEWS
index ecfaa93..ff5a31d 100644
--- 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,
diff --git a/UPGRADING b/UPGRADING
index d6d6e9b..27d01cb 100755
--- 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
diff --git a/ext/standard/pack.c b/ext/standard/pack.c
index faf0a2b...c2fa28f 100644
--- a/ext/standard/pack.c
+++ b/ext/standard/pack.c
@@ -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
index 0000000..10fcef8
--- /dev/null
+++ b/ext/standard/tests/strings/bug61038.phpt
@@ -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"
+}
+
diff --git a/ext/standard/tests/strings/unpack_error.phpt
b/ext/standard/tests/strings/unpack_error.phpt
index 43b2df1..1ef97cc 100644
--- a/ext/standard/tests/strings/unpack_error.phpt
+++ b/ext/standard/tests/strings/unpack_error.phpt
@@ -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===