pack.c 27 KB

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