Annotation of embedaddon/php/ext/standard/pack.c, revision 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>