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

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

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