Browse Source

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.
pull/60/head
theanomaly.is@gmail.com 14 years ago
committed by Gustavo André dos Santos Lopes
parent
commit
4968fa644b
  1. 4
      NEWS
  2. 6
      UPGRADING
  3. 63
      ext/standard/pack.c
  4. 37
      ext/standard/tests/strings/bug61038.phpt
  5. 4
      ext/standard/tests/strings/unpack_error.phpt

4
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,

6
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

63
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': {

37
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"
}

4
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===
Loading…
Cancel
Save