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