pack.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 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. #include "php.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <errno.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <fcntl.h>
  25. #ifdef PHP_WIN32
  26. #define O_RDONLY _O_RDONLY
  27. #include "win32/param.h"
  28. #else
  29. #include <sys/param.h>
  30. #endif
  31. #include "ext/standard/head.h"
  32. #include "php_string.h"
  33. #include "pack.h"
  34. #if HAVE_PWD_H
  35. #ifdef PHP_WIN32
  36. #include "win32/pwd.h"
  37. #else
  38. #include <pwd.h>
  39. #endif
  40. #endif
  41. #include "fsock.h"
  42. #if HAVE_NETINET_IN_H
  43. #include <netinet/in.h>
  44. #endif
  45. #define INC_OUTPUTPOS(a,b) \
  46. if ((a) < 0 || ((INT_MAX - outputpos)/((int)b)) < (a)) { \
  47. efree(formatcodes); \
  48. efree(formatargs); \
  49. php_error_docref(NULL, E_WARNING, "Type %c: integer overflow in format string", code); \
  50. RETURN_FALSE; \
  51. } \
  52. outputpos += (a)*(b);
  53. /* Whether machine is little endian */
  54. char machine_little_endian;
  55. /* Mapping of byte from char (8bit) to long for machine endian */
  56. static int byte_map[1];
  57. /* Mappings of bytes from int (machine dependent) to int for machine endian */
  58. static int int_map[sizeof(int)];
  59. /* Mappings of bytes from shorts (16bit) for all endian environments */
  60. static int machine_endian_short_map[2];
  61. static int big_endian_short_map[2];
  62. static int little_endian_short_map[2];
  63. /* Mappings of bytes from longs (32bit) for all endian environments */
  64. static int machine_endian_long_map[4];
  65. static int big_endian_long_map[4];
  66. static int little_endian_long_map[4];
  67. #if SIZEOF_ZEND_LONG > 4
  68. /* Mappings of bytes from quads (64bit) for all endian environments */
  69. static int machine_endian_longlong_map[8];
  70. static int big_endian_longlong_map[8];
  71. static int little_endian_longlong_map[8];
  72. #endif
  73. /* {{{ php_pack
  74. */
  75. static void php_pack(zval *val, size_t size, int *map, char *output)
  76. {
  77. size_t i;
  78. char *v;
  79. convert_to_long_ex(val);
  80. v = (char *) &Z_LVAL_P(val);
  81. for (i = 0; i < size; i++) {
  82. *output++ = v[map[i]];
  83. }
  84. }
  85. /* }}} */
  86. /* {{{ php_pack_reverse_int32
  87. */
  88. static inline uint32_t php_pack_reverse_int32(uint32_t arg)
  89. {
  90. uint32_t result;
  91. result = ((arg & 0xFF) << 24) | ((arg & 0xFF00) << 8) | ((arg >> 8) & 0xFF00) | ((arg >> 24) & 0xFF);
  92. return result;
  93. }
  94. /* }}} */
  95. /* {{{ php_pack
  96. */
  97. static inline uint64_t php_pack_reverse_int64(uint64_t arg)
  98. {
  99. union Swap64 {
  100. uint64_t i;
  101. uint32_t ul[2];
  102. } tmp, result;
  103. tmp.i = arg;
  104. result.ul[0] = php_pack_reverse_int32(tmp.ul[1]);
  105. result.ul[1] = php_pack_reverse_int32(tmp.ul[0]);
  106. return result.i;
  107. }
  108. /* }}} */
  109. /* {{{ php_pack_copy_float
  110. */
  111. static void php_pack_copy_float(int is_little_endian, void * dst, float f)
  112. {
  113. union Copy32 {
  114. float f;
  115. uint32_t i;
  116. } m;
  117. m.f = f;
  118. #ifdef WORDS_BIGENDIAN
  119. if (is_little_endian) {
  120. m.i = php_pack_reverse_int32(m.i);
  121. }
  122. #else /* WORDS_BIGENDIAN */
  123. if (!is_little_endian) {
  124. m.i = php_pack_reverse_int32(m.i);
  125. }
  126. #endif /* WORDS_BIGENDIAN */
  127. memcpy(dst, &m.f, sizeof(float));
  128. }
  129. /* }}} */
  130. /* {{{ php_pack_copy_double
  131. */
  132. static void php_pack_copy_double(int is_little_endian, void * dst, double d)
  133. {
  134. union Copy64 {
  135. double d;
  136. uint64_t i;
  137. } m;
  138. m.d = d;
  139. #ifdef WORDS_BIGENDIAN
  140. if (is_little_endian) {
  141. m.i = php_pack_reverse_int64(m.i);
  142. }
  143. #else /* WORDS_BIGENDIAN */
  144. if (!is_little_endian) {
  145. m.i = php_pack_reverse_int64(m.i);
  146. }
  147. #endif /* WORDS_BIGENDIAN */
  148. memcpy(dst, &m.d, sizeof(double));
  149. }
  150. /* }}} */
  151. /* {{{ php_pack_parse_float
  152. */
  153. static float php_pack_parse_float(int is_little_endian, void * src)
  154. {
  155. union Copy32 {
  156. float f;
  157. uint32_t i;
  158. } m;
  159. memcpy(&m.i, src, sizeof(float));
  160. #ifdef WORDS_BIGENDIAN
  161. if (is_little_endian) {
  162. m.i = php_pack_reverse_int32(m.i);
  163. }
  164. #else /* WORDS_BIGENDIAN */
  165. if (!is_little_endian) {
  166. m.i = php_pack_reverse_int32(m.i);
  167. }
  168. #endif /* WORDS_BIGENDIAN */
  169. return m.f;
  170. }
  171. /* }}} */
  172. /* {{{ php_pack_parse_double
  173. */
  174. static double php_pack_parse_double(int is_little_endian, void * src)
  175. {
  176. union Copy64 {
  177. double d;
  178. uint64_t i;
  179. } m;
  180. memcpy(&m.i, src, sizeof(double));
  181. #ifdef WORDS_BIGENDIAN
  182. if (is_little_endian) {
  183. m.i = php_pack_reverse_int64(m.i);
  184. }
  185. #else /* WORDS_BIGENDIAN */
  186. if (!is_little_endian) {
  187. m.i = php_pack_reverse_int64(m.i);
  188. }
  189. #endif /* WORDS_BIGENDIAN */
  190. return m.d;
  191. }
  192. /* }}} */
  193. /* pack() idea stolen from Perl (implemented formats behave the same as there except J and P)
  194. * 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, @.
  195. * Added g, G for little endian float and big endian float, added e, E for little endian double and big endian double.
  196. */
  197. /* {{{ proto string pack(string format, mixed arg1 [, mixed arg2 [, mixed ...]])
  198. Takes one or more arguments and packs them into a binary string according to the format argument */
  199. PHP_FUNCTION(pack)
  200. {
  201. zval *argv = NULL;
  202. int num_args = 0;
  203. size_t i;
  204. int currentarg;
  205. char *format;
  206. size_t formatlen;
  207. char *formatcodes;
  208. int *formatargs;
  209. size_t formatcount = 0;
  210. int outputpos = 0, outputsize = 0;
  211. zend_string *output;
  212. ZEND_PARSE_PARAMETERS_START(1, -1)
  213. Z_PARAM_STRING(format, formatlen)
  214. Z_PARAM_VARIADIC('*', argv, num_args)
  215. ZEND_PARSE_PARAMETERS_END();
  216. /* We have a maximum of <formatlen> format codes to deal with */
  217. formatcodes = safe_emalloc(formatlen, sizeof(*formatcodes), 0);
  218. formatargs = safe_emalloc(formatlen, sizeof(*formatargs), 0);
  219. currentarg = 0;
  220. /* Preprocess format into formatcodes and formatargs */
  221. for (i = 0; i < formatlen; formatcount++) {
  222. char code = format[i++];
  223. int arg = 1;
  224. /* Handle format arguments if any */
  225. if (i < formatlen) {
  226. char c = format[i];
  227. if (c == '*') {
  228. arg = -1;
  229. i++;
  230. }
  231. else if (c >= '0' && c <= '9') {
  232. arg = atoi(&format[i]);
  233. while (format[i] >= '0' && format[i] <= '9' && i < formatlen) {
  234. i++;
  235. }
  236. }
  237. }
  238. /* Handle special arg '*' for all codes and check argv overflows */
  239. switch ((int) code) {
  240. /* Never uses any args */
  241. case 'x':
  242. case 'X':
  243. case '@':
  244. if (arg < 0) {
  245. php_error_docref(NULL, E_WARNING, "Type %c: '*' ignored", code);
  246. arg = 1;
  247. }
  248. break;
  249. /* Always uses one arg */
  250. case 'a':
  251. case 'A':
  252. case 'Z':
  253. case 'h':
  254. case 'H':
  255. if (currentarg >= num_args) {
  256. efree(formatcodes);
  257. efree(formatargs);
  258. php_error_docref(NULL, E_WARNING, "Type %c: not enough arguments", code);
  259. RETURN_FALSE;
  260. }
  261. if (arg < 0) {
  262. convert_to_string(&argv[currentarg]);
  263. arg = Z_STRLEN(argv[currentarg]);
  264. if (code == 'Z') {
  265. /* add one because Z is always NUL-terminated:
  266. * pack("Z*", "aa") === "aa\0"
  267. * pack("Z2", "aa") === "a\0" */
  268. arg++;
  269. }
  270. }
  271. currentarg++;
  272. break;
  273. /* Use as many args as specified */
  274. case 'q':
  275. case 'Q':
  276. case 'J':
  277. case 'P':
  278. #if SIZEOF_ZEND_LONG < 8
  279. efree(formatcodes);
  280. efree(formatargs);
  281. php_error_docref(NULL, E_WARNING, "64-bit format codes are not available for 32-bit versions of PHP");
  282. RETURN_FALSE;
  283. #endif
  284. case 'c':
  285. case 'C':
  286. case 's':
  287. case 'S':
  288. case 'i':
  289. case 'I':
  290. case 'l':
  291. case 'L':
  292. case 'n':
  293. case 'N':
  294. case 'v':
  295. case 'V':
  296. case 'f': /* float */
  297. case 'g': /* little endian float */
  298. case 'G': /* big endian float */
  299. case 'd': /* double */
  300. case 'e': /* little endian double */
  301. case 'E': /* big endian double */
  302. if (arg < 0) {
  303. arg = num_args - currentarg;
  304. }
  305. if (currentarg > INT_MAX - arg) {
  306. goto too_few_args;
  307. }
  308. currentarg += arg;
  309. if (currentarg > num_args) {
  310. too_few_args:
  311. efree(formatcodes);
  312. efree(formatargs);
  313. php_error_docref(NULL, E_WARNING, "Type %c: too few arguments", code);
  314. RETURN_FALSE;
  315. }
  316. break;
  317. default:
  318. efree(formatcodes);
  319. efree(formatargs);
  320. php_error_docref(NULL, E_WARNING, "Type %c: unknown format code", code);
  321. RETURN_FALSE;
  322. }
  323. formatcodes[formatcount] = code;
  324. formatargs[formatcount] = arg;
  325. }
  326. if (currentarg < num_args) {
  327. php_error_docref(NULL, E_WARNING, "%d arguments unused", (num_args - currentarg));
  328. }
  329. /* Calculate output length and upper bound while processing*/
  330. for (i = 0; i < formatcount; i++) {
  331. int code = (int) formatcodes[i];
  332. int arg = formatargs[i];
  333. switch ((int) code) {
  334. case 'h':
  335. case 'H':
  336. INC_OUTPUTPOS((arg + (arg % 2)) / 2,1) /* 4 bit per arg */
  337. break;
  338. case 'a':
  339. case 'A':
  340. case 'Z':
  341. case 'c':
  342. case 'C':
  343. case 'x':
  344. INC_OUTPUTPOS(arg,1) /* 8 bit per arg */
  345. break;
  346. case 's':
  347. case 'S':
  348. case 'n':
  349. case 'v':
  350. INC_OUTPUTPOS(arg,2) /* 16 bit per arg */
  351. break;
  352. case 'i':
  353. case 'I':
  354. INC_OUTPUTPOS(arg,sizeof(int))
  355. break;
  356. case 'l':
  357. case 'L':
  358. case 'N':
  359. case 'V':
  360. INC_OUTPUTPOS(arg,4) /* 32 bit per arg */
  361. break;
  362. #if SIZEOF_ZEND_LONG > 4
  363. case 'q':
  364. case 'Q':
  365. case 'J':
  366. case 'P':
  367. INC_OUTPUTPOS(arg,8) /* 32 bit per arg */
  368. break;
  369. #endif
  370. case 'f': /* float */
  371. case 'g': /* little endian float */
  372. case 'G': /* big endian float */
  373. INC_OUTPUTPOS(arg,sizeof(float))
  374. break;
  375. case 'd': /* double */
  376. case 'e': /* little endian double */
  377. case 'E': /* big endian double */
  378. INC_OUTPUTPOS(arg,sizeof(double))
  379. break;
  380. case 'X':
  381. outputpos -= arg;
  382. if (outputpos < 0) {
  383. php_error_docref(NULL, E_WARNING, "Type %c: outside of string", code);
  384. outputpos = 0;
  385. }
  386. break;
  387. case '@':
  388. outputpos = arg;
  389. break;
  390. }
  391. if (outputsize < outputpos) {
  392. outputsize = outputpos;
  393. }
  394. }
  395. output = zend_string_alloc(outputsize, 0);
  396. outputpos = 0;
  397. currentarg = 0;
  398. /* Do actual packing */
  399. for (i = 0; i < formatcount; i++) {
  400. int code = (int) formatcodes[i];
  401. int arg = formatargs[i];
  402. switch ((int) code) {
  403. case 'a':
  404. case 'A':
  405. case 'Z': {
  406. size_t arg_cp = (code != 'Z') ? arg : MAX(0, arg - 1);
  407. zend_string *tmp_str;
  408. zend_string *str = zval_get_tmp_string(&argv[currentarg++], &tmp_str);
  409. memset(&ZSTR_VAL(output)[outputpos], (code == 'a' || code == 'Z') ? '\0' : ' ', arg);
  410. memcpy(&ZSTR_VAL(output)[outputpos], ZSTR_VAL(str),
  411. (ZSTR_LEN(str) < arg_cp) ? ZSTR_LEN(str) : arg_cp);
  412. outputpos += arg;
  413. zend_tmp_string_release(tmp_str);
  414. break;
  415. }
  416. case 'h':
  417. case 'H': {
  418. int nibbleshift = (code == 'h') ? 0 : 4;
  419. int first = 1;
  420. zend_string *tmp_str;
  421. zend_string *str = zval_get_tmp_string(&argv[currentarg++], &tmp_str);
  422. char *v = ZSTR_VAL(str);
  423. outputpos--;
  424. if ((size_t)arg > ZSTR_LEN(str)) {
  425. php_error_docref(NULL, E_WARNING, "Type %c: not enough characters in string", code);
  426. arg = ZSTR_LEN(str);
  427. }
  428. while (arg-- > 0) {
  429. char n = *v++;
  430. if (n >= '0' && n <= '9') {
  431. n -= '0';
  432. } else if (n >= 'A' && n <= 'F') {
  433. n -= ('A' - 10);
  434. } else if (n >= 'a' && n <= 'f') {
  435. n -= ('a' - 10);
  436. } else {
  437. php_error_docref(NULL, E_WARNING, "Type %c: illegal hex digit %c", code, n);
  438. n = 0;
  439. }
  440. if (first--) {
  441. ZSTR_VAL(output)[++outputpos] = 0;
  442. } else {
  443. first = 1;
  444. }
  445. ZSTR_VAL(output)[outputpos] |= (n << nibbleshift);
  446. nibbleshift = (nibbleshift + 4) & 7;
  447. }
  448. outputpos++;
  449. zend_tmp_string_release(tmp_str);
  450. break;
  451. }
  452. case 'c':
  453. case 'C':
  454. while (arg-- > 0) {
  455. php_pack(&argv[currentarg++], 1, byte_map, &ZSTR_VAL(output)[outputpos]);
  456. outputpos++;
  457. }
  458. break;
  459. case 's':
  460. case 'S':
  461. case 'n':
  462. case 'v': {
  463. int *map = machine_endian_short_map;
  464. if (code == 'n') {
  465. map = big_endian_short_map;
  466. } else if (code == 'v') {
  467. map = little_endian_short_map;
  468. }
  469. while (arg-- > 0) {
  470. php_pack(&argv[currentarg++], 2, map, &ZSTR_VAL(output)[outputpos]);
  471. outputpos += 2;
  472. }
  473. break;
  474. }
  475. case 'i':
  476. case 'I':
  477. while (arg-- > 0) {
  478. php_pack(&argv[currentarg++], sizeof(int), int_map, &ZSTR_VAL(output)[outputpos]);
  479. outputpos += sizeof(int);
  480. }
  481. break;
  482. case 'l':
  483. case 'L':
  484. case 'N':
  485. case 'V': {
  486. int *map = machine_endian_long_map;
  487. if (code == 'N') {
  488. map = big_endian_long_map;
  489. } else if (code == 'V') {
  490. map = little_endian_long_map;
  491. }
  492. while (arg-- > 0) {
  493. php_pack(&argv[currentarg++], 4, map, &ZSTR_VAL(output)[outputpos]);
  494. outputpos += 4;
  495. }
  496. break;
  497. }
  498. #if SIZEOF_ZEND_LONG > 4
  499. case 'q':
  500. case 'Q':
  501. case 'J':
  502. case 'P': {
  503. int *map = machine_endian_longlong_map;
  504. if (code == 'J') {
  505. map = big_endian_longlong_map;
  506. } else if (code == 'P') {
  507. map = little_endian_longlong_map;
  508. }
  509. while (arg-- > 0) {
  510. php_pack(&argv[currentarg++], 8, map, &ZSTR_VAL(output)[outputpos]);
  511. outputpos += 8;
  512. }
  513. break;
  514. }
  515. #endif
  516. case 'f': {
  517. while (arg-- > 0) {
  518. float v = (float) zval_get_double(&argv[currentarg++]);
  519. memcpy(&ZSTR_VAL(output)[outputpos], &v, sizeof(v));
  520. outputpos += sizeof(v);
  521. }
  522. break;
  523. }
  524. case 'g': {
  525. /* pack little endian float */
  526. while (arg-- > 0) {
  527. float v = (float) zval_get_double(&argv[currentarg++]);
  528. php_pack_copy_float(1, &ZSTR_VAL(output)[outputpos], v);
  529. outputpos += sizeof(v);
  530. }
  531. break;
  532. }
  533. case 'G': {
  534. /* pack big endian float */
  535. while (arg-- > 0) {
  536. float v = (float) zval_get_double(&argv[currentarg++]);
  537. php_pack_copy_float(0, &ZSTR_VAL(output)[outputpos], v);
  538. outputpos += sizeof(v);
  539. }
  540. break;
  541. }
  542. case 'd': {
  543. while (arg-- > 0) {
  544. double v = (double) zval_get_double(&argv[currentarg++]);
  545. memcpy(&ZSTR_VAL(output)[outputpos], &v, sizeof(v));
  546. outputpos += sizeof(v);
  547. }
  548. break;
  549. }
  550. case 'e': {
  551. /* pack little endian double */
  552. while (arg-- > 0) {
  553. double v = (double) zval_get_double(&argv[currentarg++]);
  554. php_pack_copy_double(1, &ZSTR_VAL(output)[outputpos], v);
  555. outputpos += sizeof(v);
  556. }
  557. break;
  558. }
  559. case 'E': {
  560. /* pack big endian double */
  561. while (arg-- > 0) {
  562. double v = (double) zval_get_double(&argv[currentarg++]);
  563. php_pack_copy_double(0, &ZSTR_VAL(output)[outputpos], v);
  564. outputpos += sizeof(v);
  565. }
  566. break;
  567. }
  568. case 'x':
  569. memset(&ZSTR_VAL(output)[outputpos], '\0', arg);
  570. outputpos += arg;
  571. break;
  572. case 'X':
  573. outputpos -= arg;
  574. if (outputpos < 0) {
  575. outputpos = 0;
  576. }
  577. break;
  578. case '@':
  579. if (arg > outputpos) {
  580. memset(&ZSTR_VAL(output)[outputpos], '\0', arg - outputpos);
  581. }
  582. outputpos = arg;
  583. break;
  584. }
  585. }
  586. efree(formatcodes);
  587. efree(formatargs);
  588. ZSTR_VAL(output)[outputpos] = '\0';
  589. ZSTR_LEN(output) = outputpos;
  590. RETURN_NEW_STR(output);
  591. }
  592. /* }}} */
  593. /* {{{ php_unpack
  594. */
  595. static zend_long php_unpack(char *data, size_t size, int issigned, int *map)
  596. {
  597. zend_long result;
  598. char *cresult = (char *) &result;
  599. size_t i;
  600. result = issigned ? -1 : 0;
  601. for (i = 0; i < size; i++) {
  602. cresult[map[i]] = *data++;
  603. }
  604. return result;
  605. }
  606. /* }}} */
  607. /* unpack() is based on Perl's unpack(), but is modified a bit from there.
  608. * Rather than depending on error-prone ordered lists or syntactically
  609. * unpleasant pass-by-reference, we return an object with named parameters
  610. * (like *_fetch_object()). Syntax is "f[repeat]name/...", where "f" is the
  611. * formatter char (like pack()), "[repeat]" is the optional repeater argument,
  612. * and "name" is the name of the variable to use.
  613. * Example: "c2chars/nints" will return an object with fields
  614. * chars1, chars2, and ints.
  615. * Numeric pack types will return numbers, a and A will return strings,
  616. * f and d will return doubles.
  617. * 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, @.
  618. * Added g, G for little endian float and big endian float, added e, E for little endian double and big endian double.
  619. */
  620. /* {{{ proto array unpack(string format, string input)
  621. Unpack binary string into named array elements according to format argument */
  622. PHP_FUNCTION(unpack)
  623. {
  624. char *format, *input;
  625. zend_string *formatarg, *inputarg;
  626. zend_long formatlen, inputpos, inputlen;
  627. int i;
  628. zend_long offset = 0;
  629. ZEND_PARSE_PARAMETERS_START(2, 3)
  630. Z_PARAM_STR(formatarg)
  631. Z_PARAM_STR(inputarg)
  632. Z_PARAM_OPTIONAL
  633. Z_PARAM_LONG(offset)
  634. ZEND_PARSE_PARAMETERS_END();
  635. format = ZSTR_VAL(formatarg);
  636. formatlen = ZSTR_LEN(formatarg);
  637. input = ZSTR_VAL(inputarg);
  638. inputlen = ZSTR_LEN(inputarg);
  639. inputpos = 0;
  640. if (offset < 0 || offset > inputlen) {
  641. php_error_docref(NULL, E_WARNING, "Offset " ZEND_LONG_FMT " is out of input range" , offset);
  642. RETURN_FALSE;
  643. }
  644. input += offset;
  645. inputlen -= offset;
  646. array_init(return_value);
  647. while (formatlen-- > 0) {
  648. char type = *(format++);
  649. char c;
  650. int arg = 1, argb;
  651. char *name;
  652. int namelen;
  653. int size=0;
  654. /* Handle format arguments if any */
  655. if (formatlen > 0) {
  656. c = *format;
  657. if (c >= '0' && c <= '9') {
  658. arg = atoi(format);
  659. while (formatlen > 0 && *format >= '0' && *format <= '9') {
  660. format++;
  661. formatlen--;
  662. }
  663. } else if (c == '*') {
  664. arg = -1;
  665. format++;
  666. formatlen--;
  667. }
  668. }
  669. /* Get of new value in array */
  670. name = format;
  671. argb = arg;
  672. while (formatlen > 0 && *format != '/') {
  673. formatlen--;
  674. format++;
  675. }
  676. namelen = format - name;
  677. if (namelen > 200)
  678. namelen = 200;
  679. switch ((int) type) {
  680. /* Never use any input */
  681. case 'X':
  682. size = -1;
  683. if (arg < 0) {
  684. php_error_docref(NULL, E_WARNING, "Type %c: '*' ignored", type);
  685. arg = 1;
  686. }
  687. break;
  688. case '@':
  689. size = 0;
  690. break;
  691. case 'a':
  692. case 'A':
  693. case 'Z':
  694. size = arg;
  695. arg = 1;
  696. break;
  697. case 'h':
  698. case 'H':
  699. size = (arg > 0) ? (arg + (arg % 2)) / 2 : arg;
  700. arg = 1;
  701. break;
  702. /* Use 1 byte of input */
  703. case 'c':
  704. case 'C':
  705. case 'x':
  706. size = 1;
  707. break;
  708. /* Use 2 bytes of input */
  709. case 's':
  710. case 'S':
  711. case 'n':
  712. case 'v':
  713. size = 2;
  714. break;
  715. /* Use sizeof(int) bytes of input */
  716. case 'i':
  717. case 'I':
  718. size = sizeof(int);
  719. break;
  720. /* Use 4 bytes of input */
  721. case 'l':
  722. case 'L':
  723. case 'N':
  724. case 'V':
  725. size = 4;
  726. break;
  727. /* Use 8 bytes of input */
  728. case 'q':
  729. case 'Q':
  730. case 'J':
  731. case 'P':
  732. #if SIZEOF_ZEND_LONG > 4
  733. size = 8;
  734. break;
  735. #else
  736. php_error_docref(NULL, E_WARNING, "64-bit format codes are not available for 32-bit versions of PHP");
  737. zend_array_destroy(Z_ARR_P(return_value));
  738. RETURN_FALSE;
  739. #endif
  740. /* Use sizeof(float) bytes of input */
  741. case 'f':
  742. case 'g':
  743. case 'G':
  744. size = sizeof(float);
  745. break;
  746. /* Use sizeof(double) bytes of input */
  747. case 'd':
  748. case 'e':
  749. case 'E':
  750. size = sizeof(double);
  751. break;
  752. default:
  753. php_error_docref(NULL, E_WARNING, "Invalid format type %c", type);
  754. zend_array_destroy(Z_ARR_P(return_value));
  755. RETURN_FALSE;
  756. break;
  757. }
  758. if (size != 0 && size != -1 && size < 0) {
  759. php_error_docref(NULL, E_WARNING, "Type %c: integer overflow", type);
  760. zend_array_destroy(Z_ARR_P(return_value));
  761. RETURN_FALSE;
  762. }
  763. /* Do actual unpacking */
  764. for (i = 0; i != arg; i++ ) {
  765. /* Space for name + number, safe as namelen is ensured <= 200 */
  766. char n[256];
  767. if (arg != 1 || namelen == 0) {
  768. /* Need to add element number to name */
  769. snprintf(n, sizeof(n), "%.*s%d", namelen, name, i + 1);
  770. } else {
  771. /* Truncate name to next format code or end of string */
  772. snprintf(n, sizeof(n), "%.*s", namelen, name);
  773. }
  774. if (size != 0 && size != -1 && INT_MAX - size + 1 < inputpos) {
  775. php_error_docref(NULL, E_WARNING, "Type %c: integer overflow", type);
  776. zend_array_destroy(Z_ARR_P(return_value));
  777. RETURN_FALSE;
  778. }
  779. if ((inputpos + size) <= inputlen) {
  780. switch ((int) type) {
  781. case 'a': {
  782. /* a will not strip any trailing whitespace or null padding */
  783. zend_long len = inputlen - inputpos; /* Remaining string */
  784. /* If size was given take minimum of len and size */
  785. if ((size >= 0) && (len > size)) {
  786. len = size;
  787. }
  788. size = len;
  789. add_assoc_stringl(return_value, n, &input[inputpos], len);
  790. break;
  791. }
  792. case 'A': {
  793. /* A will strip any trailing whitespace */
  794. char padn = '\0'; char pads = ' '; char padt = '\t'; char padc = '\r'; char padl = '\n';
  795. zend_long len = inputlen - inputpos; /* Remaining string */
  796. /* If size was given take minimum of len and size */
  797. if ((size >= 0) && (len > size)) {
  798. len = size;
  799. }
  800. size = len;
  801. /* Remove trailing white space and nulls chars from unpacked data */
  802. while (--len >= 0) {
  803. if (input[inputpos + len] != padn
  804. && input[inputpos + len] != pads
  805. && input[inputpos + len] != padt
  806. && input[inputpos + len] != padc
  807. && input[inputpos + len] != padl
  808. )
  809. break;
  810. }
  811. add_assoc_stringl(return_value, n, &input[inputpos], len + 1);
  812. break;
  813. }
  814. /* New option added for Z to remain in-line with the Perl implementation */
  815. case 'Z': {
  816. /* Z will strip everything after the first null character */
  817. char pad = '\0';
  818. zend_long s,
  819. len = inputlen - inputpos; /* Remaining string */
  820. /* If size was given take minimum of len and size */
  821. if ((size >= 0) && (len > size)) {
  822. len = size;
  823. }
  824. size = len;
  825. /* Remove everything after the first null */
  826. for (s=0 ; s < len ; s++) {
  827. if (input[inputpos + s] == pad)
  828. break;
  829. }
  830. len = s;
  831. add_assoc_stringl(return_value, n, &input[inputpos], len);
  832. break;
  833. }
  834. case 'h':
  835. case 'H': {
  836. zend_long len = (inputlen - inputpos) * 2; /* Remaining */
  837. int nibbleshift = (type == 'h') ? 0 : 4;
  838. int first = 1;
  839. zend_string *buf;
  840. zend_long ipos, opos;
  841. /* If size was given take minimum of len and size */
  842. if (size >= 0 && len > (size * 2)) {
  843. len = size * 2;
  844. }
  845. if (len > 0 && argb > 0) {
  846. len -= argb % 2;
  847. }
  848. buf = zend_string_alloc(len, 0);
  849. for (ipos = opos = 0; opos < len; opos++) {
  850. char cc = (input[inputpos + ipos] >> nibbleshift) & 0xf;
  851. if (cc < 10) {
  852. cc += '0';
  853. } else {
  854. cc += 'a' - 10;
  855. }
  856. ZSTR_VAL(buf)[opos] = cc;
  857. nibbleshift = (nibbleshift + 4) & 7;
  858. if (first-- == 0) {
  859. ipos++;
  860. first = 1;
  861. }
  862. }
  863. ZSTR_VAL(buf)[len] = '\0';
  864. add_assoc_str(return_value, n, buf);
  865. break;
  866. }
  867. case 'c':
  868. case 'C': {
  869. int issigned = (type == 'c') ? (input[inputpos] & 0x80) : 0;
  870. zend_long v = php_unpack(&input[inputpos], 1, issigned, byte_map);
  871. add_assoc_long(return_value, n, v);
  872. break;
  873. }
  874. case 's':
  875. case 'S':
  876. case 'n':
  877. case 'v': {
  878. zend_long v;
  879. int issigned = 0;
  880. int *map = machine_endian_short_map;
  881. if (type == 's') {
  882. issigned = input[inputpos + (machine_little_endian ? 1 : 0)] & 0x80;
  883. } else if (type == 'n') {
  884. map = big_endian_short_map;
  885. } else if (type == 'v') {
  886. map = little_endian_short_map;
  887. }
  888. v = php_unpack(&input[inputpos], 2, issigned, map);
  889. add_assoc_long(return_value, n, v);
  890. break;
  891. }
  892. case 'i':
  893. case 'I': {
  894. zend_long v;
  895. int issigned = 0;
  896. if (type == 'i') {
  897. issigned = input[inputpos + (machine_little_endian ? (sizeof(int) - 1) : 0)] & 0x80;
  898. }
  899. v = php_unpack(&input[inputpos], sizeof(int), issigned, int_map);
  900. add_assoc_long(return_value, n, v);
  901. break;
  902. }
  903. case 'l':
  904. case 'L':
  905. case 'N':
  906. case 'V': {
  907. int issigned = 0;
  908. int *map = machine_endian_long_map;
  909. zend_long v = 0;
  910. if (type == 'l' || type == 'L') {
  911. issigned = input[inputpos + (machine_little_endian ? 3 : 0)] & 0x80;
  912. } else if (type == 'N') {
  913. issigned = input[inputpos] & 0x80;
  914. map = big_endian_long_map;
  915. } else if (type == 'V') {
  916. issigned = input[inputpos + 3] & 0x80;
  917. map = little_endian_long_map;
  918. }
  919. if (SIZEOF_ZEND_LONG > 4 && issigned) {
  920. v = ~INT_MAX;
  921. }
  922. v |= php_unpack(&input[inputpos], 4, issigned, map);
  923. if (SIZEOF_ZEND_LONG > 4) {
  924. if (type == 'l') {
  925. v = (signed int) v;
  926. } else {
  927. v = (unsigned int) v;
  928. }
  929. }
  930. add_assoc_long(return_value, n, v);
  931. break;
  932. }
  933. #if SIZEOF_ZEND_LONG > 4
  934. case 'q':
  935. case 'Q':
  936. case 'J':
  937. case 'P': {
  938. int issigned = 0;
  939. int *map = machine_endian_longlong_map;
  940. zend_long v = 0;
  941. if (type == 'q' || type == 'Q') {
  942. issigned = input[inputpos + (machine_little_endian ? 7 : 0)] & 0x80;
  943. } else if (type == 'J') {
  944. issigned = input[inputpos] & 0x80;
  945. map = big_endian_longlong_map;
  946. } else if (type == 'P') {
  947. issigned = input[inputpos + 7] & 0x80;
  948. map = little_endian_longlong_map;
  949. }
  950. v = php_unpack(&input[inputpos], 8, issigned, map);
  951. if (type == 'q') {
  952. v = (zend_long) v;
  953. } else {
  954. v = (zend_ulong) v;
  955. }
  956. add_assoc_long(return_value, n, v);
  957. break;
  958. }
  959. #endif
  960. case 'f': /* float */
  961. case 'g': /* little endian float*/
  962. case 'G': /* big endian float*/
  963. {
  964. float v;
  965. if (type == 'g') {
  966. v = php_pack_parse_float(1, &input[inputpos]);
  967. } else if (type == 'G') {
  968. v = php_pack_parse_float(0, &input[inputpos]);
  969. } else {
  970. memcpy(&v, &input[inputpos], sizeof(float));
  971. }
  972. add_assoc_double(return_value, n, (double)v);
  973. break;
  974. }
  975. case 'd': /* double */
  976. case 'e': /* little endian float */
  977. case 'E': /* big endian float */
  978. {
  979. double v;
  980. if (type == 'e') {
  981. v = php_pack_parse_double(1, &input[inputpos]);
  982. } else if (type == 'E') {
  983. v = php_pack_parse_double(0, &input[inputpos]);
  984. } else {
  985. memcpy(&v, &input[inputpos], sizeof(double));
  986. }
  987. add_assoc_double(return_value, n, v);
  988. break;
  989. }
  990. case 'x':
  991. /* Do nothing with input, just skip it */
  992. break;
  993. case 'X':
  994. if (inputpos < size) {
  995. inputpos = -size;
  996. i = arg - 1; /* Break out of for loop */
  997. if (arg >= 0) {
  998. php_error_docref(NULL, E_WARNING, "Type %c: outside of string", type);
  999. }
  1000. }
  1001. break;
  1002. case '@':
  1003. if (arg <= inputlen) {
  1004. inputpos = arg;
  1005. } else {
  1006. php_error_docref(NULL, E_WARNING, "Type %c: outside of string", type);
  1007. }
  1008. i = arg - 1; /* Done, break out of for loop */
  1009. break;
  1010. }
  1011. inputpos += size;
  1012. if (inputpos < 0) {
  1013. if (size != -1) { /* only print warning if not working with * */
  1014. php_error_docref(NULL, E_WARNING, "Type %c: outside of string", type);
  1015. }
  1016. inputpos = 0;
  1017. }
  1018. } else if (arg < 0) {
  1019. /* Reached end of input for '*' repeater */
  1020. break;
  1021. } else {
  1022. php_error_docref(NULL, E_WARNING, "Type %c: not enough input, need %d, have " ZEND_LONG_FMT, type, size, inputlen - inputpos);
  1023. zend_array_destroy(Z_ARR_P(return_value));
  1024. RETURN_FALSE;
  1025. }
  1026. }
  1027. if (formatlen > 0) {
  1028. formatlen--; /* Skip '/' separator, does no harm if inputlen == 0 */
  1029. format++;
  1030. }
  1031. }
  1032. }
  1033. /* }}} */
  1034. /* {{{ PHP_MINIT_FUNCTION
  1035. */
  1036. PHP_MINIT_FUNCTION(pack)
  1037. {
  1038. int machine_endian_check = 1;
  1039. int i;
  1040. machine_little_endian = ((char *)&machine_endian_check)[0];
  1041. if (machine_little_endian) {
  1042. /* Where to get lo to hi bytes from */
  1043. byte_map[0] = 0;
  1044. for (i = 0; i < (int)sizeof(int); i++) {
  1045. int_map[i] = i;
  1046. }
  1047. machine_endian_short_map[0] = 0;
  1048. machine_endian_short_map[1] = 1;
  1049. big_endian_short_map[0] = 1;
  1050. big_endian_short_map[1] = 0;
  1051. little_endian_short_map[0] = 0;
  1052. little_endian_short_map[1] = 1;
  1053. machine_endian_long_map[0] = 0;
  1054. machine_endian_long_map[1] = 1;
  1055. machine_endian_long_map[2] = 2;
  1056. machine_endian_long_map[3] = 3;
  1057. big_endian_long_map[0] = 3;
  1058. big_endian_long_map[1] = 2;
  1059. big_endian_long_map[2] = 1;
  1060. big_endian_long_map[3] = 0;
  1061. little_endian_long_map[0] = 0;
  1062. little_endian_long_map[1] = 1;
  1063. little_endian_long_map[2] = 2;
  1064. little_endian_long_map[3] = 3;
  1065. #if SIZEOF_ZEND_LONG > 4
  1066. machine_endian_longlong_map[0] = 0;
  1067. machine_endian_longlong_map[1] = 1;
  1068. machine_endian_longlong_map[2] = 2;
  1069. machine_endian_longlong_map[3] = 3;
  1070. machine_endian_longlong_map[4] = 4;
  1071. machine_endian_longlong_map[5] = 5;
  1072. machine_endian_longlong_map[6] = 6;
  1073. machine_endian_longlong_map[7] = 7;
  1074. big_endian_longlong_map[0] = 7;
  1075. big_endian_longlong_map[1] = 6;
  1076. big_endian_longlong_map[2] = 5;
  1077. big_endian_longlong_map[3] = 4;
  1078. big_endian_longlong_map[4] = 3;
  1079. big_endian_longlong_map[5] = 2;
  1080. big_endian_longlong_map[6] = 1;
  1081. big_endian_longlong_map[7] = 0;
  1082. little_endian_longlong_map[0] = 0;
  1083. little_endian_longlong_map[1] = 1;
  1084. little_endian_longlong_map[2] = 2;
  1085. little_endian_longlong_map[3] = 3;
  1086. little_endian_longlong_map[4] = 4;
  1087. little_endian_longlong_map[5] = 5;
  1088. little_endian_longlong_map[6] = 6;
  1089. little_endian_longlong_map[7] = 7;
  1090. #endif
  1091. }
  1092. else {
  1093. zval val;
  1094. int size = sizeof(Z_LVAL(val));
  1095. Z_LVAL(val)=0; /*silence a warning*/
  1096. /* Where to get hi to lo bytes from */
  1097. byte_map[0] = size - 1;
  1098. for (i = 0; i < (int)sizeof(int); i++) {
  1099. int_map[i] = size - (sizeof(int) - i);
  1100. }
  1101. machine_endian_short_map[0] = size - 2;
  1102. machine_endian_short_map[1] = size - 1;
  1103. big_endian_short_map[0] = size - 2;
  1104. big_endian_short_map[1] = size - 1;
  1105. little_endian_short_map[0] = size - 1;
  1106. little_endian_short_map[1] = size - 2;
  1107. machine_endian_long_map[0] = size - 4;
  1108. machine_endian_long_map[1] = size - 3;
  1109. machine_endian_long_map[2] = size - 2;
  1110. machine_endian_long_map[3] = size - 1;
  1111. big_endian_long_map[0] = size - 4;
  1112. big_endian_long_map[1] = size - 3;
  1113. big_endian_long_map[2] = size - 2;
  1114. big_endian_long_map[3] = size - 1;
  1115. little_endian_long_map[0] = size - 1;
  1116. little_endian_long_map[1] = size - 2;
  1117. little_endian_long_map[2] = size - 3;
  1118. little_endian_long_map[3] = size - 4;
  1119. #if SIZEOF_ZEND_LONG > 4
  1120. machine_endian_longlong_map[0] = size - 8;
  1121. machine_endian_longlong_map[1] = size - 7;
  1122. machine_endian_longlong_map[2] = size - 6;
  1123. machine_endian_longlong_map[3] = size - 5;
  1124. machine_endian_longlong_map[4] = size - 4;
  1125. machine_endian_longlong_map[5] = size - 3;
  1126. machine_endian_longlong_map[6] = size - 2;
  1127. machine_endian_longlong_map[7] = size - 1;
  1128. big_endian_longlong_map[0] = size - 8;
  1129. big_endian_longlong_map[1] = size - 7;
  1130. big_endian_longlong_map[2] = size - 6;
  1131. big_endian_longlong_map[3] = size - 5;
  1132. big_endian_longlong_map[4] = size - 4;
  1133. big_endian_longlong_map[5] = size - 3;
  1134. big_endian_longlong_map[6] = size - 2;
  1135. big_endian_longlong_map[7] = size - 1;
  1136. little_endian_longlong_map[0] = size - 1;
  1137. little_endian_longlong_map[1] = size - 2;
  1138. little_endian_longlong_map[2] = size - 3;
  1139. little_endian_longlong_map[3] = size - 4;
  1140. little_endian_longlong_map[4] = size - 5;
  1141. little_endian_longlong_map[5] = size - 6;
  1142. little_endian_longlong_map[6] = size - 7;
  1143. little_endian_longlong_map[7] = size - 8;
  1144. #endif
  1145. }
  1146. return SUCCESS;
  1147. }
  1148. /* }}} */
  1149. /*
  1150. * Local variables:
  1151. * tab-width: 4
  1152. * c-basic-offset: 4
  1153. * End:
  1154. * vim600: noet sw=4 ts=4 fdm=marker
  1155. * vim<600: noet sw=4 ts=4
  1156. */