Return to pack.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
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: */