Browse Source

Merge branch 'PHP-5.6'

* PHP-5.6:
  Add 64 bit formats to pack() and unpack()
pull/873/merge
Tjerk Meesters 12 years ago
parent
commit
284358b317
  1. 154
      ext/standard/pack.c
  2. 115
      ext/standard/tests/strings/pack64.phpt
  3. 44
      ext/standard/tests/strings/pack64_32.phpt

154
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, size_t size, int *map, char *output)
@ -98,8 +105,8 @@ static void php_pack(zval *val, size_t 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 */
@ -198,6 +205,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':
@ -280,6 +298,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;
@ -430,6 +457,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': {
while (arg-- > 0) {
float v = (float) zval_get_double(&argv[currentarg++]);
@ -506,7 +554,7 @@ static zend_long php_unpack(char *data, size_t 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 */
@ -622,6 +670,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);
@ -845,6 +907,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;
@ -948,6 +1042,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;
@ -980,6 +1101,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;

115
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
)

44
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)
Loading…
Cancel
Save