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