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>