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

LTP GCOV extension - code coverage report
Current view: directory - standard - pack.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 411
Code covered: 71.0 % Executed lines: 292
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:24 +0000 (5 days ago)

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