Skip to content

Commit dbc5b42

Browse files
committed
pack() with new "Z" more in line with Perl.
Made pack() with "Z" force NUL termination, even if it mean truncating input to less than the number of characters specified and if the number of characters is "*", the output will be one byte larger than the input. Improved tests.
1 parent 4968fa6 commit dbc5b42

File tree

4 files changed

+73
-24
lines changed

4 files changed

+73
-24
lines changed

ext/standard/pack.c

+10-2
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@ PHP_FUNCTION(pack)
187187
}
188188
convert_to_string_ex(argv[currentarg]);
189189
arg = Z_STRLEN_PP(argv[currentarg]);
190+
if (code == 'Z') {
191+
/* add one because Z is always NUL-terminated:
192+
* pack("Z*", "aa") === "aa\0"
193+
* pack("Z2", "aa") === "a\0" */
194+
arg++;
195+
}
190196
}
191197

192198
currentarg++;
@@ -317,17 +323,19 @@ PHP_FUNCTION(pack)
317323
switch ((int) code) {
318324
case 'a':
319325
case 'A':
320-
case 'Z':
326+
case 'Z': {
327+
int arg_cp = (code != 'Z') ? arg : MAX(0, arg - 1);
321328
memset(&output[outputpos], (code == 'a' || code == 'Z') ? '\0' : ' ', arg);
322329
val = argv[currentarg++];
323330
if (Z_ISREF_PP(val)) {
324331
SEPARATE_ZVAL(val);
325332
}
326333
convert_to_string_ex(val);
327334
memcpy(&output[outputpos], Z_STRVAL_PP(val),
328-
(Z_STRLEN_PP(val) < arg) ? Z_STRLEN_PP(val) : arg);
335+
(Z_STRLEN_PP(val) < arg_cp) ? Z_STRLEN_PP(val) : arg_cp);
329336
outputpos += arg;
330337
break;
338+
}
331339

332340
case 'h':
333341
case 'H': {
+11-22
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,26 @@
11
--TEST--
2-
BugFix #61038
2+
Bug #61038: unpack("a5", "str\0\0") does not work as expected
33
--FILE--
44
<?php
5-
var_dump(unpack("Z4", pack("Z4", "foo")));
6-
var_dump(unpack("a4", pack("a4", "foo")));
7-
var_dump(unpack("A4", pack("A4", "foo")));
8-
var_dump(unpack("a9", pack("a*", "foo\x00bar\x00 ")));
9-
var_dump(unpack("A9", pack("a*", "foo\x00bar\x00 ")));
10-
var_dump(unpack("Z9", pack("a*", "foo\x00bar\x00 ")));
5+
var_dump(unpack("a4", "str\0\0"));
6+
var_dump(unpack("a5", "str\0\0"));
7+
var_dump(unpack("a6", "str\0\0"));
8+
var_dump(unpack("a*", "str\0\0"));
119
?>
1210
--EXPECTF--
1311
array(1) {
1412
[1]=>
15-
string(3) "foo"
13+
string(4) "str%c"
1614
}
1715
array(1) {
1816
[1]=>
19-
string(4) "foo%c"
20-
}
21-
array(1) {
22-
[1]=>
23-
string(3) "foo"
24-
}
25-
array(1) {
26-
[1]=>
27-
string(9) "foo%cbar%c "
28-
}
29-
array(1) {
30-
[1]=>
31-
string(7) "foo%cbar"
17+
string(5) "str%c%c"
3218
}
19+
20+
Warning: unpack(): Type a: not enough input, need 6, have 5 in %s on line %d
21+
bool(false)
3322
array(1) {
3423
[1]=>
35-
string(3) "foo"
24+
string(5) "str%c%c"
3625
}
3726

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
pack()/unpack(): "A" modifier
3+
--FILE--
4+
<?php
5+
var_dump(
6+
pack("A5", "foo "),
7+
pack("A4", "fooo"),
8+
pack("A4", "foo"),
9+
unpack("A*", "foo\0\rbar\0 \t\r\n"),
10+
unpack("A4", "foo\0\rbar\0 \t\r\n")
11+
);
12+
?>
13+
--EXPECTF--
14+
string(5) "foo "
15+
string(4) "fooo"
16+
string(4) "foo "
17+
array(1) {
18+
[1]=>
19+
string(8) "foo%c%cbar"
20+
}
21+
array(1) {
22+
[1]=>
23+
string(3) "foo"
24+
}
25+
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
pack()/unpack(): "Z" format
3+
--FILE--
4+
<?php
5+
var_dump(
6+
pack("Z0", "f"),
7+
pack("Z5", "foo\0"),
8+
pack("Z4", "fooo"),
9+
pack("Z4", "foo"),
10+
pack("Z*", "foo"),
11+
unpack("Z*", "foo\0\rbar\0 \t\r\n"),
12+
unpack("Z9", "foo\0\rbar\0 \t\r\n")
13+
);
14+
--EXPECTF--
15+
string(0) ""
16+
string(5) "foo%c%c"
17+
string(4) "foo%c"
18+
string(4) "foo%c"
19+
string(4) "foo%c"
20+
array(1) {
21+
[1]=>
22+
string(3) "foo"
23+
}
24+
array(1) {
25+
[1]=>
26+
string(3) "foo"
27+
}

0 commit comments

Comments
 (0)