LTP GCOV extension - code coverage report
Current view: directory - ext/standard - pack.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 407
Code covered: 6.4 % Executed lines: 26
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5