From 8d5f2e4417683eb92bcd42674d2d5a30f7e942ee Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 16 Jan 2026 09:30:30 +0100 Subject: [PATCH] [RFC] Add support for endianness modifier in pack()/unpack() integer format codes --- NEWS | 2 + ext/standard/pack.c | 310 ++++++++++++++++-- .../tests/strings/pack_endian_modifiers.phpt | 242 ++++++++++++++ .../strings/pack_endian_modifiers_32.phpt | 79 +++++ 4 files changed, 603 insertions(+), 30 deletions(-) create mode 100644 ext/standard/tests/strings/pack_endian_modifiers.phpt create mode 100644 ext/standard/tests/strings/pack_endian_modifiers_32.phpt diff --git a/NEWS b/NEWS index bf00d8f663b90..aa7332973ff9c 100644 --- a/NEWS +++ b/NEWS @@ -101,6 +101,8 @@ PHP NEWS while COW violation flag is still set). (alexandre-daubois) . Invalid mode values now throw in array_filter() instead of being silently defaulted to 0. (Jorg Sowa) + . Add support for endianness modifier in pack()/unpack() integer format + codes. (alexandre-daubois) - Streams: . Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream diff --git a/ext/standard/pack.c b/ext/standard/pack.c index 55da64897a2e7..e9f6ea2bc945a 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -24,6 +24,7 @@ if ((a) < 0 || ((INT_MAX - outputpos)/((int)b)) < (a)) { \ efree(formatcodes); \ efree(formatargs); \ + efree(formatendian); \ zend_value_error("Type %c: integer overflow in format string", code); \ RETURN_THROWS(); \ } \ @@ -32,6 +33,7 @@ typedef enum { PHP_LITTLE_ENDIAN, PHP_BIG_ENDIAN, + PHP_NO_ENDIAN_MODIFIER, } php_pack_endianness; #ifdef WORDS_BIGENDIAN @@ -220,12 +222,27 @@ PHP_FUNCTION(pack) /* We have a maximum of format codes to deal with */ formatcodes = safe_emalloc(formatlen, sizeof(*formatcodes), 0); formatargs = safe_emalloc(formatlen, sizeof(*formatargs), 0); + php_pack_endianness *formatendian = safe_emalloc(formatlen, sizeof(*formatendian), 0); currentarg = 0; /* Preprocess format into formatcodes and formatargs */ for (i = 0; i < formatlen; formatcount++) { char code = format[i++]; int arg = 1; + php_pack_endianness endian = PHP_NO_ENDIAN_MODIFIER; + + /* Handle endianness modifier if any */ + if (i < formatlen) { + char c = format[i]; + + if (c == '<') { + endian = PHP_LITTLE_ENDIAN; + i++; + } else if (c == '>') { + endian = PHP_BIG_ENDIAN; + i++; + } + } /* Handle format arguments if any */ if (i < formatlen) { @@ -250,6 +267,13 @@ PHP_FUNCTION(pack) case 'x': case 'X': case '@': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + efree(formatcodes); + efree(formatargs); + efree(formatendian); + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } if (arg < 0) { php_error_docref(NULL, E_WARNING, "Type %c: '*' ignored", code); arg = 1; @@ -262,9 +286,17 @@ PHP_FUNCTION(pack) case 'Z': case 'h': case 'H': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + efree(formatcodes); + efree(formatargs); + efree(formatendian); + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } if (currentarg >= num_args) { efree(formatcodes); efree(formatargs); + efree(formatendian); zend_value_error("Type %c: not enough arguments", code); RETURN_THROWS(); } @@ -273,6 +305,7 @@ PHP_FUNCTION(pack) if (!try_convert_to_string(&argv[currentarg])) { efree(formatcodes); efree(formatargs); + efree(formatendian); RETURN_THROWS(); } @@ -288,35 +321,121 @@ PHP_FUNCTION(pack) currentarg++; break; - /* Use as many args as specified */ - case 'q': - case 'Q': + /* 64-bit codes with explicit endianness, endianness modifiers not allowed */ case 'J': case 'P': #if SIZEOF_ZEND_LONG < 8 + efree(formatcodes); + efree(formatargs); + efree(formatendian); + zend_value_error("64-bit format codes are not available for 32-bit versions of PHP"); + RETURN_THROWS(); +#else + if (endian != PHP_NO_ENDIAN_MODIFIER) { efree(formatcodes); efree(formatargs); - zend_value_error("64-bit format codes are not available for 32-bit versions of PHP"); + efree(formatendian); + zend_value_error("Endianness modifier not allowed for this format code"); RETURN_THROWS(); + } + if (arg < 0) { + arg = num_args - currentarg; + } + if (currentarg > INT_MAX - arg) { + goto too_few_args; + } + currentarg += arg; + + if (currentarg > num_args) { + goto too_few_args; + } + break; #endif - case 'c': - case 'C': - case 's': - case 'S': - case 'i': - case 'I': - case 'l': - case 'L': + + /* 64-bit codes that support endianness modifiers */ + case 'q': + case 'Q': +#if SIZEOF_ZEND_LONG < 8 + efree(formatcodes); + efree(formatargs); + efree(formatendian); + zend_value_error("64-bit format codes are not available for 32-bit versions of PHP"); + RETURN_THROWS(); +#else + if (arg < 0) { + arg = num_args - currentarg; + } + if (currentarg > INT_MAX - arg) { + goto too_few_args; + } + currentarg += arg; + + if (currentarg > num_args) { + goto too_few_args; + } + break; +#endif + + /* Codes with explicit endianness, endianness modifiers not allowed */ case 'n': case 'N': case 'v': case 'V': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + efree(formatcodes); + efree(formatargs); + efree(formatendian); + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } + if (arg < 0) { + arg = num_args - currentarg; + } + if (currentarg > INT_MAX - arg) { + goto too_few_args; + } + currentarg += arg; + + if (currentarg > num_args) { + goto too_few_args; + } + break; + + /* Codes that support endianness modifiers */ + case 's': + case 'S': + case 'l': + case 'L': + if (arg < 0) { + arg = num_args - currentarg; + } + if (currentarg > INT_MAX - arg) { + goto too_few_args; + } + currentarg += arg; + + if (currentarg > num_args) { + goto too_few_args; + } + break; + + case 'c': + case 'C': + case 'i': + case 'I': case 'f': /* float */ case 'g': /* little endian float */ case 'G': /* big endian float */ case 'd': /* double */ case 'e': /* little endian double */ case 'E': /* big endian double */ + if (endian != PHP_NO_ENDIAN_MODIFIER) { + efree(formatcodes); + efree(formatargs); + efree(formatendian); + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } if (arg < 0) { arg = num_args - currentarg; } @@ -329,6 +448,7 @@ PHP_FUNCTION(pack) too_few_args: efree(formatcodes); efree(formatargs); + efree(formatendian); zend_value_error("Type %c: too few arguments", code); RETURN_THROWS(); } @@ -337,12 +457,14 @@ PHP_FUNCTION(pack) default: efree(formatcodes); efree(formatargs); + efree(formatendian); zend_value_error("Type %c: unknown format code", code); RETURN_THROWS(); } formatcodes[formatcount] = code; formatargs[formatcount] = arg; + formatendian[formatcount] = endian; } if (currentarg < num_args) { @@ -509,12 +631,16 @@ PHP_FUNCTION(pack) case 'S': case 'n': case 'v': { - php_pack_endianness endianness = PHP_MACHINE_ENDIAN; + php_pack_endianness endianness; if (code == 'n') { endianness = PHP_BIG_ENDIAN; } else if (code == 'v') { endianness = PHP_LITTLE_ENDIAN; + } else if (formatendian[i] != PHP_NO_ENDIAN_MODIFIER) { + endianness = formatendian[i]; + } else { + endianness = PHP_MACHINE_ENDIAN; } while (arg-- > 0) { @@ -536,12 +662,16 @@ PHP_FUNCTION(pack) case 'L': case 'N': case 'V': { - php_pack_endianness endianness = PHP_MACHINE_ENDIAN; + php_pack_endianness endianness; if (code == 'N') { endianness = PHP_BIG_ENDIAN; } else if (code == 'V') { endianness = PHP_LITTLE_ENDIAN; + } else if (formatendian[i] != PHP_NO_ENDIAN_MODIFIER) { + endianness = formatendian[i]; + } else { + endianness = PHP_MACHINE_ENDIAN; } while (arg-- > 0) { @@ -556,12 +686,16 @@ PHP_FUNCTION(pack) case 'Q': case 'J': case 'P': { - php_pack_endianness endianness = PHP_MACHINE_ENDIAN; + php_pack_endianness endianness; if (code == 'J') { endianness = PHP_BIG_ENDIAN; } else if (code == 'P') { endianness = PHP_LITTLE_ENDIAN; + } else if (formatendian[i] != PHP_NO_ENDIAN_MODIFIER) { + endianness = formatendian[i]; + } else { + endianness = PHP_MACHINE_ENDIAN; } while (arg-- > 0) { @@ -654,6 +788,7 @@ PHP_FUNCTION(pack) efree(formatcodes); efree(formatargs); + efree(formatendian); ZSTR_VAL(output)[outputpos] = '\0'; ZSTR_LEN(output) = outputpos; RETURN_NEW_STR(output); @@ -712,6 +847,21 @@ PHP_FUNCTION(unpack) char *name; int namelen; int size = 0; + php_pack_endianness endian = PHP_NO_ENDIAN_MODIFIER; + + if (formatlen > 0) { + char c = *format; + + if (c == '<') { + endian = PHP_LITTLE_ENDIAN; + format++; + formatlen--; + } else if (c == '>') { + endian = PHP_BIG_ENDIAN; + format++; + formatlen--; + } + } /* Handle format arguments if any */ if (formatlen > 0) { @@ -757,6 +907,10 @@ PHP_FUNCTION(unpack) switch (type) { /* Never use any input */ case 'X': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = -1; if (repetitions < 0) { php_error_docref(NULL, E_WARNING, "Type %c: '*' ignored", type); @@ -765,18 +919,30 @@ PHP_FUNCTION(unpack) break; case '@': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = 0; break; case 'a': case 'A': case 'Z': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = repetitions; repetitions = 1; break; case 'h': case 'H': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = (repetitions > 0) ? ((unsigned int) repetitions + 1) / 2 : repetitions; repetitions = 1; break; @@ -785,37 +951,74 @@ PHP_FUNCTION(unpack) case 'c': case 'C': case 'x': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = 1; break; - /* Use 2 bytes of input */ + /* Use 2 bytes of input, endianness modifiers allowed */ case 's': case 'S': + size = 2; + break; + + /* Use 2 bytes of input with inherent endianness */ case 'n': case 'v': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = 2; break; /* Use sizeof(int) bytes of input */ case 'i': case 'I': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = sizeof(int); break; - /* Use 4 bytes of input */ + /* Use 4 bytes of input, endianness modifiers allowed */ case 'l': case 'L': + size = 4; + break; + + /* Use 4 bytes of input with inherent endianness */ case 'N': case 'V': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = 4; break; - /* Use 8 bytes of input */ + /* Use 8 bytes of input, endianness modifiers allowed */ case 'q': case 'Q': +#if SIZEOF_ZEND_LONG > 4 + size = 8; + break; +#else + zend_value_error("64-bit format codes are not available for 32-bit versions of PHP"); + RETURN_THROWS(); +#endif + + /* Use 8 bytes of input with inherent endianness */ case 'J': case 'P': #if SIZEOF_ZEND_LONG > 4 + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = 8; break; #else @@ -827,6 +1030,10 @@ PHP_FUNCTION(unpack) case 'f': case 'g': case 'G': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = sizeof(float); break; @@ -834,6 +1041,10 @@ PHP_FUNCTION(unpack) case 'd': case 'e': case 'E': + if (endian != PHP_NO_ENDIAN_MODIFIER) { + zend_value_error("Endianness modifier not allowed for this format code"); + RETURN_THROWS(); + } size = sizeof(double); break; @@ -998,17 +1209,30 @@ PHP_FUNCTION(unpack) break; } - case 's': /* signed machine endian */ - case 'S': /* unsigned machine endian */ + case 's': /* signed, machine endian or explicit */ + case 'S': /* unsigned, machine endian or explicit */ case 'n': /* unsigned big endian */ case 'v': { /* unsigned little endian */ zend_long v = 0; uint16_t x = *((unaligned_uint16_t*) &input[inputpos]); + bool need_swap = false; + if (type == 'n') { + need_swap = MACHINE_LITTLE_ENDIAN; + } else if (type == 'v') { + need_swap = !MACHINE_LITTLE_ENDIAN; + } else if (endian == PHP_LITTLE_ENDIAN) { + need_swap = !MACHINE_LITTLE_ENDIAN; + } else if (endian == PHP_BIG_ENDIAN) { + need_swap = MACHINE_LITTLE_ENDIAN; + } + + if (need_swap) { + x = php_pack_reverse_int16(x); + } + if (type == 's') { v = (int16_t) x; - } else if ((type == 'n' && MACHINE_LITTLE_ENDIAN) || (type == 'v' && !MACHINE_LITTLE_ENDIAN)) { - v = php_pack_reverse_int16(x); } else { v = x; } @@ -1032,17 +1256,30 @@ PHP_FUNCTION(unpack) break; } - case 'l': /* signed machine endian */ - case 'L': /* unsigned machine endian */ + case 'l': /* signed, machine endian or explicit */ + case 'L': /* unsigned, machine endian or explicit */ case 'N': /* unsigned big endian */ case 'V': { /* unsigned little endian */ zend_long v = 0; uint32_t x = *((unaligned_uint32_t*) &input[inputpos]); + bool need_swap = false; + if (type == 'N') { + need_swap = MACHINE_LITTLE_ENDIAN; + } else if (type == 'V') { + need_swap = !MACHINE_LITTLE_ENDIAN; + } else if (endian == PHP_LITTLE_ENDIAN) { + need_swap = !MACHINE_LITTLE_ENDIAN; + } else if (endian == PHP_BIG_ENDIAN) { + need_swap = MACHINE_LITTLE_ENDIAN; + } + + if (need_swap) { + x = php_pack_reverse_int32(x); + } + if (type == 'l') { v = (int32_t) x; - } else if ((type == 'N' && MACHINE_LITTLE_ENDIAN) || (type == 'V' && !MACHINE_LITTLE_ENDIAN)) { - v = php_pack_reverse_int32(x); } else { v = x; } @@ -1052,17 +1289,30 @@ PHP_FUNCTION(unpack) } #if SIZEOF_ZEND_LONG > 4 - case 'q': /* signed machine endian */ - case 'Q': /* unsigned machine endian */ + case 'q': /* signed, machine endian or explicit */ + case 'Q': /* unsigned, machine endian or explicit */ case 'J': /* unsigned big endian */ case 'P': { /* unsigned little endian */ zend_long v = 0; uint64_t x = *((unaligned_uint64_t*) &input[inputpos]); + bool need_swap = false; + if (type == 'J') { + need_swap = MACHINE_LITTLE_ENDIAN; + } else if (type == 'P') { + need_swap = !MACHINE_LITTLE_ENDIAN; + } else if (endian == PHP_LITTLE_ENDIAN) { + need_swap = !MACHINE_LITTLE_ENDIAN; + } else if (endian == PHP_BIG_ENDIAN) { + need_swap = MACHINE_LITTLE_ENDIAN; + } + + if (need_swap) { + x = php_pack_reverse_int64(x); + } + if (type == 'q') { v = (int64_t) x; - } else if ((type == 'J' && MACHINE_LITTLE_ENDIAN) || (type == 'P' && !MACHINE_LITTLE_ENDIAN)) { - v = php_pack_reverse_int64(x); } else { v = x; } diff --git a/ext/standard/tests/strings/pack_endian_modifiers.phpt b/ext/standard/tests/strings/pack_endian_modifiers.phpt new file mode 100644 index 0000000000000..53b2a1f2d60a3 --- /dev/null +++ b/ext/standard/tests/strings/pack_endian_modifiers.phpt @@ -0,0 +1,242 @@ +--TEST-- +pack()/unpack() endianness modifiers +--SKIPIF-- + +--FILE-- +", 0x0102))); +var_dump(bin2hex(pack("S>", 0x0102))); + +var_dump(pack("s<", 0x0102) === pack("v", 0x0102)); +var_dump(pack("S<", 0x0102) === pack("v", 0x0102)); + +var_dump(pack("s>", 0x0102) === pack("n", 0x0102)); +var_dump(pack("S>", 0x0102) === pack("n", 0x0102)); + +var_dump(bin2hex(pack("l<", 0x01020304))); +var_dump(bin2hex(pack("L<", 0x01020304))); + +var_dump(bin2hex(pack("l>", 0x01020304))); +var_dump(bin2hex(pack("L>", 0x01020304))); + +var_dump(pack("l<", 0x01020304) === pack("V", 0x01020304)); +var_dump(pack("L<", 0x01020304) === pack("V", 0x01020304)); + +var_dump(pack("l>", 0x01020304) === pack("N", 0x01020304)); +var_dump(pack("L>", 0x01020304) === pack("N", 0x01020304)); + +var_dump(bin2hex(pack("q<", 0x0102030405060708))); +var_dump(bin2hex(pack("Q<", 0x0102030405060708))); + +var_dump(bin2hex(pack("q>", 0x0102030405060708))); +var_dump(bin2hex(pack("Q>", 0x0102030405060708))); + +var_dump(pack("q<", 0x0102030405060708) === pack("P", 0x0102030405060708)); +var_dump(pack("Q<", 0x0102030405060708) === pack("P", 0x0102030405060708)); + +var_dump(pack("q>", 0x0102030405060708) === pack("J", 0x0102030405060708)); +var_dump(pack("Q>", 0x0102030405060708) === pack("J", 0x0102030405060708)); + +print_r(unpack("s<", "\x02\x01")); +print_r(unpack("S<", "\x02\x01")); + +print_r(unpack("s>", "\x01\x02")); +print_r(unpack("S>", "\x01\x02")); + +print_r(unpack("s<", "\xfe\xff")); // -2 in little-endian +print_r(unpack("s>", "\xff\xfe")); // -2 in big-endian + +print_r(unpack("l<", "\x04\x03\x02\x01")); +print_r(unpack("L<", "\x04\x03\x02\x01")); + +print_r(unpack("l>", "\x01\x02\x03\x04")); +print_r(unpack("L>", "\x01\x02\x03\x04")); + +print_r(unpack("l<", "\xfe\xff\xff\xff")); // -2 in little-endian +print_r(unpack("l>", "\xff\xff\xff\xfe")); // -2 in big-endian + +print_r(unpack("q<", "\x08\x07\x06\x05\x04\x03\x02\x01")); +print_r(unpack("Q<", "\x08\x07\x06\x05\x04\x03\x02\x01")); + +print_r(unpack("q>", "\x01\x02\x03\x04\x05\x06\x07\x08")); +print_r(unpack("Q>", "\x01\x02\x03\x04\x05\x06\x07\x08")); + +print_r(unpack("q<", "\xfe\xff\xff\xff\xff\xff\xff\xff")); // -2 in little-endian +print_r(unpack("q>", "\xff\xff\xff\xff\xff\xff\xff\xfe")); // -2 in big-endian + +var_dump(bin2hex(pack("s<2", 0x0102, 0x0304))); +var_dump(bin2hex(pack("s>2", 0x0102, 0x0304))); + +print_r(unpack("s<2", "\x02\x01\x04\x03")); +print_r(unpack("s>2", "\x01\x02\x03\x04")); + +print_r(unpack("scount", "\x02\x01\x00\x00\x00\x05")); + +// modifiers on codes with inherent endianness +$error_formats = ['n<', 'v>', 'N<', 'V>', 'J<', 'P>']; +foreach ($error_formats as $fmt) { + try { + pack($fmt, 1); + echo "FAIL: Expected ValueError for pack('$fmt', 1)\n"; + } catch (ValueError $e) { + echo "pack('$fmt'): " . $e->getMessage() . "\n"; + } +} + +$unsupported_formats = ['c<', 'C>', 'a<', 'A>', 'i<', 'I>', 'f<', 'd>']; +foreach ($unsupported_formats as $fmt) { + try { + pack($fmt, 1); + echo "FAIL: Expected ValueError for pack('$fmt', 1)\n"; + } catch (ValueError $e) { + echo "pack('$fmt'): " . $e->getMessage() . "\n"; + } +} + +foreach (['n<', 'v>', 'N<', 'V>'] as $fmt) { + try { + unpack($fmt, "\x00\x00\x00\x00"); + echo "FAIL: Expected ValueError for unpack('$fmt', ...)\n"; + } catch (ValueError $e) { + echo "unpack('$fmt'): " . $e->getMessage() . "\n"; + } +} +?> +--EXPECT-- +string(4) "0201" +string(4) "0201" +string(4) "0102" +string(4) "0102" +bool(true) +bool(true) +bool(true) +bool(true) +string(8) "04030201" +string(8) "04030201" +string(8) "01020304" +string(8) "01020304" +bool(true) +bool(true) +bool(true) +bool(true) +string(16) "0807060504030201" +string(16) "0807060504030201" +string(16) "0102030405060708" +string(16) "0102030405060708" +bool(true) +bool(true) +bool(true) +bool(true) +Array +( + [1] => 258 +) +Array +( + [1] => 258 +) +Array +( + [1] => 258 +) +Array +( + [1] => 258 +) +Array +( + [1] => -2 +) +Array +( + [1] => -2 +) +Array +( + [1] => 16909060 +) +Array +( + [1] => 16909060 +) +Array +( + [1] => 16909060 +) +Array +( + [1] => 16909060 +) +Array +( + [1] => -2 +) +Array +( + [1] => -2 +) +Array +( + [1] => 72623859790382856 +) +Array +( + [1] => 72623859790382856 +) +Array +( + [1] => 72623859790382856 +) +Array +( + [1] => 72623859790382856 +) +Array +( + [1] => -2 +) +Array +( + [1] => -2 +) +string(8) "02010403" +string(8) "01020304" +Array +( + [1] => 258 + [2] => 772 +) +Array +( + [1] => 258 + [2] => 772 +) +Array +( + [value] => 258 + [count] => 5 +) +pack('n<'): Endianness modifier not allowed for this format code +pack('v>'): Endianness modifier not allowed for this format code +pack('N<'): Endianness modifier not allowed for this format code +pack('V>'): Endianness modifier not allowed for this format code +pack('J<'): Endianness modifier not allowed for this format code +pack('P>'): Endianness modifier not allowed for this format code +pack('c<'): Endianness modifier not allowed for this format code +pack('C>'): Endianness modifier not allowed for this format code +pack('a<'): Endianness modifier not allowed for this format code +pack('A>'): Endianness modifier not allowed for this format code +pack('i<'): Endianness modifier not allowed for this format code +pack('I>'): Endianness modifier not allowed for this format code +pack('f<'): Endianness modifier not allowed for this format code +pack('d>'): Endianness modifier not allowed for this format code +unpack('n<'): Endianness modifier not allowed for this format code +unpack('v>'): Endianness modifier not allowed for this format code +unpack('N<'): Endianness modifier not allowed for this format code +unpack('V>'): Endianness modifier not allowed for this format code diff --git a/ext/standard/tests/strings/pack_endian_modifiers_32.phpt b/ext/standard/tests/strings/pack_endian_modifiers_32.phpt new file mode 100644 index 0000000000000..63d433ceb1cc5 --- /dev/null +++ b/ext/standard/tests/strings/pack_endian_modifiers_32.phpt @@ -0,0 +1,79 @@ +--TEST-- +pack()/unpack() endianness modifiers on 32-bit systems +--SKIPIF-- + 4) die("skip 32bit test only"); +?> +--FILE-- +", 0x0102))); +var_dump(bin2hex(pack("S>", 0x0102))); + +print_r(unpack("s<", "\x02\x01")); +print_r(unpack("S>", "\x01\x02")); + +var_dump(bin2hex(pack("l<", 0x01020304))); +var_dump(bin2hex(pack("L<", 0x01020304))); +var_dump(bin2hex(pack("l>", 0x01020304))); +var_dump(bin2hex(pack("L>", 0x01020304))); + +print_r(unpack("l<", "\x04\x03\x02\x01")); +print_r(unpack("L>", "\x01\x02\x03\x04")); + +$formats = ['q<', 'q>', 'Q<', 'Q>']; +foreach ($formats as $fmt) { + try { + pack($fmt, 0); + echo "FAIL: Expected ValueError for pack('$fmt', 0)\n"; + } catch (ValueError $e) { + echo "pack('$fmt'): " . $e->getMessage() . "\n"; + } +} + +foreach ($formats as $fmt) { + try { + unpack($fmt, "\x00\x00\x00\x00\x00\x00\x00\x00"); + echo "FAIL: Expected ValueError for unpack('$fmt', ...)\n"; + } catch (ValueError $e) { + echo "unpack('$fmt'): " . $e->getMessage() . "\n"; + } +} +?> +--EXPECT-- +string(4) "0201" +string(4) "0201" +string(4) "0102" +string(4) "0102" +Array +( + [1] => 258 +) +Array +( + [1] => 258 +) + +string(8) "04030201" +string(8) "04030201" +string(8) "01020304" +string(8) "01020304" +Array +( + [1] => 16909060 +) +Array +( + [1] => 16909060 +) + +pack('q<'): 64-bit format codes are not available for 32-bit versions of PHP +pack('q>'): 64-bit format codes are not available for 32-bit versions of PHP +pack('Q<'): 64-bit format codes are not available for 32-bit versions of PHP +pack('Q>'): 64-bit format codes are not available for 32-bit versions of PHP +unpack('q<'): 64-bit format codes are not available for 32-bit versions of PHP +unpack('q>'): 64-bit format codes are not available for 32-bit versions of PHP +unpack('Q<'): 64-bit format codes are not available for 32-bit versions of PHP +unpack('Q>'): 64-bit format codes are not available for 32-bit versions of PHP