diff options
Diffstat (limited to 'ext/standard/pack.c')
-rw-r--r-- | ext/standard/pack.c | 72 |
1 files changed, 64 insertions, 8 deletions
diff --git a/ext/standard/pack.c b/ext/standard/pack.c index d133e66d98..16a30668dc 100644 --- a/ext/standard/pack.c +++ b/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) { @@ -186,6 +187,12 @@ PHP_FUNCTION(pack) } convert_to_string_ex(argv[currentarg]); arg = Z_STRLEN_PP(argv[currentarg]); + if (code == 'Z') { + /* add one because Z is always NUL-terminated: + * pack("Z*", "aa") === "aa\0" + * pack("Z2", "aa") === "a\0" */ + arg++; + } } currentarg++; @@ -250,6 +257,7 @@ PHP_FUNCTION(pack) case 'a': case 'A': + case 'Z': case 'c': case 'C': case 'x': @@ -315,16 +323,19 @@ PHP_FUNCTION(pack) switch ((int) code) { case 'a': case 'A': - memset(&output[outputpos], (code == 'a') ? '\0' : ' ', arg); + case 'Z': { + int arg_cp = (code != 'Z') ? arg : MAX(0, arg - 1); + memset(&output[outputpos], (code == 'a' || code == 'Z') ? '\0' : ' ', arg); val = argv[currentarg++]; if (Z_ISREF_PP(val)) { SEPARATE_ZVAL(val); } convert_to_string_ex(val); memcpy(&output[outputpos], Z_STRVAL_PP(val), - (Z_STRLEN_PP(val) < arg) ? Z_STRLEN_PP(val) : arg); + (Z_STRLEN_PP(val) < arg_cp) ? Z_STRLEN_PP(val) : arg_cp); outputpos += arg; break; + } case 'h': case 'H': { @@ -511,7 +522,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 +597,7 @@ PHP_FUNCTION(unpack) case 'a': case 'A': + case 'Z': size = arg; arg = 1; break; @@ -662,9 +674,23 @@ PHP_FUNCTION(unpack) if ((inputpos + size) <= inputlen) { switch ((int) type) { - case 'a': + case 'a': { + /* a will not strip any trailing whitespace or null padding */ + 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 +700,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 s, + 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 */ + for (s=0 ; s < len ; s++) { + if (input[inputpos + s] == pad) + break; + } + len = s; + + add_assoc_stringl(return_value, n, &input[inputpos], len, 1); + break; + } + case 'h': case 'H': { |