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-23 Instrumented lines: 397
Code covered: 71.0 % Executed lines: 282
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:40 +0000 (33 hours ago)

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