Back to index

php5  5.3.10
pack.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Chris Schneider <cschneid@relog.ch>                          |
00016    +----------------------------------------------------------------------+
00017  */
00018 /* $Id: pack.c 321634 2012-01-01 13:15:04Z felipe $ */
00019 
00020 #include "php.h"
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <errno.h>
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <fcntl.h>
00028 #ifdef PHP_WIN32
00029 #define O_RDONLY _O_RDONLY
00030 #include "win32/param.h"
00031 #elif defined(NETWARE)
00032 #ifdef USE_WINSOCK
00033 #include <novsock2.h>
00034 #else
00035 #include <sys/socket.h>
00036 #endif
00037 #include <sys/param.h>
00038 #else
00039 #include <sys/param.h>
00040 #endif
00041 #include "ext/standard/head.h"
00042 #include "safe_mode.h"
00043 #include "php_string.h"
00044 #include "pack.h"
00045 #if HAVE_PWD_H
00046 #ifdef PHP_WIN32
00047 #include "win32/pwd.h"
00048 #else
00049 #include <pwd.h>
00050 #endif
00051 #endif
00052 #include "fsock.h"
00053 #if HAVE_NETINET_IN_H
00054 #include <netinet/in.h>
00055 #endif
00056 
00057 #define INC_OUTPUTPOS(a,b) \
00058        if ((a) < 0 || ((INT_MAX - outputpos)/((int)b)) < (a)) { \
00059               efree(argv);  \
00060               efree(formatcodes);  \
00061               efree(formatargs);   \
00062               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow in format string", code); \
00063               RETURN_FALSE; \
00064        } \
00065        outputpos += (a)*(b);
00066 
00067 /* Whether machine is little endian */
00068 char machine_little_endian;
00069 
00070 /* Mapping of byte from char (8bit) to long for machine endian */
00071 static int byte_map[1];
00072 
00073 /* Mappings of bytes from int (machine dependant) to int for machine endian */
00074 static int int_map[sizeof(int)];
00075 
00076 /* Mappings of bytes from shorts (16bit) for all endian environments */
00077 static int machine_endian_short_map[2];
00078 static int big_endian_short_map[2];
00079 static int little_endian_short_map[2];
00080 
00081 /* Mappings of bytes from longs (32bit) for all endian environments */
00082 static int machine_endian_long_map[4];
00083 static int big_endian_long_map[4];
00084 static int little_endian_long_map[4];
00085 
00086 /* {{{ php_pack
00087  */
00088 static void php_pack(zval **val, int size, int *map, char *output)
00089 {
00090        int i;
00091        char *v;
00092 
00093        convert_to_long_ex(val);
00094        v = (char *) &Z_LVAL_PP(val);
00095 
00096        for (i = 0; i < size; i++) {
00097               *output++ = v[map[i]];
00098        }
00099 }
00100 /* }}} */
00101 
00102 /* pack() idea stolen from Perl (implemented formats behave the same as there)
00103  * Implemented formats are A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
00104  */
00105 /* {{{ proto string pack(string format, mixed arg1 [, mixed arg2 [, mixed ...]])
00106    Takes one or more arguments and packs them into a binary string according to the format argument */
00107 PHP_FUNCTION(pack)
00108 {
00109        zval ***argv = NULL;
00110        int num_args, i;
00111        int currentarg;
00112        char *format;
00113        int formatlen;
00114        char *formatcodes;
00115        int *formatargs;
00116        int formatcount = 0;
00117        int outputpos = 0, outputsize = 0;
00118        char *output;
00119 
00120        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &argv, &num_args) == FAILURE) {
00121               return;
00122        }
00123 
00124        if (Z_ISREF_PP(argv[0])) {
00125               SEPARATE_ZVAL(argv[0]);
00126        }
00127        convert_to_string_ex(argv[0]);
00128 
00129        format = Z_STRVAL_PP(argv[0]);
00130        formatlen = Z_STRLEN_PP(argv[0]);
00131 
00132        /* We have a maximum of <formatlen> format codes to deal with */
00133        formatcodes = safe_emalloc(formatlen, sizeof(*formatcodes), 0);
00134        formatargs = safe_emalloc(formatlen, sizeof(*formatargs), 0);
00135        currentarg = 1;
00136 
00137        /* Preprocess format into formatcodes and formatargs */
00138        for (i = 0; i < formatlen; formatcount++) {
00139               char code = format[i++];
00140               int arg = 1;
00141 
00142               /* Handle format arguments if any */
00143               if (i < formatlen) {
00144                      char c = format[i];
00145 
00146                      if (c == '*') {
00147                             arg = -1;
00148                             i++;
00149                      }
00150                      else if (c >= '0' && c <= '9') {
00151                             arg = atoi(&format[i]);
00152                 
00153                             while (format[i] >= '0' && format[i] <= '9' && i < formatlen) {
00154                                    i++;
00155                             }
00156                      }
00157               }
00158 
00159               /* Handle special arg '*' for all codes and check argv overflows */
00160               switch ((int) code) {
00161                      /* Never uses any args */
00162                      case 'x': 
00163                      case 'X':     
00164                      case '@':
00165                             if (arg < 0) {
00166                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: '*' ignored", code);
00167                                    arg = 1;
00168                             }
00169                             break;
00170 
00171                      /* Always uses one arg */
00172                      case 'a': 
00173                      case 'A': 
00174                      case 'h': 
00175                      case 'H':
00176                             if (currentarg >= num_args) {
00177                                    efree(argv);
00178                                    efree(formatcodes);
00179                                    efree(formatargs);
00180                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough arguments", code);
00181                                    RETURN_FALSE;
00182                             }
00183 
00184                             if (arg < 0) {
00185                                    if (Z_ISREF_PP(argv[currentarg])) {
00186                                           SEPARATE_ZVAL(argv[currentarg]);
00187                                    }
00188                                    convert_to_string_ex(argv[currentarg]);
00189                                    arg = Z_STRLEN_PP(argv[currentarg]);
00190                             }
00191 
00192                             currentarg++;
00193                             break;
00194 
00195                      /* Use as many args as specified */
00196                      case 'c': 
00197                      case 'C': 
00198                      case 's': 
00199                      case 'S': 
00200                      case 'i': 
00201                      case 'I':
00202                      case 'l': 
00203                      case 'L': 
00204                      case 'n': 
00205                      case 'N': 
00206                      case 'v': 
00207                      case 'V':
00208                      case 'f': 
00209                      case 'd': 
00210                             if (arg < 0) {
00211                                    arg = num_args - currentarg;
00212                             }
00213 
00214                             currentarg += arg;
00215 
00216                             if (currentarg > num_args) {
00217                                    efree(argv);
00218                                    efree(formatcodes);
00219                                    efree(formatargs);
00220                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: too few arguments", code);
00221                                    RETURN_FALSE;
00222                             }
00223                             break;
00224 
00225                      default:
00226                             efree(argv);
00227                             efree(formatcodes);
00228                             efree(formatargs);
00229                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: unknown format code", code);
00230                             RETURN_FALSE;
00231               }
00232 
00233               formatcodes[formatcount] = code;
00234               formatargs[formatcount] = arg;
00235        }
00236 
00237        if (currentarg < num_args) {
00238               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d arguments unused", (num_args - currentarg));
00239        }
00240 
00241        /* Calculate output length and upper bound while processing*/
00242        for (i = 0; i < formatcount; i++) {
00243            int code = (int) formatcodes[i];
00244               int arg = formatargs[i];
00245 
00246               switch ((int) code) {
00247                      case 'h': 
00248                      case 'H': 
00249                             INC_OUTPUTPOS((arg + (arg % 2)) / 2,1)    /* 4 bit per arg */
00250                             break;
00251 
00252                      case 'a': 
00253                      case 'A':
00254                      case 'c': 
00255                      case 'C':
00256                      case 'x':
00257                             INC_OUTPUTPOS(arg,1)        /* 8 bit per arg */
00258                             break;
00259 
00260                      case 's': 
00261                      case 'S': 
00262                      case 'n': 
00263                      case 'v':
00264                             INC_OUTPUTPOS(arg,2)        /* 16 bit per arg */
00265                             break;
00266 
00267                      case 'i': 
00268                      case 'I':
00269                             INC_OUTPUTPOS(arg,sizeof(int))
00270                             break;
00271 
00272                      case 'l': 
00273                      case 'L': 
00274                      case 'N': 
00275                      case 'V':
00276                             INC_OUTPUTPOS(arg,4)        /* 32 bit per arg */
00277                             break;
00278 
00279                      case 'f':
00280                             INC_OUTPUTPOS(arg,sizeof(float))
00281                             break;
00282 
00283                      case 'd':
00284                             INC_OUTPUTPOS(arg,sizeof(double))
00285                             break;
00286 
00287                      case 'X':
00288                             outputpos -= arg;
00289 
00290                             if (outputpos < 0) {
00291                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", code);
00292                                    outputpos = 0;
00293                             }
00294                             break;
00295 
00296                      case '@':
00297                             outputpos = arg;
00298                             break;
00299               }
00300 
00301               if (outputsize < outputpos) {
00302                      outputsize = outputpos;
00303               }
00304        }
00305 
00306        output = emalloc(outputsize + 1);
00307        outputpos = 0;
00308        currentarg = 1;
00309 
00310        /* Do actual packing */
00311        for (i = 0; i < formatcount; i++) {
00312            int code = (int) formatcodes[i];
00313               int arg = formatargs[i];
00314               zval **val;
00315 
00316               switch ((int) code) {
00317                      case 'a': 
00318                      case 'A': 
00319                             memset(&output[outputpos], (code == 'a') ? '\0' : ' ', arg);
00320                             val = argv[currentarg++];
00321                             if (Z_ISREF_PP(val)) {
00322                                    SEPARATE_ZVAL(val);
00323                             }
00324                             convert_to_string_ex(val);
00325                             memcpy(&output[outputpos], Z_STRVAL_PP(val),
00326                                       (Z_STRLEN_PP(val) < arg) ? Z_STRLEN_PP(val) : arg);
00327                             outputpos += arg;
00328                             break;
00329 
00330                      case 'h': 
00331                      case 'H': {
00332                             int nibbleshift = (code == 'h') ? 0 : 4;
00333                             int first = 1;
00334                             char *v;
00335 
00336                             val = argv[currentarg++];
00337                             if (Z_ISREF_PP(val)) {
00338                                    SEPARATE_ZVAL(val);
00339                             }
00340                             convert_to_string_ex(val);
00341                             v = Z_STRVAL_PP(val);
00342                             outputpos--;
00343                             if(arg > Z_STRLEN_PP(val)) {
00344                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough characters in string", code);
00345                                    arg = Z_STRLEN_PP(val);
00346                             }
00347 
00348                             while (arg-- > 0) {
00349                                    char n = *v++;
00350 
00351                                    if (n >= '0' && n <= '9') {
00352                                           n -= '0';
00353                                    } else if (n >= 'A' && n <= 'F') {
00354                                           n -= ('A' - 10);
00355                                    } else if (n >= 'a' && n <= 'f') {
00356                                           n -= ('a' - 10);
00357                                    } else {
00358                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: illegal hex digit %c", code, n);
00359                                           n = 0;
00360                                    }
00361 
00362                                    if (first--) {
00363                                           output[++outputpos] = 0;
00364                                    } else {
00365                                      first = 1;
00366                                    }
00367 
00368                                    output[outputpos] |= (n << nibbleshift);
00369                                    nibbleshift = (nibbleshift + 4) & 7;
00370                             }
00371 
00372                             outputpos++;
00373                             break;
00374                      }
00375 
00376                      case 'c': 
00377                      case 'C':
00378                             while (arg-- > 0) {
00379                                    php_pack(argv[currentarg++], 1, byte_map, &output[outputpos]);
00380                                    outputpos++;
00381                             }
00382                             break;
00383 
00384                      case 's': 
00385                      case 'S': 
00386                      case 'n': 
00387                      case 'v': {
00388                             int *map = machine_endian_short_map;
00389 
00390                             if (code == 'n') {
00391                                    map = big_endian_short_map;
00392                             } else if (code == 'v') {
00393                                    map = little_endian_short_map;
00394                             }
00395 
00396                             while (arg-- > 0) {
00397                                    php_pack(argv[currentarg++], 2, map, &output[outputpos]);
00398                                    outputpos += 2;
00399                             }
00400                             break;
00401                      }
00402 
00403                      case 'i': 
00404                      case 'I': 
00405                             while (arg-- > 0) {
00406                                    php_pack(argv[currentarg++], sizeof(int), int_map, &output[outputpos]);
00407                                    outputpos += sizeof(int);
00408                             }
00409                             break;
00410 
00411                      case 'l': 
00412                      case 'L': 
00413                      case 'N': 
00414                      case 'V': {
00415                             int *map = machine_endian_long_map;
00416 
00417                             if (code == 'N') {
00418                                    map = big_endian_long_map;
00419                             } else if (code == 'V') {
00420                                    map = little_endian_long_map;
00421                             }
00422 
00423                             while (arg-- > 0) {
00424                                    php_pack(argv[currentarg++], 4, map, &output[outputpos]);
00425                                    outputpos += 4;
00426                             }
00427                             break;
00428                      }
00429 
00430                      case 'f': {
00431                             float v;
00432 
00433                             while (arg-- > 0) {
00434                                    val = argv[currentarg++];
00435                                    convert_to_double_ex(val);
00436                                    v = (float) Z_DVAL_PP(val);
00437                                    memcpy(&output[outputpos], &v, sizeof(v));
00438                                    outputpos += sizeof(v);
00439                             }
00440                             break;
00441                      }
00442 
00443                      case 'd': {
00444                             double v;
00445 
00446                             while (arg-- > 0) {
00447                                    val = argv[currentarg++];
00448                                    convert_to_double_ex(val);
00449                                    v = (double) Z_DVAL_PP(val);
00450                                    memcpy(&output[outputpos], &v, sizeof(v));
00451                                    outputpos += sizeof(v);
00452                             }
00453                             break;
00454                      }
00455 
00456                      case 'x':
00457                             memset(&output[outputpos], '\0', arg);
00458                             outputpos += arg;
00459                             break;
00460 
00461                      case 'X':
00462                             outputpos -= arg;
00463 
00464                             if (outputpos < 0) {
00465                                    outputpos = 0;
00466                             }
00467                             break;
00468 
00469                      case '@':
00470                             if (arg > outputpos) {
00471                                    memset(&output[outputpos], '\0', arg - outputpos);
00472                             }
00473                             outputpos = arg;
00474                             break;
00475               }
00476        }
00477 
00478        efree(argv);
00479        efree(formatcodes);
00480        efree(formatargs);
00481        output[outputpos] = '\0';
00482        RETVAL_STRINGL(output, outputpos, 1);
00483        efree(output);
00484 }
00485 /* }}} */
00486 
00487 /* {{{ php_unpack
00488  */
00489 static long php_unpack(char *data, int size, int issigned, int *map)
00490 {
00491        long result;
00492        char *cresult = (char *) &result;
00493        int i;
00494 
00495        result = issigned ? -1 : 0;
00496 
00497        for (i = 0; i < size; i++) {
00498               cresult[map[i]] = *data++;
00499        }
00500 
00501        return result;
00502 }
00503 /* }}} */
00504 
00505 /* unpack() is based on Perl's unpack(), but is modified a bit from there.
00506  * Rather than depending on error-prone ordered lists or syntactically
00507  * unpleasant pass-by-reference, we return an object with named paramters 
00508  * (like *_fetch_object()). Syntax is "f[repeat]name/...", where "f" is the
00509  * formatter char (like pack()), "[repeat]" is the optional repeater argument,
00510  * and "name" is the name of the variable to use.
00511  * Example: "c2chars/nints" will return an object with fields
00512  * chars1, chars2, and ints.
00513  * Numeric pack types will return numbers, a and A will return strings,
00514  * f and d will return doubles.
00515  * Implemented formats are A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @.
00516  */
00517 /* {{{ proto array unpack(string format, string input)
00518    Unpack binary string into named array elements according to format argument */
00519 PHP_FUNCTION(unpack)
00520 {
00521        char *format, *input, *formatarg, *inputarg;
00522        int formatlen, formatarg_len, inputarg_len;
00523        int inputpos, inputlen, i;
00524 
00525        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &formatarg, &formatarg_len,
00526               &inputarg, &inputarg_len) == FAILURE) {
00527               return;
00528        }
00529 
00530        format = formatarg;
00531        formatlen = formatarg_len;
00532        input = inputarg;
00533        inputlen = inputarg_len;
00534        inputpos = 0;
00535 
00536        array_init(return_value);
00537 
00538        while (formatlen-- > 0) {
00539               char type = *(format++);
00540               char c;
00541               int arg = 1, argb;
00542               char *name;
00543               int namelen;
00544               int size=0;
00545 
00546               /* Handle format arguments if any */
00547               if (formatlen > 0) {
00548                      c = *format;
00549 
00550                      if (c >= '0' && c <= '9') {
00551                             arg = atoi(format);
00552 
00553                             while (formatlen > 0 && *format >= '0' && *format <= '9') {
00554                                    format++;
00555                                    formatlen--;
00556                             }
00557                      } else if (c == '*') {
00558                             arg = -1;
00559                             format++;
00560                             formatlen--;
00561                      }
00562               }
00563 
00564               /* Get of new value in array */
00565               name = format;
00566               argb = arg;
00567 
00568               while (formatlen > 0 && *format != '/') {
00569                      formatlen--;
00570                      format++;
00571               }
00572 
00573               namelen = format - name;
00574 
00575               if (namelen > 200)
00576                      namelen = 200;
00577 
00578               switch ((int) type) {
00579                      /* Never use any input */
00580                      case 'X': 
00581                             size = -1;
00582                             break;
00583 
00584                      case '@':
00585                             size = 0;
00586                             break;
00587 
00588                      case 'a': 
00589                      case 'A':
00590                             size = arg;
00591                             arg = 1;
00592                             break;
00593 
00594                      case 'h': 
00595                      case 'H': 
00596                             size = (arg > 0) ? (arg + (arg % 2)) / 2 : arg;
00597                             arg = 1;
00598                             break;
00599 
00600                      /* Use 1 byte of input */
00601                      case 'c': 
00602                      case 'C':
00603                      case 'x':
00604                             size = 1;
00605                             break;
00606 
00607                      /* Use 2 bytes of input */
00608                      case 's': 
00609                      case 'S': 
00610                      case 'n': 
00611                      case 'v':
00612                             size = 2;
00613                             break;
00614 
00615                      /* Use sizeof(int) bytes of input */
00616                      case 'i': 
00617                      case 'I':
00618                             size = sizeof(int);
00619                             break;
00620 
00621                      /* Use 4 bytes of input */
00622                      case 'l': 
00623                      case 'L': 
00624                      case 'N': 
00625                      case 'V':
00626                             size = 4;
00627                             break;
00628 
00629                      /* Use sizeof(float) bytes of input */
00630                      case 'f':
00631                             size = sizeof(float);
00632                             break;
00633 
00634                      /* Use sizeof(double) bytes of input */
00635                      case 'd':
00636                             size = sizeof(double);
00637                             break;
00638 
00639                      default:
00640                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid format type %c", type);
00641                             zval_dtor(return_value);
00642                             RETURN_FALSE;
00643                             break;
00644               }
00645 
00646               /* Do actual unpacking */
00647               for (i = 0; i != arg; i++ ) {
00648                      /* Space for name + number, safe as namelen is ensured <= 200 */
00649                      char n[256];
00650 
00651                      if (arg != 1 || namelen == 0) {
00652                             /* Need to add element number to name */
00653                             snprintf(n, sizeof(n), "%.*s%d", namelen, name, i + 1);
00654                      } else {
00655                             /* Truncate name to next format code or end of string */
00656                             snprintf(n, sizeof(n), "%.*s", namelen, name);
00657                      }
00658 
00659                      if (size != 0 && size != -1 && INT_MAX - size + 1 < inputpos) {
00660                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow", type);
00661                             inputpos = 0;
00662                      }
00663 
00664                      if ((inputpos + size) <= inputlen) {
00665                             switch ((int) type) {
00666                                    case 'a': 
00667                                    case 'A': {
00668                                           char pad = (type == 'a') ? '\0' : ' ';
00669                                           int len = inputlen - inputpos;     /* Remaining string */
00670 
00671                                           /* If size was given take minimum of len and size */
00672                                           if ((size >= 0) && (len > size)) {
00673                                                  len = size;
00674                                           }
00675 
00676                                           size = len;
00677 
00678                                           /* Remove padding chars from unpacked data */
00679                                           while (--len >= 0) {
00680                                                  if (input[inputpos + len] != pad)
00681                                                         break;
00682                                           }
00683 
00684                                           add_assoc_stringl(return_value, n, &input[inputpos], len + 1, 1);
00685                                           break;
00686                                    }
00687                                    
00688                                    case 'h': 
00689                                    case 'H': {
00690                                           int len = (inputlen - inputpos) * 2;      /* Remaining */
00691                                           int nibbleshift = (type == 'h') ? 0 : 4;
00692                                           int first = 1;
00693                                           char *buf;
00694                                           int ipos, opos;
00695 
00696                                           /* If size was given take minimum of len and size */
00697                                           if (size >= 0 && len > (size * 2)) {
00698                                                  len = size * 2;
00699                                           } 
00700 
00701                                           if (argb > 0) {      
00702                                                  len -= argb % 2;
00703                                           }
00704 
00705                                           buf = emalloc(len + 1);
00706 
00707                                           for (ipos = opos = 0; opos < len; opos++) {
00708                                                  char cc = (input[inputpos + ipos] >> nibbleshift) & 0xf;
00709 
00710                                                  if (cc < 10) {
00711                                                         cc += '0';
00712                                                  } else {
00713                                                         cc += 'a' - 10;
00714                                                  }
00715 
00716                                                  buf[opos] = cc;
00717                                                  nibbleshift = (nibbleshift + 4) & 7;
00718 
00719                                                  if (first-- == 0) {
00720                                                         ipos++;
00721                                                         first = 1;
00722                                                  }
00723                                           }
00724 
00725                                           buf[len] = '\0';
00726                                           add_assoc_stringl(return_value, n, buf, len, 1);
00727                                           efree(buf);
00728                                           break;
00729                                    }
00730 
00731                                    case 'c': 
00732                                    case 'C': {
00733                                           int issigned = (type == 'c') ? (input[inputpos] & 0x80) : 0;
00734                                           long v = php_unpack(&input[inputpos], 1, issigned, byte_map);
00735                                           add_assoc_long(return_value, n, v);
00736                                           break;
00737                                    }
00738 
00739                                    case 's': 
00740                                    case 'S': 
00741                                    case 'n': 
00742                                    case 'v': {
00743                                           long v;
00744                                           int issigned = 0;
00745                                           int *map = machine_endian_short_map;
00746 
00747                                           if (type == 's') {
00748                                                  issigned = input[inputpos + (machine_little_endian ? 1 : 0)] & 0x80;
00749                                           } else if (type == 'n') {
00750                                                  map = big_endian_short_map;
00751                                           } else if (type == 'v') {
00752                                                  map = little_endian_short_map;
00753                                           }
00754 
00755                                           v = php_unpack(&input[inputpos], 2, issigned, map);
00756                                           add_assoc_long(return_value, n, v);
00757                                           break;
00758                                    }
00759 
00760                                    case 'i': 
00761                                    case 'I': {
00762                                           long v = 0;
00763                                           int issigned = 0;
00764 
00765                                           if (type == 'i') {
00766                                                  issigned = input[inputpos + (machine_little_endian ? (sizeof(int) - 1) : 0)] & 0x80;
00767                                           } else if (sizeof(long) > 4 && (input[inputpos + machine_endian_long_map[3]] & 0x80) == 0x80) {
00768                                                  v = ~INT_MAX;
00769                                           }
00770 
00771                                           v |= php_unpack(&input[inputpos], sizeof(int), issigned, int_map);
00772                                           add_assoc_long(return_value, n, v);
00773                                           break;
00774                                    }
00775 
00776                                    case 'l': 
00777                                    case 'L': 
00778                                    case 'N': 
00779                                    case 'V': {
00780                                           int issigned = 0;
00781                                           int *map = machine_endian_long_map;
00782                                           long v = 0;
00783 
00784                                           if (type == 'l' || type == 'L') {
00785                                                  issigned = input[inputpos + (machine_little_endian ? 3 : 0)] & 0x80;
00786                                           } else if (type == 'N') {
00787                                                  issigned = input[inputpos] & 0x80;
00788                                                  map = big_endian_long_map;
00789                                           } else if (type == 'V') {
00790                                                  issigned = input[inputpos + 3] & 0x80;
00791                                                  map = little_endian_long_map;
00792                                           }
00793 
00794                                           if (sizeof(long) > 4 && issigned) {
00795                                                  v = ~INT_MAX;
00796                                           }
00797 
00798                                           v |= php_unpack(&input[inputpos], 4, issigned, map);
00799                                           if (sizeof(long) > 4) {
00800                                                  if (type == 'l') {
00801                                                         v = (signed int) v; 
00802                                                  } else {
00803                                                         v = (unsigned int) v;
00804                                                  }
00805                                           }
00806                                           add_assoc_long(return_value, n, v);
00807                                           break;
00808                                    }
00809 
00810                                    case 'f': {
00811                                           float v;
00812 
00813                                           memcpy(&v, &input[inputpos], sizeof(float));
00814                                           add_assoc_double(return_value, n, (double)v);
00815                                           break;
00816                                    }
00817 
00818                                    case 'd': {
00819                                           double v;
00820 
00821                                           memcpy(&v, &input[inputpos], sizeof(double));
00822                                           add_assoc_double(return_value, n, v);
00823                                           break;
00824                                    }
00825 
00826                                    case 'x':
00827                                           /* Do nothing with input, just skip it */
00828                                           break;
00829 
00830                                    case 'X':
00831                                           if (inputpos < size) {
00832                                                  inputpos = -size;
00833                                                  i = arg - 1;         /* Break out of for loop */
00834 
00835                                                  if (arg >= 0) {
00836                                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
00837                                                  }
00838                                           }
00839                                           break;
00840 
00841                                    case '@':
00842                                           if (arg <= inputlen) {
00843                                                  inputpos = arg;
00844                                           } else {
00845                                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
00846                                           }
00847 
00848                                           i = arg - 1;  /* Done, break out of for loop */
00849                                           break;
00850                             }
00851 
00852                             inputpos += size;
00853                             if (inputpos < 0) {
00854                                    if (size != -1) { /* only print warning if not working with * */
00855                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type);
00856                                    }
00857                                    inputpos = 0;
00858                             }
00859                      } else if (arg < 0) {
00860                             /* Reached end of input for '*' repeater */
00861                             break;
00862                      } else {
00863                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough input, need %d, have %d", type, size, inputlen - inputpos);
00864                             zval_dtor(return_value);
00865                             RETURN_FALSE;
00866                      }
00867               }
00868 
00869               formatlen--;  /* Skip '/' separator, does no harm if inputlen == 0 */
00870               format++;
00871        }
00872 }
00873 /* }}} */
00874 
00875 /* {{{ PHP_MINIT_FUNCTION
00876  */
00877 PHP_MINIT_FUNCTION(pack)
00878 {
00879        int machine_endian_check = 1;
00880        int i;
00881 
00882        machine_little_endian = ((char *)&machine_endian_check)[0];
00883 
00884        if (machine_little_endian) {
00885               /* Where to get lo to hi bytes from */
00886               byte_map[0] = 0;
00887 
00888               for (i = 0; i < (int)sizeof(int); i++) {
00889                      int_map[i] = i;
00890               }
00891 
00892               machine_endian_short_map[0] = 0;
00893               machine_endian_short_map[1] = 1;
00894               big_endian_short_map[0] = 1;
00895               big_endian_short_map[1] = 0;
00896               little_endian_short_map[0] = 0;
00897               little_endian_short_map[1] = 1;
00898 
00899               machine_endian_long_map[0] = 0;
00900               machine_endian_long_map[1] = 1;
00901               machine_endian_long_map[2] = 2;
00902               machine_endian_long_map[3] = 3;
00903               big_endian_long_map[0] = 3;
00904               big_endian_long_map[1] = 2;
00905               big_endian_long_map[2] = 1;
00906               big_endian_long_map[3] = 0;
00907               little_endian_long_map[0] = 0;
00908               little_endian_long_map[1] = 1;
00909               little_endian_long_map[2] = 2;
00910               little_endian_long_map[3] = 3;
00911        }
00912        else {
00913               zval val;
00914               int size = sizeof(Z_LVAL(val));
00915               Z_LVAL(val)=0; /*silence a warning*/
00916 
00917               /* Where to get hi to lo bytes from */
00918               byte_map[0] = size - 1;
00919 
00920               for (i = 0; i < (int)sizeof(int); i++) {
00921                      int_map[i] = size - (sizeof(int) - i);
00922               }
00923 
00924               machine_endian_short_map[0] = size - 2;
00925               machine_endian_short_map[1] = size - 1;
00926               big_endian_short_map[0] = size - 2;
00927               big_endian_short_map[1] = size - 1;
00928               little_endian_short_map[0] = size - 1;
00929               little_endian_short_map[1] = size - 2;
00930 
00931               machine_endian_long_map[0] = size - 4;
00932               machine_endian_long_map[1] = size - 3;
00933               machine_endian_long_map[2] = size - 2;
00934               machine_endian_long_map[3] = size - 1;
00935               big_endian_long_map[0] = size - 4;
00936               big_endian_long_map[1] = size - 3;
00937               big_endian_long_map[2] = size - 2;
00938               big_endian_long_map[3] = size - 1;
00939               little_endian_long_map[0] = size - 1;
00940               little_endian_long_map[1] = size - 2;
00941               little_endian_long_map[2] = size - 3;
00942               little_endian_long_map[3] = size - 4;
00943        }
00944 
00945        return SUCCESS;
00946 }
00947 /* }}} */
00948 
00949 /*
00950  * Local variables:
00951  * tab-width: 4
00952  * c-basic-offset: 4
00953  * End:
00954  * vim600: noet sw=4 ts=4 fdm=marker
00955  * vim<600: noet sw=4 ts=4
00956  */