Annotation of embedaddon/php/ext/standard/pack.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>