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: 296 419 70.6 %
Date: 2015-05-17 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      504626 : static void php_pack(zval **val, int size, int *map, char *output)
      88             : {
      89             :         int i;
      90             :         char *v;
      91             : 
      92      504626 :         convert_to_long_ex(val);
      93      504626 :         v = (char *) &Z_LVAL_PP(val);
      94             : 
      95     1041498 :         for (i = 0; i < size; i++) {
      96      536872 :                 *output++ = v[map[i]];
      97             :         }
      98      504626 : }
      99             : /* }}} */
     100             : 
     101             : /* pack() idea stolen from Perl (implemented formats behave the same as there)
     102             :  * Implemented formats are 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      153371 : PHP_FUNCTION(pack)
     107             : {
     108      153371 :         zval ***argv = NULL;
     109             :         int num_args, i;
     110             :         int currentarg;
     111             :         char *format;
     112             :         int formatlen;
     113             :         char *formatcodes;
     114             :         int *formatargs;
     115      153371 :         int formatcount = 0;
     116      153371 :         int outputpos = 0, outputsize = 0;
     117             :         char *output;
     118             : 
     119      153371 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &argv, &num_args) == FAILURE) {
     120           0 :                 return;
     121             :         }
     122             : 
     123      306742 :         if (Z_ISREF_PP(argv[0])) {
     124           0 :                 SEPARATE_ZVAL(argv[0]);
     125             :         }
     126      153371 :         convert_to_string_ex(argv[0]);
     127             : 
     128      153371 :         format = Z_STRVAL_PP(argv[0]);
     129      153371 :         formatlen = Z_STRLEN_PP(argv[0]);
     130             : 
     131             :         /* We have a maximum of <formatlen> format codes to deal with */
     132      153371 :         formatcodes = safe_emalloc(formatlen, sizeof(*formatcodes), 0);
     133      153371 :         formatargs = safe_emalloc(formatlen, sizeof(*formatargs), 0);
     134      153371 :         currentarg = 1;
     135             : 
     136             :         /* Preprocess format into formatcodes and formatargs */
     137      309058 :         for (i = 0; i < formatlen; formatcount++) {
     138      155687 :                 char code = format[i++];
     139      155687 :                 int arg = 1;
     140             : 
     141             :                 /* Handle format arguments if any */
     142      155687 :                 if (i < formatlen) {
     143      153772 :                         char c = format[i];
     144             : 
     145      153772 :                         if (c == '*') {
     146          39 :                                 arg = -1;
     147          39 :                                 i++;
     148             :                         }
     149      153733 :                         else if (c >= '0' && c <= '9') {
     150      152019 :                                 arg = atoi(&format[i]);
     151             : 
     152      456569 :                                 while (format[i] >= '0' && format[i] <= '9' && i < formatlen) {
     153      152531 :                                         i++;
     154             :                                 }
     155             :                         }
     156             :                 }
     157             : 
     158             :                 /* Handle special arg '*' for all codes and check argv overflows */
     159      155687 :                 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 'h':
     174             :                         case 'H':
     175         799 :                                 if (currentarg >= num_args) {
     176           0 :                                         efree(argv);
     177           0 :                                         efree(formatcodes);
     178           0 :                                         efree(formatargs);
     179           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough arguments", code);
     180           0 :                                         RETURN_FALSE;
     181             :                                 }
     182             : 
     183         799 :                                 if (arg < 0) {
     184          78 :                                         if (Z_ISREF_PP(argv[currentarg])) {
     185           0 :                                                 SEPARATE_ZVAL(argv[currentarg]);
     186             :                                         }
     187          39 :                                         convert_to_string_ex(argv[currentarg]);
     188          39 :                                         arg = Z_STRLEN_PP(argv[currentarg]);
     189             :                                 }
     190             : 
     191         799 :                                 currentarg++;
     192         799 :                                 break;
     193             : 
     194             :                         /* Use as many args as specified */
     195             :                         case 'c':
     196             :                         case 'C':
     197             :                         case 's':
     198             :                         case 'S':
     199             :                         case 'i':
     200             :                         case 'I':
     201             :                         case 'l':
     202             :                         case 'L':
     203             :                         case 'n':
     204             :                         case 'N':
     205             :                         case 'v':
     206             :                         case 'V':
     207             :                         case 'f':
     208             :                         case 'd':
     209      154888 :                                 if (arg < 0) {
     210           0 :                                         arg = num_args - currentarg;
     211             :                                 }
     212             : 
     213      154888 :                                 currentarg += arg;
     214             : 
     215      154888 :                                 if (currentarg > num_args) {
     216           0 :                                         efree(argv);
     217           0 :                                         efree(formatcodes);
     218           0 :                                         efree(formatargs);
     219           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: too few arguments", code);
     220           0 :                                         RETURN_FALSE;
     221             :                                 }
     222      154888 :                                 break;
     223             : 
     224             :                         default:
     225           0 :                                 efree(argv);
     226           0 :                                 efree(formatcodes);
     227           0 :                                 efree(formatargs);
     228           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: unknown format code", code);
     229           0 :                                 RETURN_FALSE;
     230             :                 }
     231             : 
     232      155687 :                 formatcodes[formatcount] = code;
     233      155687 :                 formatargs[formatcount] = arg;
     234             :         }
     235             : 
     236      153371 :         if (currentarg < num_args) {
     237           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d arguments unused", (num_args - currentarg));
     238             :         }
     239             : 
     240             :         /* Calculate output length and upper bound while processing*/
     241      309058 :         for (i = 0; i < formatcount; i++) {
     242      155687 :             int code = (int) formatcodes[i];
     243      155687 :                 int arg = formatargs[i];
     244             : 
     245      155687 :                 switch ((int) code) {
     246             :                         case 'h':
     247             :                         case 'H':
     248          43 :                                 INC_OUTPUTPOS((arg + (arg % 2)) / 2,1)  /* 4 bit per arg */
     249          43 :                                 break;
     250             : 
     251             :                         case 'a':
     252             :                         case 'A':
     253             :                         case 'c':
     254             :                         case 'C':
     255             :                         case 'x':
     256      144819 :                                 INC_OUTPUTPOS(arg,1)            /* 8 bit per arg */
     257      144819 :                                 break;
     258             : 
     259             :                         case 's':
     260             :                         case 'S':
     261             :                         case 'n':
     262             :                         case 'v':
     263          95 :                                 INC_OUTPUTPOS(arg,2)            /* 16 bit per arg */
     264          95 :                                 break;
     265             : 
     266             :                         case 'i':
     267             :                         case 'I':
     268           7 :                                 INC_OUTPUTPOS(arg,sizeof(int))
     269           7 :                                 break;
     270             : 
     271             :                         case 'l':
     272             :                         case 'L':
     273             :                         case 'N':
     274             :                         case 'V':
     275       10710 :                                 INC_OUTPUTPOS(arg,4)            /* 32 bit per arg */
     276       10710 :                                 break;
     277             : 
     278             :                         case 'f':
     279           0 :                                 INC_OUTPUTPOS(arg,sizeof(float))
     280           0 :                                 break;
     281             : 
     282             :                         case 'd':
     283          13 :                                 INC_OUTPUTPOS(arg,sizeof(double))
     284          13 :                                 break;
     285             : 
     286             :                         case 'X':
     287           0 :                                 outputpos -= arg;
     288             : 
     289           0 :                                 if (outputpos < 0) {
     290           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", code);
     291           0 :                                         outputpos = 0;
     292             :                                 }
     293           0 :                                 break;
     294             : 
     295             :                         case '@':
     296           0 :                                 outputpos = arg;
     297             :                                 break;
     298             :                 }
     299             : 
     300      155687 :                 if (outputsize < outputpos) {
     301      155687 :                         outputsize = outputpos;
     302             :                 }
     303             :         }
     304             : 
     305      153371 :         output = emalloc(outputsize + 1);
     306      153371 :         outputpos = 0;
     307      153371 :         currentarg = 1;
     308             : 
     309             :         /* Do actual packing */
     310      309058 :         for (i = 0; i < formatcount; i++) {
     311      155687 :             int code = (int) formatcodes[i];
     312      155687 :                 int arg = formatargs[i];
     313             :                 zval **val;
     314             : 
     315      155687 :                 switch ((int) code) {
     316             :                         case 'a':
     317             :                         case 'A':
     318         756 :                                 memset(&output[outputpos], (code == 'a') ? '\0' : ' ', arg);
     319         756 :                                 val = argv[currentarg++];
     320        1512 :                                 if (Z_ISREF_PP(val)) {
     321           0 :                                         SEPARATE_ZVAL(val);
     322             :                                 }
     323        1212 :                                 convert_to_string_ex(val);
     324         756 :                                 memcpy(&output[outputpos], Z_STRVAL_PP(val),
     325         756 :                                            (Z_STRLEN_PP(val) < arg) ? Z_STRLEN_PP(val) : arg);
     326         756 :                                 outputpos += arg;
     327         756 :                                 break;
     328             : 
     329             :                         case 'h':
     330             :                         case 'H': {
     331          43 :                                 int nibbleshift = (code == 'h') ? 0 : 4;
     332          43 :                                 int first = 1;
     333             :                                 char *v;
     334             : 
     335          43 :                                 val = argv[currentarg++];
     336          86 :                                 if (Z_ISREF_PP(val)) {
     337           0 :                                         SEPARATE_ZVAL(val);
     338             :                                 }
     339          43 :                                 convert_to_string_ex(val);
     340          43 :                                 v = Z_STRVAL_PP(val);
     341          43 :                                 outputpos--;
     342          43 :                                 if(arg > Z_STRLEN_PP(val)) {
     343           0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough characters in string", code);
     344           0 :                                         arg = Z_STRLEN_PP(val);
     345             :                                 }
     346             : 
     347         674 :                                 while (arg-- > 0) {
     348         588 :                                         char n = *v++;
     349             : 
     350        1018 :                                         if (n >= '0' && n <= '9') {
     351         430 :                                                 n -= '0';
     352         158 :                                         } else if (n >= 'A' && n <= 'F') {
     353           0 :                                                 n -= ('A' - 10);
     354         316 :                                         } else if (n >= 'a' && n <= 'f') {
     355         158 :                                                 n -= ('a' - 10);
     356             :                                         } else {
     357           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: illegal hex digit %c", code, n);
     358           0 :                                                 n = 0;
     359             :                                         }
     360             : 
     361         588 :                                         if (first--) {
     362         296 :                                                 output[++outputpos] = 0;
     363             :                                         } else {
     364         292 :                                           first = 1;
     365             :                                         }
     366             : 
     367         588 :                                         output[outputpos] |= (n << nibbleshift);
     368         588 :                                         nibbleshift = (nibbleshift + 4) & 7;
     369             :                                 }
     370             : 
     371          43 :                                 outputpos++;
     372          43 :                                 break;
     373             :                         }
     374             : 
     375             :                         case 'c':
     376             :                         case 'C':
     377      781940 :                                 while (arg-- > 0) {
     378      493814 :                                         php_pack(argv[currentarg++], 1, byte_map, &output[outputpos]);
     379      493814 :                                         outputpos++;
     380             :                                 }
     381      144063 :                                 break;
     382             : 
     383             :                         case 's':
     384             :                         case 'S':
     385             :                         case 'n':
     386             :                         case 'v': {
     387          95 :                                 int *map = machine_endian_short_map;
     388             : 
     389          95 :                                 if (code == 'n') {
     390          93 :                                         map = big_endian_short_map;
     391           2 :                                 } else if (code == 'v') {
     392           0 :                                         map = little_endian_short_map;
     393             :                                 }
     394             : 
     395         285 :                                 while (arg-- > 0) {
     396          95 :                                         php_pack(argv[currentarg++], 2, map, &output[outputpos]);
     397          95 :                                         outputpos += 2;
     398             :                                 }
     399          95 :                                 break;
     400             :                         }
     401             : 
     402             :                         case 'i':
     403             :                         case 'I':
     404          21 :                                 while (arg-- > 0) {
     405           7 :                                         php_pack(argv[currentarg++], sizeof(int), int_map, &output[outputpos]);
     406           7 :                                         outputpos += sizeof(int);
     407             :                                 }
     408           7 :                                 break;
     409             : 
     410             :                         case 'l':
     411             :                         case 'L':
     412             :                         case 'N':
     413             :                         case 'V': {
     414       10710 :                                 int *map = machine_endian_long_map;
     415             : 
     416       10710 :                                 if (code == 'N') {
     417        8261 :                                         map = big_endian_long_map;
     418        2449 :                                 } else if (code == 'V') {
     419        2447 :                                         map = little_endian_long_map;
     420             :                                 }
     421             : 
     422       32130 :                                 while (arg-- > 0) {
     423       10710 :                                         php_pack(argv[currentarg++], 4, map, &output[outputpos]);
     424       10710 :                                         outputpos += 4;
     425             :                                 }
     426       10710 :                                 break;
     427             :                         }
     428             : 
     429             :                         case 'f': {
     430             :                                 float v;
     431             : 
     432           0 :                                 while (arg-- > 0) {
     433           0 :                                         val = argv[currentarg++];
     434           0 :                                         convert_to_double_ex(val);
     435           0 :                                         v = (float) Z_DVAL_PP(val);
     436           0 :                                         memcpy(&output[outputpos], &v, sizeof(v));
     437           0 :                                         outputpos += sizeof(v);
     438             :                                 }
     439           0 :                                 break;
     440             :                         }
     441             : 
     442             :                         case 'd': {
     443             :                                 double v;
     444             : 
     445          39 :                                 while (arg-- > 0) {
     446          13 :                                         val = argv[currentarg++];
     447          13 :                                         convert_to_double_ex(val);
     448          13 :                                         v = (double) Z_DVAL_PP(val);
     449          13 :                                         memcpy(&output[outputpos], &v, sizeof(v));
     450          13 :                                         outputpos += sizeof(v);
     451             :                                 }
     452          13 :                                 break;
     453             :                         }
     454             : 
     455             :                         case 'x':
     456           0 :                                 memset(&output[outputpos], '\0', arg);
     457           0 :                                 outputpos += arg;
     458           0 :                                 break;
     459             : 
     460             :                         case 'X':
     461           0 :                                 outputpos -= arg;
     462             : 
     463           0 :                                 if (outputpos < 0) {
     464           0 :                                         outputpos = 0;
     465             :                                 }
     466           0 :                                 break;
     467             : 
     468             :                         case '@':
     469           0 :                                 if (arg > outputpos) {
     470           0 :                                         memset(&output[outputpos], '\0', arg - outputpos);
     471             :                                 }
     472           0 :                                 outputpos = arg;
     473             :                                 break;
     474             :                 }
     475             :         }
     476             : 
     477      153371 :         efree(argv);
     478      153371 :         efree(formatcodes);
     479      153371 :         efree(formatargs);
     480      153371 :         output[outputpos] = '\0';
     481      153371 :         RETVAL_STRINGL(output, outputpos, 1);
     482      153371 :         efree(output);
     483             : }
     484             : /* }}} */
     485             : 
     486             : /* {{{ php_unpack
     487             :  */
     488          17 : static long php_unpack(char *data, int size, int issigned, int *map)
     489             : {
     490             :         long result;
     491          17 :         char *cresult = (char *) &result;
     492             :         int i;
     493             : 
     494          17 :         result = issigned ? -1 : 0;
     495             : 
     496          77 :         for (i = 0; i < size; i++) {
     497          60 :                 cresult[map[i]] = *data++;
     498             :         }
     499             : 
     500          17 :         return result;
     501             : }
     502             : /* }}} */
     503             : 
     504             : /* unpack() is based on Perl's unpack(), but is modified a bit from there.
     505             :  * Rather than depending on error-prone ordered lists or syntactically
     506             :  * unpleasant pass-by-reference, we return an object with named parameters
     507             :  * (like *_fetch_object()). Syntax is "f[repeat]name/...", where "f" is the
     508             :  * formatter char (like pack()), "[repeat]" is the optional repeater argument,
     509             :  * and "name" is the name of the variable to use.
     510             :  * Example: "c2chars/nints" will return an object with fields
     511             :  * chars1, chars2, and ints.
     512             :  * Numeric pack types will return numbers, a and A will return strings,
     513             :  * f and d will return doubles.
     514             :  * Implemented formats are A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
     515             :  */
     516             : /* {{{ proto array unpack(string format, string input)
     517             :    Unpack binary string into named array elements according to format argument */
     518        1014 : PHP_FUNCTION(unpack)
     519             : {
     520             :         char *format, *input, *formatarg, *inputarg;
     521             :         int formatlen, formatarg_len, inputarg_len;
     522             :         int inputpos, inputlen, i;
     523             : 
     524        1014 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &formatarg, &formatarg_len,
     525             :                 &inputarg, &inputarg_len) == FAILURE) {
     526           2 :                 return;
     527             :         }
     528             : 
     529        1012 :         format = formatarg;
     530        1012 :         formatlen = formatarg_len;
     531        1012 :         input = inputarg;
     532        1012 :         inputlen = inputarg_len;
     533        1012 :         inputpos = 0;
     534             : 
     535        1012 :         array_init(return_value);
     536             : 
     537        3033 :         while (formatlen-- > 0) {
     538        1012 :                 char type = *(format++);
     539             :                 char c;
     540        1012 :                 int arg = 1, argb;
     541             :                 char *name;
     542             :                 int namelen;
     543        1012 :                 int size=0;
     544             : 
     545             :                 /* Handle format arguments if any */
     546        1012 :                 if (formatlen > 0) {
     547         993 :                         c = *format;
     548             : 
     549        1008 :                         if (c >= '0' && c <= '9') {
     550          15 :                                 arg = atoi(format);
     551             : 
     552          57 :                                 while (formatlen > 0 && *format >= '0' && *format <= '9') {
     553          27 :                                         format++;
     554          27 :                                         formatlen--;
     555             :                                 }
     556         978 :                         } else if (c == '*') {
     557         971 :                                 arg = -1;
     558         971 :                                 format++;
     559         971 :                                 formatlen--;
     560             :                         }
     561             :                 }
     562             : 
     563             :                 /* Get of new value in array */
     564        1012 :                 name = format;
     565        1012 :                 argb = arg;
     566             : 
     567        2031 :                 while (formatlen > 0 && *format != '/') {
     568           7 :                         formatlen--;
     569           7 :                         format++;
     570             :                 }
     571             : 
     572        1012 :                 namelen = format - name;
     573             : 
     574        1012 :                 if (namelen > 200)
     575           0 :                         namelen = 200;
     576             : 
     577        1012 :                 switch ((int) type) {
     578             :                         /* Never use any input */
     579             :                         case 'X':
     580           0 :                                 size = -1;
     581           0 :                                 break;
     582             : 
     583             :                         case '@':
     584           0 :                                 size = 0;
     585           0 :                                 break;
     586             : 
     587             :                         case 'a':
     588             :                         case 'A':
     589           0 :                                 size = arg;
     590           0 :                                 arg = 1;
     591           0 :                                 break;
     592             : 
     593             :                         case 'h':
     594             :                         case 'H':
     595         984 :                                 size = (arg > 0) ? (arg + (arg % 2)) / 2 : arg;
     596         984 :                                 arg = 1;
     597         984 :                                 break;
     598             : 
     599             :                         /* Use 1 byte of input */
     600             :                         case 'c':
     601             :                         case 'C':
     602             :                         case 'x':
     603           1 :                                 size = 1;
     604           1 :                                 break;
     605             : 
     606             :                         /* Use 2 bytes of input */
     607             :                         case 's':
     608             :                         case 'S':
     609             :                         case 'n':
     610             :                         case 'v':
     611           1 :                                 size = 2;
     612           1 :                                 break;
     613             : 
     614             :                         /* Use sizeof(int) bytes of input */
     615             :                         case 'i':
     616             :                         case 'I':
     617           1 :                                 size = sizeof(int);
     618           1 :                                 break;
     619             : 
     620             :                         /* Use 4 bytes of input */
     621             :                         case 'l':
     622             :                         case 'L':
     623             :                         case 'N':
     624             :                         case 'V':
     625          10 :                                 size = 4;
     626          10 :                                 break;
     627             : 
     628             :                         /* Use sizeof(float) bytes of input */
     629             :                         case 'f':
     630           0 :                                 size = sizeof(float);
     631           0 :                                 break;
     632             : 
     633             :                         /* Use sizeof(double) bytes of input */
     634             :                         case 'd':
     635          13 :                                 size = sizeof(double);
     636          13 :                                 break;
     637             : 
     638             :                         default:
     639           2 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid format type %c", type);
     640             :                                 zval_dtor(return_value);
     641           2 :                                 RETURN_FALSE;
     642             :                                 break;
     643             :                 }
     644             : 
     645        1010 :                 if (size != 0 && size != -1 && size < 0) {
     646           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow", type);
     647             :                         zval_dtor(return_value);
     648           1 :                         RETURN_FALSE;
     649             :                 }
     650             : 
     651             :                 /* Do actual unpacking */
     652        2022 :                 for (i = 0; i != arg; i++ ) {
     653             :                         /* Space for name + number, safe as namelen is ensured <= 200 */
     654             :                         char n[256];
     655             : 
     656        2021 :                         if (arg != 1 || namelen == 0) {
     657             :                                 /* Need to add element number to name */
     658        1007 :                                 snprintf(n, sizeof(n), "%.*s%d", namelen, name, i + 1);
     659             :                         } else {
     660             :                                 /* Truncate name to next format code or end of string */
     661           7 :                                 snprintf(n, sizeof(n), "%.*s", namelen, name);
     662             :                         }
     663             : 
     664        1014 :                         if (size != 0 && size != -1 && INT_MAX - size + 1 < inputpos) {
     665           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow", type);
     666             :                                 zval_dtor(return_value);
     667           0 :                                 RETURN_FALSE;
     668             :                         }
     669             : 
     670        1014 :                         if ((inputpos + size) <= inputlen) {
     671        1013 :                                 switch ((int) type) {
     672             :                                         case 'a':
     673             :                                         case 'A': {
     674           0 :                                                 char pad = (type == 'a') ? '\0' : ' ';
     675           0 :                                                 int len = inputlen - inputpos;  /* Remaining string */
     676             : 
     677             :                                                 /* If size was given take minimum of len and size */
     678           0 :                                                 if ((size >= 0) && (len > size)) {
     679           0 :                                                         len = size;
     680             :                                                 }
     681             : 
     682           0 :                                                 size = len;
     683             : 
     684             :                                                 /* Remove padding chars from unpacked data */
     685           0 :                                                 while (--len >= 0) {
     686           0 :                                                         if (input[inputpos + len] != pad)
     687           0 :                                                                 break;
     688             :                                                 }
     689             : 
     690           0 :                                                 add_assoc_stringl(return_value, n, &input[inputpos], len + 1, 1);
     691           0 :                                                 break;
     692             :                                         }
     693             : 
     694             :                                         case 'h':
     695             :                                         case 'H': {
     696         983 :                                                 int len = (inputlen - inputpos) * 2;    /* Remaining */
     697         983 :                                                 int nibbleshift = (type == 'h') ? 0 : 4;
     698         983 :                                                 int first = 1;
     699             :                                                 char *buf;
     700             :                                                 int ipos, opos;
     701             : 
     702             :                                                 /* If size was given take minimum of len and size */
     703         983 :                                                 if (size >= 0 && len > (size * 2)) {
     704           0 :                                                         len = size * 2;
     705             :                                                 }
     706             : 
     707         983 :                                                 if (len > 0 && argb > 0) {
     708          13 :                                                         len -= argb % 2;
     709             :                                                 }
     710             : 
     711         983 :                                                 buf = emalloc(len + 1);
     712             : 
     713        3459 :                                                 for (ipos = opos = 0; opos < len; opos++) {
     714        2476 :                                                         char cc = (input[inputpos + ipos] >> nibbleshift) & 0xf;
     715             : 
     716        2476 :                                                         if (cc < 10) {
     717        1261 :                                                                 cc += '0';
     718             :                                                         } else {
     719        1215 :                                                                 cc += 'a' - 10;
     720             :                                                         }
     721             : 
     722        2476 :                                                         buf[opos] = cc;
     723        2476 :                                                         nibbleshift = (nibbleshift + 4) & 7;
     724             : 
     725        2476 :                                                         if (first-- == 0) {
     726        1237 :                                                                 ipos++;
     727        1237 :                                                                 first = 1;
     728             :                                                         }
     729             :                                                 }
     730             : 
     731         983 :                                                 buf[len] = '\0';
     732         983 :                                                 add_assoc_stringl(return_value, n, buf, len, 1);
     733         983 :                                                 efree(buf);
     734         983 :                                                 break;
     735             :                                         }
     736             : 
     737             :                                         case 'c':
     738             :                                         case 'C': {
     739           2 :                                                 int issigned = (type == 'c') ? (input[inputpos] & 0x80) : 0;
     740           2 :                                                 long v = php_unpack(&input[inputpos], 1, issigned, byte_map);
     741           2 :                                                 add_assoc_long(return_value, n, v);
     742           2 :                                                 break;
     743             :                                         }
     744             : 
     745             :                                         case 's':
     746             :                                         case 'S':
     747             :                                         case 'n':
     748             :                                         case 'v': {
     749             :                                                 long v;
     750           1 :                                                 int issigned = 0;
     751           1 :                                                 int *map = machine_endian_short_map;
     752             : 
     753           1 :                                                 if (type == 's') {
     754           0 :                                                         issigned = input[inputpos + (machine_little_endian ? 1 : 0)] & 0x80;
     755           1 :                                                 } else if (type == 'n') {
     756           0 :                                                         map = big_endian_short_map;
     757           1 :                                                 } else if (type == 'v') {
     758           1 :                                                         map = little_endian_short_map;
     759             :                                                 }
     760             : 
     761           1 :                                                 v = php_unpack(&input[inputpos], 2, issigned, map);
     762           1 :                                                 add_assoc_long(return_value, n, v);
     763           1 :                                                 break;
     764             :                                         }
     765             : 
     766             :                                         case 'i':
     767             :                                         case 'I': {
     768             :                                                 long v;
     769           1 :                                                 int issigned = 0;
     770             : 
     771           1 :                                                 if (type == 'i') {
     772           0 :                                                         issigned = input[inputpos + (machine_little_endian ? (sizeof(int) - 1) : 0)] & 0x80;
     773             :                                                 }
     774             : 
     775           1 :                                                 v = php_unpack(&input[inputpos], sizeof(int), issigned, int_map);
     776           1 :                                                 add_assoc_long(return_value, n, v);
     777           1 :                                                 break;
     778             :                                         }
     779             : 
     780             :                                         case 'l':
     781             :                                         case 'L':
     782             :                                         case 'N':
     783             :                                         case 'V': {
     784          13 :                                                 int issigned = 0;
     785          13 :                                                 int *map = machine_endian_long_map;
     786          13 :                                                 long v = 0;
     787             : 
     788          14 :                                                 if (type == 'l' || type == 'L') {
     789           1 :                                                         issigned = input[inputpos + (machine_little_endian ? 3 : 0)] & 0x80;
     790          12 :                                                 } else if (type == 'N') {
     791           8 :                                                         issigned = input[inputpos] & 0x80;
     792           8 :                                                         map = big_endian_long_map;
     793           4 :                                                 } else if (type == 'V') {
     794           4 :                                                         issigned = input[inputpos + 3] & 0x80;
     795           4 :                                                         map = little_endian_long_map;
     796             :                                                 }
     797             : 
     798          13 :                                                 if (sizeof(long) > 4 && issigned) {
     799           2 :                                                         v = ~INT_MAX;
     800             :                                                 }
     801             : 
     802          13 :                                                 v |= php_unpack(&input[inputpos], 4, issigned, map);
     803             :                                                 if (sizeof(long) > 4) {
     804          13 :                                                         if (type == 'l') {
     805           1 :                                                                 v = (signed int) v;
     806             :                                                         } else {
     807          12 :                                                                 v = (unsigned int) v;
     808             :                                                         }
     809             :                                                 }
     810          13 :                                                 add_assoc_long(return_value, n, v);
     811          13 :                                                 break;
     812             :                                         }
     813             : 
     814             :                                         case 'f': {
     815             :                                                 float v;
     816             : 
     817           0 :                                                 memcpy(&v, &input[inputpos], sizeof(float));
     818           0 :                                                 add_assoc_double(return_value, n, (double)v);
     819           0 :                                                 break;
     820             :                                         }
     821             : 
     822             :                                         case 'd': {
     823             :                                                 double v;
     824             : 
     825          13 :                                                 memcpy(&v, &input[inputpos], sizeof(double));
     826          13 :                                                 add_assoc_double(return_value, n, v);
     827          13 :                                                 break;
     828             :                                         }
     829             : 
     830             :                                         case 'x':
     831             :                                                 /* Do nothing with input, just skip it */
     832           0 :                                                 break;
     833             : 
     834             :                                         case 'X':
     835           0 :                                                 if (inputpos < size) {
     836           0 :                                                         inputpos = -size;
     837           0 :                                                         i = arg - 1;            /* Break out of for loop */
     838             : 
     839           0 :                                                         if (arg >= 0) {
     840           0 :                                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
     841             :                                                         }
     842             :                                                 }
     843           0 :                                                 break;
     844             : 
     845             :                                         case '@':
     846           0 :                                                 if (arg <= inputlen) {
     847           0 :                                                         inputpos = arg;
     848             :                                                 } else {
     849           0 :                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
     850             :                                                 }
     851             : 
     852           0 :                                                 i = arg - 1;    /* Done, break out of for loop */
     853             :                                                 break;
     854             :                                 }
     855             : 
     856        1013 :                                 inputpos += size;
     857        1013 :                                 if (inputpos < 0) {
     858         970 :                                         if (size != -1) { /* only print warning if not working with * */
     859           0 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
     860             :                                         }
     861         970 :                                         inputpos = 0;
     862             :                                 }
     863           1 :                         } else if (arg < 0) {
     864             :                                 /* Reached end of input for '*' repeater */
     865           1 :                                 break;
     866             :                         } else {
     867           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough input, need %d, have %d", type, size, inputlen - inputpos);
     868             :                                 zval_dtor(return_value);
     869           0 :                                 RETURN_FALSE;
     870             :                         }
     871             :                 }
     872             : 
     873        1009 :                 formatlen--;    /* Skip '/' separator, does no harm if inputlen == 0 */
     874        1009 :                 format++;
     875             :         }
     876             : }
     877             : /* }}} */
     878             : 
     879             : /* {{{ PHP_MINIT_FUNCTION
     880             :  */
     881       20266 : PHP_MINIT_FUNCTION(pack)
     882             : {
     883       20266 :         int machine_endian_check = 1;
     884             :         int i;
     885             : 
     886       20266 :         machine_little_endian = ((char *)&machine_endian_check)[0];
     887             : 
     888       20266 :         if (machine_little_endian) {
     889             :                 /* Where to get lo to hi bytes from */
     890       20266 :                 byte_map[0] = 0;
     891             : 
     892      101330 :                 for (i = 0; i < (int)sizeof(int); i++) {
     893       81064 :                         int_map[i] = i;
     894             :                 }
     895             : 
     896       20266 :                 machine_endian_short_map[0] = 0;
     897       20266 :                 machine_endian_short_map[1] = 1;
     898       20266 :                 big_endian_short_map[0] = 1;
     899       20266 :                 big_endian_short_map[1] = 0;
     900       20266 :                 little_endian_short_map[0] = 0;
     901       20266 :                 little_endian_short_map[1] = 1;
     902             : 
     903       20266 :                 machine_endian_long_map[0] = 0;
     904       20266 :                 machine_endian_long_map[1] = 1;
     905       20266 :                 machine_endian_long_map[2] = 2;
     906       20266 :                 machine_endian_long_map[3] = 3;
     907       20266 :                 big_endian_long_map[0] = 3;
     908       20266 :                 big_endian_long_map[1] = 2;
     909       20266 :                 big_endian_long_map[2] = 1;
     910       20266 :                 big_endian_long_map[3] = 0;
     911       20266 :                 little_endian_long_map[0] = 0;
     912       20266 :                 little_endian_long_map[1] = 1;
     913       20266 :                 little_endian_long_map[2] = 2;
     914       20266 :                 little_endian_long_map[3] = 3;
     915             :         }
     916             :         else {
     917             :                 zval val;
     918           0 :                 int size = sizeof(Z_LVAL(val));
     919           0 :                 Z_LVAL(val)=0; /*silence a warning*/
     920             : 
     921             :                 /* Where to get hi to lo bytes from */
     922           0 :                 byte_map[0] = size - 1;
     923             : 
     924           0 :                 for (i = 0; i < (int)sizeof(int); i++) {
     925           0 :                         int_map[i] = size - (sizeof(int) - i);
     926             :                 }
     927             : 
     928           0 :                 machine_endian_short_map[0] = size - 2;
     929           0 :                 machine_endian_short_map[1] = size - 1;
     930           0 :                 big_endian_short_map[0] = size - 2;
     931           0 :                 big_endian_short_map[1] = size - 1;
     932           0 :                 little_endian_short_map[0] = size - 1;
     933           0 :                 little_endian_short_map[1] = size - 2;
     934             : 
     935           0 :                 machine_endian_long_map[0] = size - 4;
     936           0 :                 machine_endian_long_map[1] = size - 3;
     937           0 :                 machine_endian_long_map[2] = size - 2;
     938           0 :                 machine_endian_long_map[3] = size - 1;
     939           0 :                 big_endian_long_map[0] = size - 4;
     940           0 :                 big_endian_long_map[1] = size - 3;
     941           0 :                 big_endian_long_map[2] = size - 2;
     942           0 :                 big_endian_long_map[3] = size - 1;
     943           0 :                 little_endian_long_map[0] = size - 1;
     944           0 :                 little_endian_long_map[1] = size - 2;
     945           0 :                 little_endian_long_map[2] = size - 3;
     946           0 :                 little_endian_long_map[3] = size - 4;
     947             :         }
     948             : 
     949       20266 :         return SUCCESS;
     950             : }
     951             : /* }}} */
     952             : 
     953             : /*
     954             :  * Local variables:
     955             :  * tab-width: 4
     956             :  * c-basic-offset: 4
     957             :  * End:
     958             :  * vim600: noet sw=4 ts=4 fdm=marker
     959             :  * vim<600: noet sw=4 ts=4
     960             :  */

Generated by: LCOV version 1.10

Generated at Sun, 17 May 2015 16:25:18 +0000 (5 days ago)

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