PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/standard - pack.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 332 440 75.5 %
Date: 2014-08-04 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 5                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2014 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Author: Chris Schneider <cschneid@relog.ch>                          |
      16             :    +----------------------------------------------------------------------+
      17             :  */
      18             : /* $Id$ */
      19             : 
      20             : #include "php.h"
      21             : 
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <errno.h>
      25             : #include <sys/types.h>
      26             : #include <sys/stat.h>
      27             : #include <fcntl.h>
      28             : #ifdef PHP_WIN32
      29             : #define O_RDONLY _O_RDONLY
      30             : #include "win32/param.h"
      31             : #elif defined(NETWARE)
      32             : #ifdef USE_WINSOCK
      33             : #include <novsock2.h>
      34             : #else
      35             : #include <sys/socket.h>
      36             : #endif
      37             : #include <sys/param.h>
      38             : #else
      39             : #include <sys/param.h>
      40             : #endif
      41             : #include "ext/standard/head.h"
      42             : #include "php_string.h"
      43             : #include "pack.h"
      44             : #if HAVE_PWD_H
      45             : #ifdef PHP_WIN32
      46             : #include "win32/pwd.h"
      47             : #else
      48             : #include <pwd.h>
      49             : #endif
      50             : #endif
      51             : #include "fsock.h"
      52             : #if HAVE_NETINET_IN_H
      53             : #include <netinet/in.h>
      54             : #endif
      55             : 
      56             : #define INC_OUTPUTPOS(a,b) \
      57             :         if ((a) < 0 || ((INT_MAX - outputpos)/((int)b)) < (a)) { \
      58             :                 efree(argv);    \
      59             :                 efree(formatcodes);     \
      60             :                 efree(formatargs);      \
      61             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow in format string", code); \
      62             :                 RETURN_FALSE; \
      63             :         } \
      64             :         outputpos += (a)*(b);
      65             : 
      66             : /* Whether machine is little endian */
      67             : char machine_little_endian;
      68             : 
      69             : /* Mapping of byte from char (8bit) to long for machine endian */
      70             : static int byte_map[1];
      71             : 
      72             : /* Mappings of bytes from int (machine dependent) to int for machine endian */
      73             : static int int_map[sizeof(int)];
      74             : 
      75             : /* Mappings of bytes from shorts (16bit) for all endian environments */
      76             : static int machine_endian_short_map[2];
      77             : static int big_endian_short_map[2];
      78             : static int little_endian_short_map[2];
      79             : 
      80             : /* Mappings of bytes from longs (32bit) for all endian environments */
      81             : static int machine_endian_long_map[4];
      82             : static int big_endian_long_map[4];
      83             : static int little_endian_long_map[4];
      84             : 
      85             : /* {{{ php_pack
      86             :  */
      87      504622 : static void php_pack(zval **val, int size, int *map, char *output)
      88             : {
      89             :         int i;
      90             :         char *v;
      91             : 
      92      504622 :         convert_to_long_ex(val);
      93      504622 :         v = (char *) &Z_LVAL_PP(val);
      94             : 
      95     1041478 :         for (i = 0; i < size; i++) {
      96      536856 :                 *output++ = v[map[i]];
      97             :         }
      98      504622 : }
      99             : /* }}} */
     100             : 
     101             : /* pack() idea stolen from Perl (implemented formats behave the same as there)
     102             :  * Implemented formats are Z, A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
     103             :  */
     104             : /* {{{ proto string pack(string format, mixed arg1 [, mixed arg2 [, mixed ...]])
     105             :    Takes one or more arguments and packs them into a binary string according to the format argument */
     106      153377 : PHP_FUNCTION(pack)
     107             : {
     108      153377 :         zval ***argv = NULL;
     109             :         int num_args, i;
     110             :         int currentarg;
     111             :         char *format;
     112             :         int formatlen;
     113             :         char *formatcodes;
     114             :         int *formatargs;
     115      153377 :         int formatcount = 0;
     116      153377 :         int outputpos = 0, outputsize = 0;
     117             :         char *output;
     118             : 
     119      153377 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &argv, &num_args) == FAILURE) {
     120           0 :                 return;
     121             :         }
     122             : 
     123      306754 :         if (Z_ISREF_PP(argv[0])) {
     124           0 :                 SEPARATE_ZVAL(argv[0]);
     125             :         }
     126      153377 :         convert_to_string_ex(argv[0]);
     127             : 
     128      153377 :         format = Z_STRVAL_PP(argv[0]);
     129      153377 :         formatlen = Z_STRLEN_PP(argv[0]);
     130             : 
     131             :         /* We have a maximum of <formatlen> format codes to deal with */
     132      153377 :         formatcodes = safe_emalloc(formatlen, sizeof(*formatcodes), 0);
     133      153377 :         formatargs = safe_emalloc(formatlen, sizeof(*formatargs), 0);
     134      153377 :         currentarg = 1;
     135             : 
     136             :         /* Preprocess format into formatcodes and formatargs */
     137      309056 :         for (i = 0; i < formatlen; formatcount++) {
     138      155679 :                 char code = format[i++];
     139      155679 :                 int arg = 1;
     140             : 
     141             :                 /* Handle format arguments if any */
     142      155679 :                 if (i < formatlen) {
     143      153766 :                         char c = format[i];
     144             : 
     145      153766 :                         if (c == '*') {
     146          40 :                                 arg = -1;
     147          40 :                                 i++;
     148             :                         }
     149      153726 :                         else if (c >= '0' && c <= '9') {
     150      152026 :                                 arg = atoi(&format[i]);
     151             :                   
     152      456590 :                                 while (format[i] >= '0' && format[i] <= '9' && i < formatlen) {
     153      152538 :                                         i++;
     154             :                                 }
     155             :                         }
     156             :                 }
     157             : 
     158             :                 /* Handle special arg '*' for all codes and check argv overflows */
     159      155679 :                 switch ((int) code) {
     160             :                         /* Never uses any args */
     161             :                         case 'x': 
     162             :                         case 'X':       
     163             :                         case '@':
     164           0 :                                 if (arg < 0) {
     165           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: '*' ignored", code);
     166           0 :                                         arg = 1;
     167             :                                 }
     168           0 :                                 break;
     169             : 
     170             :                         /* Always uses one arg */
     171             :                         case 'a': 
     172             :                         case 'A': 
     173             :                         case 'Z': 
     174             :                         case 'h': 
     175             :                         case 'H':
     176         795 :                                 if (currentarg >= num_args) {
     177           0 :                                         efree(argv);
     178           0 :                                         efree(formatcodes);
     179           0 :                                         efree(formatargs);
     180           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough arguments", code);
     181           0 :                                         RETURN_FALSE;
     182             :                                 }
     183             : 
     184         795 :                                 if (arg < 0) {
     185          80 :                                         if (Z_ISREF_PP(argv[currentarg])) {
     186           0 :                                                 SEPARATE_ZVAL(argv[currentarg]);
     187             :                                         }
     188          40 :                                         convert_to_string_ex(argv[currentarg]);
     189          40 :                                         arg = Z_STRLEN_PP(argv[currentarg]);
     190          40 :                                         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           1 :                                                 arg++;
     195             :                                         }
     196             :                                 }
     197             : 
     198         795 :                                 currentarg++;
     199         795 :                                 break;
     200             : 
     201             :                         /* Use as many args as specified */
     202             :                         case 'c': 
     203             :                         case 'C': 
     204             :                         case 's': 
     205             :                         case 'S': 
     206             :                         case 'i': 
     207             :                         case 'I':
     208             :                         case 'l': 
     209             :                         case 'L': 
     210             :                         case 'n': 
     211             :                         case 'N': 
     212             :                         case 'v': 
     213             :                         case 'V':
     214             :                         case 'f': 
     215             :                         case 'd': 
     216      154884 :                                 if (arg < 0) {
     217           0 :                                         arg = num_args - currentarg;
     218             :                                 }
     219             : 
     220      154884 :                                 currentarg += arg;
     221             : 
     222      154884 :                                 if (currentarg > num_args) {
     223           0 :                                         efree(argv);
     224           0 :                                         efree(formatcodes);
     225           0 :                                         efree(formatargs);
     226           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: too few arguments", code);
     227           0 :                                         RETURN_FALSE;
     228             :                                 }
     229      154884 :                                 break;
     230             : 
     231             :                         default:
     232           0 :                                 efree(argv);
     233           0 :                                 efree(formatcodes);
     234           0 :                                 efree(formatargs);
     235           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: unknown format code", code);
     236           0 :                                 RETURN_FALSE;
     237             :                 }
     238             : 
     239      155679 :                 formatcodes[formatcount] = code;
     240      155679 :                 formatargs[formatcount] = arg;
     241             :         }
     242             : 
     243      153377 :         if (currentarg < num_args) {
     244           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d arguments unused", (num_args - currentarg));
     245             :         }
     246             : 
     247             :         /* Calculate output length and upper bound while processing*/
     248      309056 :         for (i = 0; i < formatcount; i++) {
     249      155679 :             int code = (int) formatcodes[i];
     250      155679 :                 int arg = formatargs[i];
     251             : 
     252      155679 :                 switch ((int) code) {
     253             :                         case 'h': 
     254             :                         case 'H': 
     255          43 :                                 INC_OUTPUTPOS((arg + (arg % 2)) / 2,1)  /* 4 bit per arg */
     256          43 :                                 break;
     257             : 
     258             :                         case 'a': 
     259             :                         case 'A':
     260             :                         case 'Z':
     261             :                         case 'c': 
     262             :                         case 'C':
     263             :                         case 'x':
     264      144815 :                                 INC_OUTPUTPOS(arg,1)            /* 8 bit per arg */
     265      144815 :                                 break;
     266             : 
     267             :                         case 's': 
     268             :                         case 'S': 
     269             :                         case 'n': 
     270             :                         case 'v':
     271          95 :                                 INC_OUTPUTPOS(arg,2)            /* 16 bit per arg */
     272          95 :                                 break;
     273             : 
     274             :                         case 'i': 
     275             :                         case 'I':
     276           3 :                                 INC_OUTPUTPOS(arg,sizeof(int))
     277           3 :                                 break;
     278             : 
     279             :                         case 'l': 
     280             :                         case 'L': 
     281             :                         case 'N': 
     282             :                         case 'V':
     283       10710 :                                 INC_OUTPUTPOS(arg,4)            /* 32 bit per arg */
     284       10710 :                                 break;
     285             : 
     286             :                         case 'f':
     287           0 :                                 INC_OUTPUTPOS(arg,sizeof(float))
     288           0 :                                 break;
     289             : 
     290             :                         case 'd':
     291          13 :                                 INC_OUTPUTPOS(arg,sizeof(double))
     292          13 :                                 break;
     293             : 
     294             :                         case 'X':
     295           0 :                                 outputpos -= arg;
     296             : 
     297           0 :                                 if (outputpos < 0) {
     298           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", code);
     299           0 :                                         outputpos = 0;
     300             :                                 }
     301           0 :                                 break;
     302             : 
     303             :                         case '@':
     304           0 :                                 outputpos = arg;
     305             :                                 break;
     306             :                 }
     307             : 
     308      155679 :                 if (outputsize < outputpos) {
     309      155678 :                         outputsize = outputpos;
     310             :                 }
     311             :         }
     312             : 
     313      153377 :         output = emalloc(outputsize + 1);
     314      153377 :         outputpos = 0;
     315      153377 :         currentarg = 1;
     316             : 
     317             :         /* Do actual packing */
     318      309056 :         for (i = 0; i < formatcount; i++) {
     319      155679 :             int code = (int) formatcodes[i];
     320      155679 :                 int arg = formatargs[i];
     321             :                 zval **val;
     322             : 
     323      155679 :                 switch ((int) code) {
     324             :                         case 'a': 
     325             :                         case 'A': 
     326             :                         case 'Z': {
     327         752 :                                 int arg_cp = (code != 'Z') ? arg : MAX(0, arg - 1);
     328         752 :                                 memset(&output[outputpos], (code == 'a' || code == 'Z') ? '\0' : ' ', arg);
     329         752 :                                 val = argv[currentarg++];
     330        1504 :                                 if (Z_ISREF_PP(val)) {
     331           0 :                                         SEPARATE_ZVAL(val);
     332             :                                 }
     333        1172 :                                 convert_to_string_ex(val);
     334         752 :                                 memcpy(&output[outputpos], Z_STRVAL_PP(val),
     335         752 :                                            (Z_STRLEN_PP(val) < arg_cp) ? Z_STRLEN_PP(val) : arg_cp);
     336         752 :                                 outputpos += arg;
     337         752 :                                 break;
     338             :                         }
     339             : 
     340             :                         case 'h': 
     341             :                         case 'H': {
     342          43 :                                 int nibbleshift = (code == 'h') ? 0 : 4;
     343          43 :                                 int first = 1;
     344             :                                 char *v;
     345             : 
     346          43 :                                 val = argv[currentarg++];
     347          86 :                                 if (Z_ISREF_PP(val)) {
     348           0 :                                         SEPARATE_ZVAL(val);
     349             :                                 }
     350          43 :                                 convert_to_string_ex(val);
     351          43 :                                 v = Z_STRVAL_PP(val);
     352          43 :                                 outputpos--;
     353          43 :                                 if(arg > Z_STRLEN_PP(val)) {
     354           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough characters in string", code);
     355           0 :                                         arg = Z_STRLEN_PP(val);
     356             :                                 }
     357             : 
     358         674 :                                 while (arg-- > 0) {
     359         588 :                                         char n = *v++;
     360             : 
     361        1018 :                                         if (n >= '0' && n <= '9') {
     362         430 :                                                 n -= '0';
     363         158 :                                         } else if (n >= 'A' && n <= 'F') {
     364           0 :                                                 n -= ('A' - 10);
     365         316 :                                         } else if (n >= 'a' && n <= 'f') {
     366         158 :                                                 n -= ('a' - 10);
     367             :                                         } else {
     368           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: illegal hex digit %c", code, n);
     369           0 :                                                 n = 0;
     370             :                                         }
     371             : 
     372         588 :                                         if (first--) {
     373         296 :                                                 output[++outputpos] = 0;
     374             :                                         } else {
     375         292 :                                           first = 1;
     376             :                                         }
     377             : 
     378         588 :                                         output[outputpos] |= (n << nibbleshift);
     379         588 :                                         nibbleshift = (nibbleshift + 4) & 7;
     380             :                                 }
     381             : 
     382          43 :                                 outputpos++;
     383          43 :                                 break;
     384             :                         }
     385             : 
     386             :                         case 'c': 
     387             :                         case 'C':
     388      781940 :                                 while (arg-- > 0) {
     389      493814 :                                         php_pack(argv[currentarg++], 1, byte_map, &output[outputpos]);
     390      493814 :                                         outputpos++;
     391             :                                 }
     392      144063 :                                 break;
     393             : 
     394             :                         case 's': 
     395             :                         case 'S': 
     396             :                         case 'n': 
     397             :                         case 'v': {
     398          95 :                                 int *map = machine_endian_short_map;
     399             : 
     400          95 :                                 if (code == 'n') {
     401          93 :                                         map = big_endian_short_map;
     402           2 :                                 } else if (code == 'v') {
     403           0 :                                         map = little_endian_short_map;
     404             :                                 }
     405             : 
     406         285 :                                 while (arg-- > 0) {
     407          95 :                                         php_pack(argv[currentarg++], 2, map, &output[outputpos]);
     408          95 :                                         outputpos += 2;
     409             :                                 }
     410          95 :                                 break;
     411             :                         }
     412             : 
     413             :                         case 'i': 
     414             :                         case 'I': 
     415           9 :                                 while (arg-- > 0) {
     416           3 :                                         php_pack(argv[currentarg++], sizeof(int), int_map, &output[outputpos]);
     417           3 :                                         outputpos += sizeof(int);
     418             :                                 }
     419           3 :                                 break;
     420             : 
     421             :                         case 'l': 
     422             :                         case 'L': 
     423             :                         case 'N': 
     424             :                         case 'V': {
     425       10710 :                                 int *map = machine_endian_long_map;
     426             : 
     427       10710 :                                 if (code == 'N') {
     428        8261 :                                         map = big_endian_long_map;
     429        2449 :                                 } else if (code == 'V') {
     430        2447 :                                         map = little_endian_long_map;
     431             :                                 }
     432             : 
     433       32130 :                                 while (arg-- > 0) {
     434       10710 :                                         php_pack(argv[currentarg++], 4, map, &output[outputpos]);
     435       10710 :                                         outputpos += 4;
     436             :                                 }
     437       10710 :                                 break;
     438             :                         }
     439             : 
     440             :                         case 'f': {
     441             :                                 float v;
     442             : 
     443           0 :                                 while (arg-- > 0) {
     444           0 :                                         val = argv[currentarg++];
     445           0 :                                         convert_to_double_ex(val);
     446           0 :                                         v = (float) Z_DVAL_PP(val);
     447           0 :                                         memcpy(&output[outputpos], &v, sizeof(v));
     448           0 :                                         outputpos += sizeof(v);
     449             :                                 }
     450           0 :                                 break;
     451             :                         }
     452             : 
     453             :                         case 'd': {
     454             :                                 double v;
     455             : 
     456          39 :                                 while (arg-- > 0) {
     457          13 :                                         val = argv[currentarg++];
     458          13 :                                         convert_to_double_ex(val);
     459          13 :                                         v = (double) Z_DVAL_PP(val);
     460          13 :                                         memcpy(&output[outputpos], &v, sizeof(v));
     461          13 :                                         outputpos += sizeof(v);
     462             :                                 }
     463          13 :                                 break;
     464             :                         }
     465             : 
     466             :                         case 'x':
     467           0 :                                 memset(&output[outputpos], '\0', arg);
     468           0 :                                 outputpos += arg;
     469           0 :                                 break;
     470             : 
     471             :                         case 'X':
     472           0 :                                 outputpos -= arg;
     473             : 
     474           0 :                                 if (outputpos < 0) {
     475           0 :                                         outputpos = 0;
     476             :                                 }
     477           0 :                                 break;
     478             : 
     479             :                         case '@':
     480           0 :                                 if (arg > outputpos) {
     481           0 :                                         memset(&output[outputpos], '\0', arg - outputpos);
     482             :                                 }
     483           0 :                                 outputpos = arg;
     484             :                                 break;
     485             :                 }
     486             :         }
     487             : 
     488      153377 :         efree(argv);
     489      153377 :         efree(formatcodes);
     490      153377 :         efree(formatargs);
     491      153377 :         output[outputpos] = '\0';
     492      153377 :         RETVAL_STRINGL(output, outputpos, 1);
     493      153377 :         efree(output);
     494             : }
     495             : /* }}} */
     496             : 
     497             : /* {{{ php_unpack
     498             :  */
     499          17 : static long php_unpack(char *data, int size, int issigned, int *map)
     500             : {
     501             :         long result;
     502          17 :         char *cresult = (char *) &result;
     503             :         int i;
     504             : 
     505          17 :         result = issigned ? -1 : 0;
     506             : 
     507          77 :         for (i = 0; i < size; i++) {
     508          60 :                 cresult[map[i]] = *data++;
     509             :         }
     510             : 
     511          17 :         return result;
     512             : }
     513             : /* }}} */
     514             : 
     515             : /* unpack() is based on Perl's unpack(), but is modified a bit from there.
     516             :  * Rather than depending on error-prone ordered lists or syntactically
     517             :  * unpleasant pass-by-reference, we return an object with named parameters 
     518             :  * (like *_fetch_object()). Syntax is "f[repeat]name/...", where "f" is the
     519             :  * formatter char (like pack()), "[repeat]" is the optional repeater argument,
     520             :  * and "name" is the name of the variable to use.
     521             :  * Example: "c2chars/nints" will return an object with fields
     522             :  * chars1, chars2, and ints.
     523             :  * Numeric pack types will return numbers, a and A will return strings,
     524             :  * f and d will return doubles.
     525             :  * Implemented formats are Z, A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
     526             :  */
     527             : /* {{{ proto array unpack(string format, string input)
     528             :    Unpack binary string into named array elements according to format argument */
     529        1026 : PHP_FUNCTION(unpack)
     530             : {
     531             :         char *format, *input, *formatarg, *inputarg;
     532             :         int formatlen, formatarg_len, inputarg_len;
     533             :         int inputpos, inputlen, i;
     534             : 
     535        1026 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &formatarg, &formatarg_len,
     536             :                 &inputarg, &inputarg_len) == FAILURE) {
     537           2 :                 return;
     538             :         }
     539             : 
     540        1024 :         format = formatarg;
     541        1024 :         formatlen = formatarg_len;
     542        1024 :         input = inputarg;
     543        1024 :         inputlen = inputarg_len;
     544        1024 :         inputpos = 0;
     545             : 
     546        1024 :         array_init(return_value);
     547             : 
     548        3068 :         while (formatlen-- > 0) {
     549        1024 :                 char type = *(format++);
     550             :                 char c;
     551        1024 :                 int arg = 1, argb;
     552             :                 char *name;
     553             :                 int namelen;
     554        1024 :                 int size=0;
     555             : 
     556             :                 /* Handle format arguments if any */
     557        1024 :                 if (formatlen > 0) {
     558        1005 :                         c = *format;
     559             : 
     560        1029 :                         if (c >= '0' && c <= '9') {
     561          24 :                                 arg = atoi(format);
     562             : 
     563          75 :                                 while (formatlen > 0 && *format >= '0' && *format <= '9') {
     564          27 :                                         format++;
     565          27 :                                         formatlen--;
     566             :                                 }
     567         981 :                         } else if (c == '*') {
     568         974 :                                 arg = -1;
     569         974 :                                 format++;
     570         974 :                                 formatlen--;
     571             :                         }
     572             :                 }
     573             : 
     574             :                 /* Get of new value in array */
     575        1024 :                 name = format;
     576        1024 :                 argb = arg;
     577             : 
     578        2055 :                 while (formatlen > 0 && *format != '/') {
     579           7 :                         formatlen--;
     580           7 :                         format++;
     581             :                 }
     582             : 
     583        1024 :                 namelen = format - name;
     584             : 
     585        1024 :                 if (namelen > 200)
     586           0 :                         namelen = 200;
     587             : 
     588        1024 :                 switch ((int) type) {
     589             :                         /* Never use any input */
     590             :                         case 'X': 
     591           0 :                                 size = -1;
     592           0 :                                 break;
     593             : 
     594             :                         case '@':
     595           0 :                                 size = 0;
     596           0 :                                 break;
     597             : 
     598             :                         case 'a': 
     599             :                         case 'A':
     600             :                         case 'Z':
     601          13 :                                 size = arg;
     602          13 :                                 arg = 1;
     603          13 :                                 break;
     604             : 
     605             :                         case 'h': 
     606             :                         case 'H': 
     607         983 :                                 size = (arg > 0) ? (arg + (arg % 2)) / 2 : arg;
     608         983 :                                 arg = 1;
     609         983 :                                 break;
     610             : 
     611             :                         /* Use 1 byte of input */
     612             :                         case 'c': 
     613             :                         case 'C':
     614             :                         case 'x':
     615           1 :                                 size = 1;
     616           1 :                                 break;
     617             : 
     618             :                         /* Use 2 bytes of input */
     619             :                         case 's': 
     620             :                         case 'S': 
     621             :                         case 'n': 
     622             :                         case 'v':
     623           1 :                                 size = 2;
     624           1 :                                 break;
     625             : 
     626             :                         /* Use sizeof(int) bytes of input */
     627             :                         case 'i': 
     628             :                         case 'I':
     629           1 :                                 size = sizeof(int);
     630           1 :                                 break;
     631             : 
     632             :                         /* Use 4 bytes of input */
     633             :                         case 'l': 
     634             :                         case 'L': 
     635             :                         case 'N': 
     636             :                         case 'V':
     637          10 :                                 size = 4;
     638          10 :                                 break;
     639             : 
     640             :                         /* Use sizeof(float) bytes of input */
     641             :                         case 'f':
     642           0 :                                 size = sizeof(float);
     643           0 :                                 break;
     644             : 
     645             :                         /* Use sizeof(double) bytes of input */
     646             :                         case 'd':
     647          13 :                                 size = sizeof(double);
     648          13 :                                 break;
     649             : 
     650             :                         default:
     651           2 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid format type %c", type);
     652             :                                 zval_dtor(return_value);
     653           2 :                                 RETURN_FALSE;
     654             :                                 break;
     655             :                 }
     656             : 
     657             :                 /* Do actual unpacking */
     658        2046 :                 for (i = 0; i != arg; i++ ) {
     659             :                         /* Space for name + number, safe as namelen is ensured <= 200 */
     660             :                         char n[256];
     661             : 
     662        2047 :                         if (arg != 1 || namelen == 0) {
     663             :                                 /* Need to add element number to name */
     664        1020 :                                 snprintf(n, sizeof(n), "%.*s%d", namelen, name, i + 1);
     665             :                         } else {
     666             :                                 /* Truncate name to next format code or end of string */
     667           7 :                                 snprintf(n, sizeof(n), "%.*s", namelen, name);
     668             :                         }
     669             : 
     670        1027 :                         if (size != 0 && size != -1 && INT_MAX - size + 1 < inputpos) {
     671           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow", type);
     672           0 :                                 inputpos = 0;
     673             :                         }
     674             : 
     675        1027 :                         if ((inputpos + size) <= inputlen) {
     676        1024 :                                 switch ((int) type) {
     677             :                                         case 'a': {
     678             :                                                 /* a will not strip any trailing whitespace or null padding */
     679           3 :                                                 int len = inputlen - inputpos;  /* Remaining string */
     680             : 
     681             :                                                 /* If size was given take minimum of len and size */
     682           3 :                                                 if ((size >= 0) && (len > size)) {
     683           1 :                                                         len = size;
     684             :                                                 }
     685             : 
     686           3 :                                                 size = len;
     687             : 
     688           3 :                                                 add_assoc_stringl(return_value, n, &input[inputpos], len, 1);
     689           3 :                                                 break;
     690             :                                         }
     691             :                                         case 'A': {
     692             :                                                 /* A will strip any trailing whitespace */
     693           2 :                                                 char padn = '\0'; char pads = ' '; char padt = '\t'; char padc = '\r'; char padl = '\n';
     694           2 :                                                 int len = inputlen - inputpos;  /* Remaining string */
     695             : 
     696             :                                                 /* If size was given take minimum of len and size */
     697           2 :                                                 if ((size >= 0) && (len > size)) {
     698           1 :                                                         len = size;
     699             :                                                 }
     700             : 
     701           2 :                                                 size = len;
     702             : 
     703             :                                                 /* Remove trailing white space and nulls chars from unpacked data */
     704          10 :                                                 while (--len >= 0) {
     705          26 :                                                         if (input[inputpos + len] != padn
     706           6 :                                                                 && input[inputpos + len] != pads
     707           5 :                                                                 && input[inputpos + len] != padt
     708           4 :                                                                 && input[inputpos + len] != padc
     709           3 :                                                                 && input[inputpos + len] != padl
     710             :                                                         )
     711           2 :                                                                 break;
     712             :                                                 }
     713             : 
     714           2 :                                                 add_assoc_stringl(return_value, n, &input[inputpos], len + 1, 1);
     715           2 :                                                 break;
     716             :                                         }
     717             :                                         /* New option added for Z to remain in-line with the Perl implementation */
     718             :                                         case 'Z': {
     719             :                                                 /* Z will strip everything after the first null character */
     720           6 :                                                 char pad = '\0';
     721             :                                                 int      s,
     722           6 :                                                          len = inputlen - inputpos;     /* Remaining string */
     723             : 
     724             :                                                 /* If size was given take minimum of len and size */
     725           6 :                                                 if ((size >= 0) && (len > size)) {
     726           3 :                                                         len = size;
     727             :                                                 }
     728             : 
     729           6 :                                                 size = len;
     730             : 
     731             :                                                 /* Remove everything after the first null */
     732          17 :                                                 for (s=0 ; s < len ; s++) {
     733          15 :                                                         if (input[inputpos + s] == pad)
     734           4 :                                                                 break;
     735             :                                                 }
     736           6 :                                                 len = s;
     737             : 
     738           6 :                                                 add_assoc_stringl(return_value, n, &input[inputpos], len, 1);
     739           6 :                                                 break;
     740             :                                         }
     741             : 
     742             :                                         
     743             :                                         case 'h': 
     744             :                                         case 'H': {
     745         983 :                                                 int len = (inputlen - inputpos) * 2;    /* Remaining */
     746         983 :                                                 int nibbleshift = (type == 'h') ? 0 : 4;
     747         983 :                                                 int first = 1;
     748             :                                                 char *buf;
     749             :                                                 int ipos, opos;
     750             : 
     751             :                                                 /* If size was given take minimum of len and size */
     752         983 :                                                 if (size >= 0 && len > (size * 2)) {
     753           0 :                                                         len = size * 2;
     754             :                                                 } 
     755             : 
     756         983 :                                                 if (argb > 0) {      
     757          13 :                                                         len -= argb % 2;
     758             :                                                 }
     759             : 
     760         983 :                                                 buf = emalloc(len + 1);
     761             : 
     762        3459 :                                                 for (ipos = opos = 0; opos < len; opos++) {
     763        2476 :                                                         char cc = (input[inputpos + ipos] >> nibbleshift) & 0xf;
     764             : 
     765        2476 :                                                         if (cc < 10) {
     766        1261 :                                                                 cc += '0';
     767             :                                                         } else {
     768        1215 :                                                                 cc += 'a' - 10;
     769             :                                                         }
     770             : 
     771        2476 :                                                         buf[opos] = cc;
     772        2476 :                                                         nibbleshift = (nibbleshift + 4) & 7;
     773             : 
     774        2476 :                                                         if (first-- == 0) {
     775        1237 :                                                                 ipos++;
     776        1237 :                                                                 first = 1;
     777             :                                                         }
     778             :                                                 }
     779             : 
     780         983 :                                                 buf[len] = '\0';
     781         983 :                                                 add_assoc_stringl(return_value, n, buf, len, 1);
     782         983 :                                                 efree(buf);
     783         983 :                                                 break;
     784             :                                         }
     785             : 
     786             :                                         case 'c': 
     787             :                                         case 'C': {
     788           2 :                                                 int issigned = (type == 'c') ? (input[inputpos] & 0x80) : 0;
     789           2 :                                                 long v = php_unpack(&input[inputpos], 1, issigned, byte_map);
     790           2 :                                                 add_assoc_long(return_value, n, v);
     791           2 :                                                 break;
     792             :                                         }
     793             : 
     794             :                                         case 's': 
     795             :                                         case 'S': 
     796             :                                         case 'n': 
     797             :                                         case 'v': {
     798             :                                                 long v;
     799           1 :                                                 int issigned = 0;
     800           1 :                                                 int *map = machine_endian_short_map;
     801             : 
     802           1 :                                                 if (type == 's') {
     803           0 :                                                         issigned = input[inputpos + (machine_little_endian ? 1 : 0)] & 0x80;
     804           1 :                                                 } else if (type == 'n') {
     805           0 :                                                         map = big_endian_short_map;
     806           1 :                                                 } else if (type == 'v') {
     807           1 :                                                         map = little_endian_short_map;
     808             :                                                 }
     809             : 
     810           1 :                                                 v = php_unpack(&input[inputpos], 2, issigned, map);
     811           1 :                                                 add_assoc_long(return_value, n, v);
     812           1 :                                                 break;
     813             :                                         }
     814             : 
     815             :                                         case 'i': 
     816             :                                         case 'I': {
     817             :                                                 long v;
     818           1 :                                                 int issigned = 0;
     819             : 
     820           1 :                                                 if (type == 'i') {
     821           0 :                                                         issigned = input[inputpos + (machine_little_endian ? (sizeof(int) - 1) : 0)] & 0x80;
     822             :                                                 }
     823             : 
     824           1 :                                                 v = php_unpack(&input[inputpos], sizeof(int), issigned, int_map);
     825           1 :                                                 add_assoc_long(return_value, n, v);
     826           1 :                                                 break;
     827             :                                         }
     828             : 
     829             :                                         case 'l': 
     830             :                                         case 'L': 
     831             :                                         case 'N': 
     832             :                                         case 'V': {
     833          13 :                                                 int issigned = 0;
     834          13 :                                                 int *map = machine_endian_long_map;
     835          13 :                                                 long v = 0;
     836             : 
     837          14 :                                                 if (type == 'l' || type == 'L') {
     838           1 :                                                         issigned = input[inputpos + (machine_little_endian ? 3 : 0)] & 0x80;
     839          12 :                                                 } else if (type == 'N') {
     840           8 :                                                         issigned = input[inputpos] & 0x80;
     841           8 :                                                         map = big_endian_long_map;
     842           4 :                                                 } else if (type == 'V') {
     843           4 :                                                         issigned = input[inputpos + 3] & 0x80;
     844           4 :                                                         map = little_endian_long_map;
     845             :                                                 }
     846             : 
     847          13 :                                                 if (sizeof(long) > 4 && issigned) {
     848           2 :                                                         v = ~INT_MAX;
     849             :                                                 }
     850             : 
     851          13 :                                                 v |= php_unpack(&input[inputpos], 4, issigned, map);
     852             :                                                 if (sizeof(long) > 4) {
     853          13 :                                                         if (type == 'l') {
     854           1 :                                                                 v = (signed int) v; 
     855             :                                                         } else {
     856          12 :                                                                 v = (unsigned int) v;
     857             :                                                         }
     858             :                                                 }
     859          13 :                                                 add_assoc_long(return_value, n, v);
     860          13 :                                                 break;
     861             :                                         }
     862             : 
     863             :                                         case 'f': {
     864             :                                                 float v;
     865             : 
     866           0 :                                                 memcpy(&v, &input[inputpos], sizeof(float));
     867           0 :                                                 add_assoc_double(return_value, n, (double)v);
     868           0 :                                                 break;
     869             :                                         }
     870             : 
     871             :                                         case 'd': {
     872             :                                                 double v;
     873             : 
     874          13 :                                                 memcpy(&v, &input[inputpos], sizeof(double));
     875          13 :                                                 add_assoc_double(return_value, n, v);
     876          13 :                                                 break;
     877             :                                         }
     878             : 
     879             :                                         case 'x':
     880             :                                                 /* Do nothing with input, just skip it */
     881           0 :                                                 break;
     882             : 
     883             :                                         case 'X':
     884           0 :                                                 if (inputpos < size) {
     885           0 :                                                         inputpos = -size;
     886           0 :                                                         i = arg - 1;            /* Break out of for loop */
     887             : 
     888           0 :                                                         if (arg >= 0) {
     889           0 :                                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
     890             :                                                         }
     891             :                                                 }
     892           0 :                                                 break;
     893             : 
     894             :                                         case '@':
     895           0 :                                                 if (arg <= inputlen) {
     896           0 :                                                         inputpos = arg;
     897             :                                                 } else {
     898           0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
     899             :                                                 }
     900             : 
     901           0 :                                                 i = arg - 1;    /* Done, break out of for loop */
     902             :                                                 break;
     903             :                                 }
     904             : 
     905        1024 :                                 inputpos += size;
     906        1024 :                                 if (inputpos < 0) {
     907         970 :                                         if (size != -1) { /* only print warning if not working with * */
     908           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
     909             :                                         }
     910         970 :                                         inputpos = 0;
     911             :                                 }
     912           3 :                         } else if (arg < 0) {
     913             :                                 /* Reached end of input for '*' repeater */
     914           1 :                                 break;
     915             :                         } else {
     916           2 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough input, need %d, have %d", type, size, inputlen - inputpos);
     917             :                                 zval_dtor(return_value);
     918           2 :                                 RETURN_FALSE;
     919             :                         }
     920             :                 }
     921             : 
     922        1020 :                 formatlen--;    /* Skip '/' separator, does no harm if inputlen == 0 */
     923        1020 :                 format++;
     924             :         }
     925             : }
     926             : /* }}} */
     927             : 
     928             : /* {{{ PHP_MINIT_FUNCTION
     929             :  */
     930       21265 : PHP_MINIT_FUNCTION(pack)
     931             : {
     932       21265 :         int machine_endian_check = 1;
     933             :         int i;
     934             : 
     935       21265 :         machine_little_endian = ((char *)&machine_endian_check)[0];
     936             : 
     937       21265 :         if (machine_little_endian) {
     938             :                 /* Where to get lo to hi bytes from */
     939       21265 :                 byte_map[0] = 0;
     940             : 
     941      106325 :                 for (i = 0; i < (int)sizeof(int); i++) {
     942       85060 :                         int_map[i] = i;
     943             :                 }
     944             : 
     945       21265 :                 machine_endian_short_map[0] = 0;
     946       21265 :                 machine_endian_short_map[1] = 1;
     947       21265 :                 big_endian_short_map[0] = 1;
     948       21265 :                 big_endian_short_map[1] = 0;
     949       21265 :                 little_endian_short_map[0] = 0;
     950       21265 :                 little_endian_short_map[1] = 1;
     951             : 
     952       21265 :                 machine_endian_long_map[0] = 0;
     953       21265 :                 machine_endian_long_map[1] = 1;
     954       21265 :                 machine_endian_long_map[2] = 2;
     955       21265 :                 machine_endian_long_map[3] = 3;
     956       21265 :                 big_endian_long_map[0] = 3;
     957       21265 :                 big_endian_long_map[1] = 2;
     958       21265 :                 big_endian_long_map[2] = 1;
     959       21265 :                 big_endian_long_map[3] = 0;
     960       21265 :                 little_endian_long_map[0] = 0;
     961       21265 :                 little_endian_long_map[1] = 1;
     962       21265 :                 little_endian_long_map[2] = 2;
     963       21265 :                 little_endian_long_map[3] = 3;
     964             :         }
     965             :         else {
     966             :                 zval val;
     967           0 :                 int size = sizeof(Z_LVAL(val));
     968           0 :                 Z_LVAL(val)=0; /*silence a warning*/
     969             : 
     970             :                 /* Where to get hi to lo bytes from */
     971           0 :                 byte_map[0] = size - 1;
     972             : 
     973           0 :                 for (i = 0; i < (int)sizeof(int); i++) {
     974           0 :                         int_map[i] = size - (sizeof(int) - i);
     975             :                 }
     976             : 
     977           0 :                 machine_endian_short_map[0] = size - 2;
     978           0 :                 machine_endian_short_map[1] = size - 1;
     979           0 :                 big_endian_short_map[0] = size - 2;
     980           0 :                 big_endian_short_map[1] = size - 1;
     981           0 :                 little_endian_short_map[0] = size - 1;
     982           0 :                 little_endian_short_map[1] = size - 2;
     983             : 
     984           0 :                 machine_endian_long_map[0] = size - 4;
     985           0 :                 machine_endian_long_map[1] = size - 3;
     986           0 :                 machine_endian_long_map[2] = size - 2;
     987           0 :                 machine_endian_long_map[3] = size - 1;
     988           0 :                 big_endian_long_map[0] = size - 4;
     989           0 :                 big_endian_long_map[1] = size - 3;
     990           0 :                 big_endian_long_map[2] = size - 2;
     991           0 :                 big_endian_long_map[3] = size - 1;
     992           0 :                 little_endian_long_map[0] = size - 1;
     993           0 :                 little_endian_long_map[1] = size - 2;
     994           0 :                 little_endian_long_map[2] = size - 3;
     995           0 :                 little_endian_long_map[3] = size - 4;
     996             :         }
     997             : 
     998       21265 :         return SUCCESS;
     999             : }
    1000             : /* }}} */
    1001             : 
    1002             : /*
    1003             :  * Local variables:
    1004             :  * tab-width: 4
    1005             :  * c-basic-offset: 4
    1006             :  * End:
    1007             :  * vim600: noet sw=4 ts=4 fdm=marker
    1008             :  * vim<600: noet sw=4 ts=4
    1009             :  */

Generated by: LCOV version 1.10

Generated at Mon, 04 Aug 2014 15:49:14 +0000 (43 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.