PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/standard/pack.c

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