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

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:37 +0000 (6 days ago)

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