summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--ext/standard/pack.c154
-rw-r--r--ext/standard/tests/strings/pack64.phpt115
-rw-r--r--ext/standard/tests/strings/pack64_32.phpt44
4 files changed, 311 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index 6207983a24..4f6ce962a9 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,7 @@ PHP NEWS
and passwords) (Tjerk)
. Fixed bug #67949 (DOMNodeList elements should be accessible through
array notation) (Florian)
+ . Implemented 64-bit format codes for pack() and unpack(). (Leigh)
- FPM:
. Fixed bug #65641 (PHP-FPM incorrectly defines the SCRIPT_NAME variable
diff --git a/ext/standard/pack.c b/ext/standard/pack.c
index 16a30668dc..9427db90a0 100644
--- a/ext/standard/pack.c
+++ b/ext/standard/pack.c
@@ -82,6 +82,13 @@ static int machine_endian_long_map[4];
static int big_endian_long_map[4];
static int little_endian_long_map[4];
+#if SIZEOF_LONG > 4
+/* Mappings of bytes from quads (64bit) for all endian environments */
+static int machine_endian_longlong_map[8];
+static int big_endian_longlong_map[8];
+static int little_endian_longlong_map[8];
+#endif
+
/* {{{ php_pack
*/
static void php_pack(zval **val, int size, int *map, char *output)
@@ -98,8 +105,8 @@ 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 Z, A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
+/* pack() idea stolen from Perl (implemented formats behave the same as there except J and P)
+ * Implemented formats are Z, A, a, h, H, c, C, s, S, i, I, l, L, n, N, q, Q, J, P, 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 */
@@ -199,6 +206,17 @@ PHP_FUNCTION(pack)
break;
/* Use as many args as specified */
+ case 'q':
+ case 'Q':
+ case 'J':
+ case 'P':
+#if SIZEOF_LONG < 8
+ efree(argv);
+ efree(formatcodes);
+ efree(formatargs);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "64-bit format codes are not available for 32-bit versions of PHP");
+ RETURN_FALSE;
+#endif
case 'c':
case 'C':
case 's':
@@ -283,6 +301,15 @@ PHP_FUNCTION(pack)
INC_OUTPUTPOS(arg,4) /* 32 bit per arg */
break;
+#if SIZEOF_LONG > 4
+ case 'q':
+ case 'Q':
+ case 'J':
+ case 'P':
+ INC_OUTPUTPOS(arg,8) /* 32 bit per arg */
+ break;
+#endif
+
case 'f':
INC_OUTPUTPOS(arg,sizeof(float))
break;
@@ -437,6 +464,27 @@ PHP_FUNCTION(pack)
break;
}
+#if SIZEOF_LONG > 4
+ case 'q':
+ case 'Q':
+ case 'J':
+ case 'P': {
+ int *map = machine_endian_longlong_map;
+
+ if (code == 'J') {
+ map = big_endian_longlong_map;
+ } else if (code == 'P') {
+ map = little_endian_longlong_map;
+ }
+
+ while (arg-- > 0) {
+ php_pack(argv[currentarg++], 8, map, &output[outputpos]);
+ outputpos += 8;
+ }
+ break;
+ }
+#endif
+
case 'f': {
float v;
@@ -522,7 +570,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 Z, 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, q, Q, J, P, f, d, x, X, @.
*/
/* {{{ proto array unpack(string format, string input)
Unpack binary string into named array elements according to format argument */
@@ -637,6 +685,20 @@ PHP_FUNCTION(unpack)
size = 4;
break;
+ /* Use 8 bytes of input */
+ case 'q':
+ case 'Q':
+ case 'J':
+ case 'P':
+#if SIZEOF_LONG > 4
+ size = 8;
+ break;
+#else
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "64-bit format codes are not available for 32-bit versions of PHP");
+ zval_dtor(return_value);
+ RETURN_FALSE;
+#endif
+
/* Use sizeof(float) bytes of input */
case 'f':
size = sizeof(float);
@@ -860,6 +922,38 @@ PHP_FUNCTION(unpack)
break;
}
+#if SIZEOF_LONG > 4
+ case 'q':
+ case 'Q':
+ case 'J':
+ case 'P': {
+ int issigned = 0;
+ int *map = machine_endian_longlong_map;
+ long v = 0;
+
+ if (type == 'q' || type == 'Q') {
+ issigned = input[inputpos + (machine_little_endian ? 7 : 0)] & 0x80;
+ } else if (type == 'J') {
+ issigned = input[inputpos] & 0x80;
+ map = big_endian_longlong_map;
+ } else if (type == 'P') {
+ issigned = input[inputpos + 7] & 0x80;
+ map = little_endian_longlong_map;
+ }
+
+ v = php_unpack(&input[inputpos], 8, issigned, map);
+
+ if (type == 'q') {
+ v = (signed long int) v;
+ } else {
+ v = (unsigned long int) v;
+ }
+
+ add_assoc_long(return_value, n, v);
+ break;
+ }
+#endif
+
case 'f': {
float v;
@@ -961,6 +1055,33 @@ PHP_MINIT_FUNCTION(pack)
little_endian_long_map[1] = 1;
little_endian_long_map[2] = 2;
little_endian_long_map[3] = 3;
+
+#if SIZEOF_LONG > 4
+ machine_endian_longlong_map[0] = 0;
+ machine_endian_longlong_map[1] = 1;
+ machine_endian_longlong_map[2] = 2;
+ machine_endian_longlong_map[3] = 3;
+ machine_endian_longlong_map[4] = 4;
+ machine_endian_longlong_map[5] = 5;
+ machine_endian_longlong_map[6] = 6;
+ machine_endian_longlong_map[7] = 7;
+ big_endian_longlong_map[0] = 7;
+ big_endian_longlong_map[1] = 6;
+ big_endian_longlong_map[2] = 5;
+ big_endian_longlong_map[3] = 4;
+ big_endian_longlong_map[4] = 3;
+ big_endian_longlong_map[5] = 2;
+ big_endian_longlong_map[6] = 1;
+ big_endian_longlong_map[7] = 0;
+ little_endian_longlong_map[0] = 0;
+ little_endian_longlong_map[1] = 1;
+ little_endian_longlong_map[2] = 2;
+ little_endian_longlong_map[3] = 3;
+ little_endian_longlong_map[4] = 4;
+ little_endian_longlong_map[5] = 5;
+ little_endian_longlong_map[6] = 6;
+ little_endian_longlong_map[7] = 7;
+#endif
}
else {
zval val;
@@ -993,6 +1114,33 @@ PHP_MINIT_FUNCTION(pack)
little_endian_long_map[1] = size - 2;
little_endian_long_map[2] = size - 3;
little_endian_long_map[3] = size - 4;
+
+#if SIZEOF_LONG > 4
+ machine_endian_longlong_map[0] = size - 8;
+ machine_endian_longlong_map[1] = size - 7;
+ machine_endian_longlong_map[2] = size - 6;
+ machine_endian_longlong_map[3] = size - 5;
+ machine_endian_longlong_map[0] = size - 4;
+ machine_endian_longlong_map[1] = size - 3;
+ machine_endian_longlong_map[2] = size - 2;
+ machine_endian_longlong_map[3] = size - 1;
+ big_endian_longlong_map[0] = size - 8;
+ big_endian_longlong_map[1] = size - 7;
+ big_endian_longlong_map[2] = size - 6;
+ big_endian_longlong_map[3] = size - 5;
+ big_endian_longlong_map[0] = size - 4;
+ big_endian_longlong_map[1] = size - 3;
+ big_endian_longlong_map[2] = size - 2;
+ big_endian_longlong_map[3] = size - 1;
+ little_endian_longlong_map[0] = size - 1;
+ little_endian_longlong_map[1] = size - 2;
+ little_endian_longlong_map[2] = size - 3;
+ little_endian_longlong_map[3] = size - 4;
+ little_endian_longlong_map[0] = size - 5;
+ little_endian_longlong_map[1] = size - 6;
+ little_endian_longlong_map[2] = size - 7;
+ little_endian_longlong_map[3] = size - 8;
+#endif
}
return SUCCESS;
diff --git a/ext/standard/tests/strings/pack64.phpt b/ext/standard/tests/strings/pack64.phpt
new file mode 100644
index 0000000000..9bc24928fe
--- /dev/null
+++ b/ext/standard/tests/strings/pack64.phpt
@@ -0,0 +1,115 @@
+--TEST--
+64bit pack()/unpack() tests
+--SKIPIF--
+<?php
+if (PHP_INT_SIZE < 8) {
+ die("skip 64bit test only");
+}
+?>
+--FILE--
+<?php
+print_r(unpack("Q", pack("Q", 0xfffffffffffe)));
+print_r(unpack("Q", pack("Q", 0)));
+print_r(unpack("Q", pack("Q", 0x8000000000000002)));
+print_r(unpack("Q", pack("Q", -1)));
+print_r(unpack("Q", pack("Q", 0x8000000000000000)));
+
+print_r(unpack("J", pack("J", 0xfffffffffffe)));
+print_r(unpack("J", pack("J", 0)));
+print_r(unpack("J", pack("J", 0x8000000000000002)));
+print_r(unpack("J", pack("J", -1)));
+print_r(unpack("J", pack("J", 0x8000000000000000)));
+
+print_r(unpack("P", pack("P", 0xfffffffffffe)));
+print_r(unpack("P", pack("P", 0)));
+print_r(unpack("P", pack("P", 0x8000000000000002)));
+print_r(unpack("P", pack("P", -1)));
+print_r(unpack("P", pack("P", 0x8000000000000000)));
+
+print_r(unpack("q", pack("q", 0xfffffffffffe)));
+print_r(unpack("q", pack("q", 0)));
+print_r(unpack("q", pack("q", 0x8000000000000002)));
+print_r(unpack("q", pack("q", -1)));
+print_r(unpack("q", pack("q", 0x8000000000000000)));
+?>
+--EXPECTF--
+Array
+(
+ [1] => 281474976710654
+)
+Array
+(
+ [1] => 0
+)
+Array
+(
+ [1] => -9223372036854775808
+)
+Array
+(
+ [1] => -1
+)
+Array
+(
+ [1] => -9223372036854775808
+)
+Array
+(
+ [1] => 281474976710654
+)
+Array
+(
+ [1] => 0
+)
+Array
+(
+ [1] => -9223372036854775808
+)
+Array
+(
+ [1] => -1
+)
+Array
+(
+ [1] => -9223372036854775808
+)
+Array
+(
+ [1] => 281474976710654
+)
+Array
+(
+ [1] => 0
+)
+Array
+(
+ [1] => -9223372036854775808
+)
+Array
+(
+ [1] => -1
+)
+Array
+(
+ [1] => -9223372036854775808
+)
+Array
+(
+ [1] => 281474976710654
+)
+Array
+(
+ [1] => 0
+)
+Array
+(
+ [1] => -9223372036854775808
+)
+Array
+(
+ [1] => -1
+)
+Array
+(
+ [1] => -9223372036854775808
+)
diff --git a/ext/standard/tests/strings/pack64_32.phpt b/ext/standard/tests/strings/pack64_32.phpt
new file mode 100644
index 0000000000..f52de63ca4
--- /dev/null
+++ b/ext/standard/tests/strings/pack64_32.phpt
@@ -0,0 +1,44 @@
+--TEST--
+64bit pack()/unpack() tests
+--SKIPIF--
+<?php
+if (PHP_INT_SIZE > 4) {
+ die("skip 32bit test only");
+}
+?>
+--FILE--
+<?php
+var_dump(pack("Q", 0));
+var_dump(pack("J", 0));
+var_dump(pack("P", 0));
+var_dump(pack("q", 0));
+
+var_dump(unpack("Q", ''));
+var_dump(unpack("J", ''));
+var_dump(unpack("P", ''));
+var_dump(unpack("q", ''));
+?>
+--EXPECTF--
+Warning: pack(): 64-bit format codes are not available for 32-bit versions of PHP in %s on line %d
+bool(false)
+
+Warning: pack(): 64-bit format codes are not available for 32-bit versions of PHP in %s on line %d
+bool(false)
+
+Warning: pack(): 64-bit format codes are not available for 32-bit versions of PHP in %s on line %d
+bool(false)
+
+Warning: pack(): 64-bit format codes are not available for 32-bit versions of PHP in %s on line %d
+bool(false)
+
+Warning: unpack(): 64-bit format codes are not available for 32-bit versions of PHP in %s on line %d
+bool(false)
+
+Warning: unpack(): 64-bit format codes are not available for 32-bit versions of PHP in %s on line %d
+bool(false)
+
+Warning: unpack(): 64-bit format codes are not available for 32-bit versions of PHP in %s on line %d
+bool(false)
+
+Warning: unpack(): 64-bit format codes are not available for 32-bit versions of PHP in %s on line %d
+bool(false)