• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/lib/struct.c

  1 /*
  2  * Binary data packing/unpacking module for ucode.
  3  * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io>
  4  *
  5  * This module is heavily based on the Python 3.10 "_struct.c" module source
  6  * published under the following license:
  7  *
  8  * -----------------------------------------------------------------------------------
  9  *
 10  * 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
 11  *    the Individual or Organization ("Licensee") accessing and otherwise using Python
 12  *    3.10.0 software in source or binary form and its associated documentation.
 13  *
 14  * 2. Subject to the terms and conditions of this License Agreement, PSF hereby
 15  *    grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
 16  *    analyze, test, perform and/or display publicly, prepare derivative works,
 17  *    distribute, and otherwise use Python 3.10.0 alone or in any derivative
 18  *    version, provided, however, that PSF's License Agreement and PSF's notice of
 19  *    copyright, i.e., "Copyright © 2001-2021 Python Software Foundation; All Rights
 20  *    Reserved" are retained in Python 3.10.0 alone or in any derivative version
 21  *    prepared by Licensee.
 22  *
 23  * 3. In the event Licensee prepares a derivative work that is based on or
 24  *    incorporates Python 3.10.0 or any part thereof, and wants to make the
 25  *    derivative work available to others as provided herein, then Licensee hereby
 26  *    agrees to include in any such work a brief summary of the changes made to Python
 27  *    3.10.0.
 28  *
 29  * 4. PSF is making Python 3.10.0 available to Licensee on an "AS IS" basis.
 30  *    PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.  BY WAY OF
 31  *    EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
 32  *    WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
 33  *    USE OF PYTHON 3.10.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
 34  *
 35  * 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.10.0
 36  *    FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
 37  *    MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.10.0, OR ANY DERIVATIVE
 38  *    THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
 39  *
 40  * 6. This License Agreement will automatically terminate upon a material breach of
 41  *    its terms and conditions.
 42  *
 43  * 7. Nothing in this License Agreement shall be deemed to create any relationship
 44  *    of agency, partnership, or joint venture between PSF and Licensee.  This License
 45  *    Agreement does not grant permission to use PSF trademarks or trade name in a
 46  *    trademark sense to endorse or promote products or services of Licensee, or any
 47  *    third party.
 48  *
 49  * 8. By copying, installing or otherwise using Python 3.10.0, Licensee agrees
 50  *    to be bound by the terms and conditions of this License Agreement.
 51  *
 52  * -----------------------------------------------------------------------------------
 53  *
 54  * Brief summary of changes compared to the original Python 3.10 source:
 55  *
 56  * - Inlined and refactored IEEE 754 float conversion routines
 57  * - Usage of stdbool for function return values and boolean parameters
 58  * - Renamed functions and structures for clarity
 59  * - Interface adapated to ucode C api
 60  * - Removed unused code
 61  */
 62 
 63 #include <ctype.h>
 64 #include <errno.h>
 65 #include <limits.h>
 66 #include <math.h>
 67 #include <stdlib.h>
 68 #include <float.h>
 69 #include <assert.h>
 70 
 71 #include "ucode/module.h"
 72 #include "ucode/vallist.h"
 73 
 74 static uc_resource_type_t *struct_type;
 75 
 76 typedef struct formatdef {
 77         char format;
 78         ssize_t size;
 79         ssize_t alignment;
 80         uc_value_t* (*unpack)(uc_vm_t *, const char *, const struct formatdef *);
 81         bool (*pack)(uc_vm_t *, char *, uc_value_t *, const struct formatdef *);
 82 } formatdef_t;
 83 
 84 typedef struct {
 85         const formatdef_t *fmtdef;
 86         ssize_t offset;
 87         ssize_t size;
 88         ssize_t repeat;
 89 } formatcode_t;
 90 
 91 typedef struct {
 92         size_t len;
 93         size_t size;
 94         size_t ncodes;
 95         formatcode_t codes[];
 96 } formatstate_t;
 97 
 98 
 99 /* Define various structs to figure out the alignments of types */
100 
101 typedef struct { char c; short x; } st_short;
102 typedef struct { char c; int x; } st_int;
103 typedef struct { char c; long x; } st_long;
104 typedef struct { char c; float x; } st_float;
105 typedef struct { char c; double x; } st_double;
106 typedef struct { char c; void *x; } st_void_p;
107 typedef struct { char c; size_t x; } st_size_t;
108 typedef struct { char c; bool x; } st_bool;
109 typedef struct { char c; long long x; } s_long_long;
110 
111 #define SHORT_ALIGN (sizeof(st_short) - sizeof(short))
112 #define INT_ALIGN (sizeof(st_int) - sizeof(int))
113 #define LONG_ALIGN (sizeof(st_long) - sizeof(long))
114 #define FLOAT_ALIGN (sizeof(st_float) - sizeof(float))
115 #define DOUBLE_ALIGN (sizeof(st_double) - sizeof(double))
116 #define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))
117 #define SIZE_T_ALIGN (sizeof(st_size_t) - sizeof(size_t))
118 #define BOOL_ALIGN (sizeof(st_bool) - sizeof(bool))
119 #define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(long long))
120 
121 #ifdef __powerc
122 #pragma options align=reset
123 #endif
124 
125 
126 static bool
127 ucv_as_long(uc_vm_t *vm, uc_value_t *v, long *p)
128 {
129         char *s, *e;
130         int64_t i;
131         double d;
132         long x;
133 
134         errno = 0;
135 
136         switch (ucv_type(v)) {
137         case UC_INTEGER:
138                 i = ucv_int64_get(v);
139 
140                 if (i < LONG_MIN || i > LONG_MAX)
141                         errno = ERANGE;
142 
143                 x = (long)i;
144                 break;
145 
146         case UC_DOUBLE:
147                 d = ucv_double_get(v);
148                 x = (long)d;
149 
150                 if (isnan(d) || d < (double)LONG_MIN || d > (double)LONG_MAX || d - x != 0)
151                         errno = ERANGE;
152 
153                 break;
154 
155         case UC_BOOLEAN:
156                 x = (long)ucv_boolean_get(v);
157                 break;
158 
159         case UC_NULL:
160                 x = 0;
161                 break;
162 
163         case UC_STRING:
164                 s = ucv_string_get(v);
165                 x = strtol(s, &e, 0);
166 
167                 if (e == s || *e != '\0')
168                         errno = EINVAL;
169 
170                 break;
171 
172         default:
173                 errno = EINVAL;
174                 x = 0;
175                 break;
176         }
177 
178         if (errno != 0) {
179                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
180                         (errno == ERANGE)
181                                 ? "Argument out of range"
182                                 : "Argument not convertible to number");
183 
184                 return false;
185         }
186 
187         *p = x;
188 
189         return true;
190 }
191 
192 static bool
193 ucv_as_ulong(uc_vm_t *vm, uc_value_t *v, unsigned long *p)
194 {
195         unsigned long x;
196         char *s, *e;
197         uint64_t i;
198         double d;
199 
200         errno = 0;
201 
202         switch (ucv_type(v)) {
203         case UC_INTEGER:
204                 i = ucv_uint64_get(v);
205 
206                 if (i > ULONG_MAX)
207                         errno = ERANGE;
208 
209                 x = (unsigned long)i;
210                 break;
211 
212         case UC_DOUBLE:
213                 d = ucv_double_get(v);
214                 x = (unsigned long)d;
215 
216                 if (isnan(d) || d < 0 || d > (double)ULONG_MAX || d - x != 0)
217                         errno = ERANGE;
218 
219                 break;
220 
221         case UC_BOOLEAN:
222                 x = (unsigned long)ucv_boolean_get(v);
223                 break;
224 
225         case UC_NULL:
226                 x = 0;
227                 break;
228 
229         case UC_STRING:
230                 s = ucv_string_get(v);
231                 x = strtoul(s, &e, 0);
232 
233                 if (e == s || *e != '\0')
234                         errno = EINVAL;
235 
236                 break;
237 
238         default:
239                 errno = EINVAL;
240                 x = 0;
241                 break;
242         }
243 
244         if (errno != 0) {
245                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
246                         (errno == ERANGE)
247                                 ? "Argument out of range"
248                                 : "Argument not convertible to number");
249 
250                 return false;
251         }
252 
253         *p = x;
254 
255         return true;
256 }
257 
258 static bool
259 ucv_as_longlong(uc_vm_t *vm, uc_value_t *v, long long *p)
260 {
261         char *s, *e;
262         long long x;
263         int64_t i;
264         double d;
265 
266         errno = 0;
267 
268         switch (ucv_type(v)) {
269         case UC_INTEGER:
270                 i = ucv_int64_get(v);
271 
272                 if (i < LLONG_MIN || i > LLONG_MAX)
273                         errno = ERANGE;
274 
275                 x = (long long)i;
276                 break;
277 
278         case UC_DOUBLE:
279                 d = ucv_double_get(v);
280                 x = (long long)d;
281 
282                 if (isnan(d) || d < (double)LLONG_MIN || d > (double)LLONG_MAX || d - x != 0)
283                         errno = ERANGE;
284 
285                 break;
286 
287         case UC_BOOLEAN:
288                 x = (long long)ucv_boolean_get(v);
289                 break;
290 
291         case UC_NULL:
292                 x = 0;
293                 break;
294 
295         case UC_STRING:
296                 s = ucv_string_get(v);
297                 x = strtoll(s, &e, 0);
298 
299                 if (e == s || *e != '\0')
300                         errno = EINVAL;
301 
302                 break;
303 
304         default:
305                 errno = EINVAL;
306                 x = 0;
307                 break;
308         }
309 
310         if (errno != 0) {
311                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
312                         (errno == ERANGE)
313                                 ? "Argument out of range"
314                                 : "Argument not convertible to number");
315 
316                 return false;
317         }
318 
319         *p = x;
320 
321         return true;
322 }
323 
324 static bool
325 ucv_as_ulonglong(uc_vm_t *vm, uc_value_t *v, unsigned long long *p)
326 {
327         unsigned long long x;
328         char *s, *e;
329         uint64_t i;
330         double d;
331 
332         errno = 0;
333 
334         switch (ucv_type(v)) {
335         case UC_INTEGER:
336                 i = ucv_uint64_get(v);
337 
338                 if (i > ULLONG_MAX)
339                         errno = ERANGE;
340 
341                 x = (unsigned long long)i;
342                 break;
343 
344         case UC_DOUBLE:
345                 d = ucv_double_get(v);
346                 x = (unsigned long long)d;
347 
348                 if (isnan(d) || d < 0 || d > (double)ULLONG_MAX || d - x != 0)
349                         errno = ERANGE;
350 
351                 break;
352 
353         case UC_BOOLEAN:
354                 x = (unsigned long long)ucv_boolean_get(v);
355                 break;
356 
357         case UC_NULL:
358                 x = 0;
359                 break;
360 
361         case UC_STRING:
362                 s = ucv_string_get(v);
363                 x = strtoull(s, &e, 0);
364 
365                 if (e == s || *e != '\0')
366                         errno = EINVAL;
367 
368                 break;
369 
370         default:
371                 errno = EINVAL;
372                 x = 0;
373                 break;
374         }
375 
376         if (errno != 0) {
377                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
378                         (errno == ERANGE)
379                                 ? "Argument out of range"
380                                 : "Argument not convertible to number");
381 
382                 return false;
383         }
384 
385         *p = x;
386 
387         return true;
388 }
389 
390 static bool
391 ucv_as_ssize_t(uc_vm_t *vm, uc_value_t *v, ssize_t *p)
392 {
393         char *s, *e;
394         int64_t i;
395         ssize_t x;
396         double d;
397 
398         errno = 0;
399 
400         switch (ucv_type(v)) {
401         case UC_INTEGER:
402                 i = ucv_int64_get(v);
403 
404                 if (i < -1 || i > SSIZE_MAX)
405                         errno = ERANGE;
406 
407                 x = (ssize_t)i;
408                 break;
409 
410         case UC_DOUBLE:
411                 d = ucv_double_get(v);
412                 x = (ssize_t)d;
413 
414                 if (isnan(d) || d < -1 || d > (double)SSIZE_MAX || d - x != 0)
415                         errno = ERANGE;
416 
417                 break;
418 
419         case UC_BOOLEAN:
420                 x = (ssize_t)ucv_boolean_get(v);
421                 break;
422 
423         case UC_NULL:
424                 x = 0;
425                 break;
426 
427         case UC_STRING:
428                 s = ucv_string_get(v);
429                 i = strtoll(s, &e, 0);
430 
431                 if (e == s || *e != '\0')
432                         errno = EINVAL;
433                 else if (i < -1 || i > SSIZE_MAX)
434                         errno = ERANGE;
435 
436                 x = (ssize_t)i;
437                 break;
438 
439         default:
440                 errno = EINVAL;
441                 x = 0;
442                 break;
443         }
444 
445         if (errno != 0) {
446                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
447                         (errno == ERANGE)
448                                 ? "Argument out of range"
449                                 : "Argument not convertible to number");
450 
451                 return false;
452         }
453 
454         *p = x;
455 
456         return true;
457 }
458 
459 /* Same, but handling size_t */
460 
461 static bool
462 ucv_as_size_t(uc_vm_t *vm, uc_value_t *v, size_t *p)
463 {
464         char *s, *e;
465         uint64_t i;
466         double d;
467         size_t x;
468 
469         errno = 0;
470 
471         switch (ucv_type(v)) {
472         case UC_INTEGER:
473                 i = ucv_uint64_get(v);
474 
475                 if (i > SIZE_MAX)
476                         errno = ERANGE;
477 
478                 x = (size_t)i;
479                 break;
480 
481         case UC_DOUBLE:
482                 d = ucv_double_get(v);
483                 x = (size_t)d;
484 
485                 if (isnan(d) || d < 0 || d > (double)SIZE_MAX || d - x != 0)
486                         errno = ERANGE;
487 
488                 break;
489 
490         case UC_BOOLEAN:
491                 x = (size_t)ucv_boolean_get(v);
492                 break;
493 
494         case UC_NULL:
495                 x = 0;
496                 break;
497 
498         case UC_STRING:
499                 s = ucv_string_get(v);
500                 i = strtoull(s, &e, 0);
501 
502                 if (e == s || *e != '\0')
503                         errno = EINVAL;
504                 else if (i > SIZE_MAX)
505                         errno = ERANGE;
506 
507                 x = (size_t)i;
508                 break;
509 
510         default:
511                 errno = EINVAL;
512                 x = 0;
513                 break;
514         }
515 
516         if (errno != 0) {
517                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
518                         (errno == ERANGE)
519                                 ? "Argument out of range"
520                                 : "Argument not convertible to number");
521 
522                 return false;
523         }
524 
525         *p = x;
526 
527         return true;
528 }
529 
530 static bool
531 ucv_as_double(uc_vm_t *vm, uc_value_t *v, double *p)
532 {
533         char *s, *e;
534         int64_t i;
535         double x;
536 
537         errno = 0;
538 
539         switch (ucv_type(v)) {
540         case UC_INTEGER:
541                 i = ucv_int64_get(v);
542 
543                 if (errno == 0) {
544                         if (i < -DBL_MAX || i > DBL_MAX)
545                                 errno = ERANGE;
546                 }
547 
548                 x = (double)i;
549                 break;
550 
551         case UC_DOUBLE:
552                 x = ucv_double_get(v);
553                 break;
554 
555         case UC_BOOLEAN:
556                 x = (double)ucv_boolean_get(v);
557                 break;
558 
559         case UC_NULL:
560                 x = 0.0;
561                 break;
562 
563         case UC_STRING:
564                 s = ucv_string_get(v);
565                 x = strtod(s, &e);
566 
567                 if (e == s || *e != '\0')
568                         errno = EINVAL;
569 
570                 break;
571 
572         default:
573                 errno = EINVAL;
574                 x = 0.0;
575                 break;
576         }
577 
578         if (errno != 0) {
579                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
580                         (errno == ERANGE)
581                                 ? "Argument out of range"
582                                 : "Argument not convertible to number");
583 
584                 return false;
585         }
586 
587         *p = x;
588 
589         return true;
590 }
591 
592 
593 /* Floating point helpers */
594 
595 static bool
596 double_pack16(double d, char *buf, bool little_endian)
597 {
598         int32_t exponent = 0;
599         uint16_t bits = 0;
600         bool sign = false;
601         double fraction;
602         uint8_t *p;
603 
604         if (d == 0.0) {
605                 sign = (copysign(1.0, d) == -1.0);
606         }
607         else if (isnan(d)) {
608                 sign = (copysign(1.0, d) == -1.0);
609                 exponent = 0x1f;
610                 bits = 512;
611         }
612         else if (!isfinite(d)) {
613                 sign = (d < 0.0);
614                 exponent = 0x1f;
615         }
616         else {
617                 if (d < 0.0) {
618                         sign = true;
619                         d = -d;
620                 }
621 
622                 fraction = frexp(d, &exponent);
623 
624                 assert(fraction >= 0.5 && fraction < 1.0);
625 
626                 fraction *= 2.0;
627                 exponent--;
628 
629                 if (exponent >= 16) {
630                         errno = ERANGE;
631 
632                         return false;
633                 }
634                 else if (exponent < -25) {
635                         fraction = 0.0;
636                         exponent = 0;
637                 }
638                 else if (exponent < -14) {
639                         fraction = ldexp(fraction, 14 + exponent);
640                         exponent = 0;
641                 }
642                 else {
643                         fraction -= 1.0;
644                         exponent += 15;
645                 }
646 
647                 fraction *= 1024.0;
648                 bits = (uint16_t)fraction;
649 
650                 assert(bits < 1024);
651                 assert(exponent < 31);
652 
653                 if ((fraction - bits > 0.5) || ((fraction - bits == 0.5) && (bits % 2))) {
654                         if (++bits == 1024) {
655                                 bits = 0;
656 
657                                 if (++exponent == 31) {
658                                         errno = ERANGE;
659 
660                                         return false;
661                                 }
662                         }
663                 }
664         }
665 
666         bits |= (exponent << 10) | (sign << 15);
667 
668         p = (uint8_t *)buf + little_endian;
669         *p = (bits >> 8) & 0xff;
670 
671         p += (little_endian ? -1 : 1);
672         *p = bits & 0xff;
673 
674         return true;
675 }
676 
677 static bool
678 double_pack32(double d, char *buf, bool little_endian)
679 {
680         int8_t step = little_endian ? -1 : 1;
681         int32_t exponent = 0;
682         uint32_t bits = 0;
683         bool sign = false;
684         double fraction;
685         uint8_t *p;
686 
687         if (d == 0.0) {
688                 sign = (copysign(1.0, d) == -1.0);
689         }
690         else if (isnan(d)) {
691                 sign = (copysign(1.0, d) == -1.0);
692                 exponent = 0xff;
693                 bits = 0x7fffff;
694         }
695         else if (!isfinite(d)) {
696                 sign = (d < 0.0);
697                 exponent = 0xff;
698         }
699         else {
700                 if (d < 0.0) {
701                         sign = true;
702                         d = -d;
703                 }
704 
705                 fraction = frexp(d, &exponent);
706 
707                 if (fraction == 0.0) {
708                         exponent = 0;
709                 }
710                 else {
711                         assert(fraction >= 0.5 && fraction < 1.0);
712 
713                         fraction *= 2.0;
714                         exponent--;
715                 }
716 
717                 if (exponent >= 128) {
718                         errno = ERANGE;
719 
720                         return false;
721                 }
722                 else if (exponent < -126) {
723                         fraction = ldexp(fraction, 126 + exponent);
724                         exponent = 0;
725                 }
726                 else if (exponent != 0 || fraction != 0.0) {
727                         fraction -= 1.0;
728                         exponent += 127;
729                 }
730 
731                 fraction *= 8388608.0;
732                 bits = (uint32_t)(fraction + 0.5);
733 
734                 assert(bits <= 8388608);
735 
736                 if (bits >> 23) {
737                         bits = 0;
738 
739                         if (++exponent >= 255) {
740                                 errno = ERANGE;
741 
742                                 return false;
743                         }
744                 }
745         }
746 
747         p = (uint8_t *)buf + (little_endian ? 3 : 0);
748         *p = (sign << 7) | (exponent >> 1);
749 
750         p += step;
751         *p = ((exponent & 1) << 7) | (bits >> 16);
752 
753         p += step;
754         *p = (bits >> 8) & 0xff;
755 
756         p += step;
757         *p = bits & 0xff;
758 
759         return true;
760 }
761 
762 #define double_pack64 uc_double_pack
763 
764 static double
765 double_unpack16(const char *buf, bool little_endian)
766 {
767         uint32_t fraction;
768         int32_t exponent;
769         uint8_t *p;
770         bool sign;
771         double d;
772 
773         p = (uint8_t *)buf + little_endian;
774         sign = (*p >> 7) & 1;
775         exponent = (*p & 0x7c) >> 2;
776         fraction = (*p & 0x03) << 8;
777 
778         p += little_endian ? -1 : 1;
779         fraction |= *p;
780 
781         if (exponent == 0x1f) {
782                 if (fraction == 0)
783                         return sign ? -INFINITY : INFINITY;
784                 else
785                         return sign ? -NAN : NAN;
786         }
787 
788         d = (double)fraction / 1024.0;
789 
790         if (exponent == 0) {
791                 exponent = -14;
792         }
793         else {
794                 exponent -= 15;
795                 d += 1.0;
796         }
797 
798         d = ldexp(d, exponent);
799 
800         return sign ? -d : d;
801 }
802 
803 static double
804 double_unpack32(const char *buf, bool little_endian)
805 {
806         int8_t step = little_endian ? -1 : 1;
807         uint32_t fraction;
808         int32_t exponent;
809         uint8_t *p;
810         bool sign;
811         double d;
812 
813         p = (uint8_t *)buf + (little_endian ? 3 : 0);
814         sign = (*p >> 7) & 1;
815         exponent = (*p & 0x7f) << 1;
816 
817         p += step;
818         exponent |= (*p >> 7) & 1;
819         fraction = (*p & 0x7f) << 16;
820 
821         p += step;
822         fraction |= *p << 8;
823 
824         p += step;
825         fraction |= *p;
826 
827         if (exponent == 0xff) {
828                 if (fraction == 0)
829                         return sign ? -INFINITY : INFINITY;
830                 else
831                         return sign ? -NAN : NAN;
832         }
833 
834         d = (double)fraction / 8388608.0;
835 
836         if (exponent == 0) {
837                 exponent = -126;
838         }
839         else {
840                 exponent -= 127;
841                 d += 1.0;
842         }
843 
844         d = ldexp(d, exponent);
845 
846         return sign ? -d : d;
847 }
848 
849 #define double_unpack64 uc_double_unpack
850 
851 static bool
852 range_exception(uc_vm_t *vm, const formatdef_t *f, bool is_unsigned)
853 {
854         /* ulargest is the largest unsigned value with f->size bytes.
855          * Note that the simpler:
856          *       ((size_t)1 << (f->size * 8)) - 1
857          * doesn't work when f->size == sizeof(size_t) because C doesn't
858          * define what happens when a left shift count is >= the number of
859          * bits in the integer being shifted; e.g., on some boxes it doesn't
860          * shift at all when they're equal.
861          */
862         const size_t ulargest = (size_t)-1 >> ((sizeof(size_t) - f->size)*8);
863 
864         assert(f->size >= 1 && f->size <= (ssize_t)sizeof(size_t));
865 
866         if (is_unsigned) {
867                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
868                         "Format '%c' requires numeric argument between 0 and %zu",
869                         f->format,
870                         ulargest);
871         }
872         else {
873                 const ssize_t largest = (ssize_t)(ulargest >> 1);
874 
875                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
876                         "Format '%c' requires numeric argument between %zd and %zd",
877                         f->format,
878                         ~ largest,
879                         largest);
880         }
881 
882         return false;
883 }
884 
885 
886 /* Native mode routines. ****************************************************/
887 
888 static uc_value_t *
889 native_unpack_char(uc_vm_t *vm, const char *p, const formatdef_t *f)
890 {
891         return ucv_string_new_length(p, 1);
892 }
893 
894 static uc_value_t *
895 native_unpack_byte(uc_vm_t *vm, const char *p, const formatdef_t *f)
896 {
897         return ucv_int64_new(*(signed char *)p);
898 }
899 
900 static uc_value_t *
901 native_unpack_ubyte(uc_vm_t *vm, const char *p, const formatdef_t *f)
902 {
903         return ucv_uint64_new(*(unsigned char *)p);
904 }
905 
906 static uc_value_t *
907 native_unpack_short(uc_vm_t *vm, const char *p, const formatdef_t *f)
908 {
909         short x = 0;
910 
911         memcpy(&x, p, sizeof(x));
912 
913         return ucv_int64_new(x);
914 }
915 
916 static uc_value_t *
917 native_unpack_ushort(uc_vm_t *vm, const char *p, const formatdef_t *f)
918 {
919         unsigned short x = 0;
920 
921         memcpy(&x, p, sizeof(x));
922 
923         return ucv_uint64_new(x);
924 }
925 
926 static uc_value_t *
927 native_unpack_int(uc_vm_t *vm, const char *p, const formatdef_t *f)
928 {
929         int x = 0;
930 
931         memcpy(&x, p, sizeof(x));
932 
933         return ucv_int64_new(x);
934 }
935 
936 static uc_value_t *
937 native_unpack_uint(uc_vm_t *vm, const char *p, const formatdef_t *f)
938 {
939         unsigned int x = 0;
940 
941         memcpy(&x, p, sizeof(x));
942 
943         return ucv_uint64_new(x);
944 }
945 
946 static uc_value_t *
947 native_unpack_long(uc_vm_t *vm, const char *p, const formatdef_t *f)
948 {
949         long x = 0;
950 
951         memcpy(&x, p, sizeof(x));
952 
953         return ucv_int64_new(x);
954 }
955 
956 static uc_value_t *
957 native_unpack_ulong(uc_vm_t *vm, const char *p, const formatdef_t *f)
958 {
959         unsigned long x = 0;
960 
961         memcpy(&x, p, sizeof(x));
962 
963         return ucv_uint64_new(x);
964 }
965 
966 static uc_value_t *
967 native_unpack_ssize_t(uc_vm_t *vm, const char *p, const formatdef_t *f)
968 {
969         ssize_t x = 0;
970 
971         memcpy(&x, p, sizeof(x));
972 
973         return ucv_int64_new(x);
974 }
975 
976 static uc_value_t *
977 native_unpack_size_t(uc_vm_t *vm, const char *p, const formatdef_t *f)
978 {
979         size_t x = 0;
980 
981         memcpy(&x, p, sizeof(x));
982 
983         return ucv_uint64_new(x);
984 }
985 
986 static uc_value_t *
987 native_unpack_longlong(uc_vm_t *vm, const char *p, const formatdef_t *f)
988 {
989         long long x = 0;
990 
991         memcpy(&x, p, sizeof(x));
992 
993         return ucv_int64_new(x);
994 }
995 
996 static uc_value_t *
997 native_unpack_ulonglong(uc_vm_t *vm, const char *p, const formatdef_t *f)
998 {
999         unsigned long long x = 0;
1000 
1001         memcpy(&x, p, sizeof(x));
1002 
1003         return ucv_uint64_new(x);
1004 }
1005 
1006 static uc_value_t *
1007 native_unpack_bool(uc_vm_t *vm, const char *p, const formatdef_t *f)
1008 {
1009         bool x = false;
1010 
1011         memcpy(&x, p, sizeof(x));
1012 
1013         return ucv_boolean_new(x != 0);
1014 }
1015 
1016 
1017 static uc_value_t *
1018 native_unpack_halffloat(uc_vm_t *vm, const char *p, const formatdef_t *f)
1019 {
1020 #if __BYTE_ORDER == __LITTLE_ENDIAN
1021         return ucv_double_new(double_unpack16(p, true));
1022 #else
1023         return ucv_double_new(double_unpack16(p, false));
1024 #endif
1025 }
1026 
1027 static uc_value_t *
1028 native_unpack_float(uc_vm_t *vm, const char *p, const formatdef_t *f)
1029 {
1030         float x = 0.0;
1031 
1032         memcpy(&x, p, sizeof(x));
1033 
1034         return ucv_double_new(x);
1035 }
1036 
1037 static uc_value_t *
1038 native_unpack_double(uc_vm_t *vm, const char *p, const formatdef_t *f)
1039 {
1040         double x = 0.0;
1041 
1042         memcpy(&x, p, sizeof(x));
1043 
1044         return ucv_double_new(x);
1045 }
1046 
1047 static uc_value_t *
1048 native_unpack_void_p(uc_vm_t *vm, const char *p, const formatdef_t *f)
1049 {
1050         void *x = NULL;
1051 
1052         memcpy(&x, p, sizeof(x));
1053 
1054         return ucv_int64_new((intptr_t)x);
1055 }
1056 
1057 static bool
1058 native_pack_byte(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1059 {
1060         long x = 0;
1061 
1062         if (!ucv_as_long(vm, v, &x))
1063                 return false;
1064 
1065         if (x < -128 || x > 127) {
1066                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1067                         "Byte format requires numeric value between -128 and 127");
1068 
1069                 return false;
1070         }
1071 
1072         *p = (char)x;
1073 
1074         return true;
1075 }
1076 
1077 static bool
1078 native_pack_ubyte(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1079 {
1080         long x = 0;
1081 
1082         if (!ucv_as_long(vm, v, &x))
1083                 return false;
1084 
1085         if (x < 0 || x > 255) {
1086                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1087                         "Unsigned byte format requires numeric value between 0 and 255");
1088 
1089                 return false;
1090         }
1091 
1092         *(unsigned char *)p = (unsigned char)x;
1093 
1094         return true;
1095 }
1096 
1097 static bool
1098 native_pack_char(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1099 {
1100         char *s = NULL;
1101 
1102         if (ucv_type(v) == UC_STRING) {
1103                 s = ucv_string_get(v);
1104                 *p = *s;
1105         }
1106         else {
1107                 s = ucv_to_string(vm, v);
1108                 *p = *s;
1109                 free(s);
1110         }
1111 
1112         return true;
1113 }
1114 
1115 static bool
1116 native_pack_short(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1117 {
1118         long x = 0;
1119         short y = 0;
1120 
1121         if (!ucv_as_long(vm, v, &x))
1122                 return false;
1123 
1124         if (x < SHRT_MIN || x > SHRT_MAX) {
1125                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1126                         "Short format requires numeric value between %d and %d",
1127                         (int)SHRT_MIN, (int)SHRT_MAX);
1128 
1129                 return false;
1130         }
1131 
1132         y = (short)x;
1133         memcpy(p, &y, sizeof(y));
1134 
1135         return true;
1136 }
1137 
1138 static bool
1139 native_pack_ushort(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1140 {
1141         unsigned short y = 0;
1142         long x = 0;
1143 
1144         if (!ucv_as_long(vm, v, &x))
1145                 return false;
1146 
1147         if (x < 0 || x > USHRT_MAX) {
1148                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1149                         "Unsigned short format requires numeric value between 0 and %u",
1150                         (unsigned int)USHRT_MAX);
1151 
1152                 return false;
1153         }
1154 
1155         y = (unsigned short)x;
1156         memcpy(p, &y, sizeof(y));
1157 
1158         return true;
1159 }
1160 
1161 static bool
1162 native_pack_int(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1163 {
1164         long x = 0;
1165         int y = 0;
1166 
1167         if (!ucv_as_long(vm, v, &x))
1168                 return false;
1169 
1170         if (sizeof(long) > sizeof(int)) {
1171                 if ((x < ((long)INT_MIN)) || (x > ((long)INT_MAX)))
1172                         return range_exception(vm, f, false);
1173         }
1174 
1175         y = (int)x;
1176         memcpy(p, &y, sizeof(y));
1177 
1178         return true;
1179 }
1180 
1181 static bool
1182 native_pack_uint(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1183 {
1184         unsigned long x = 0;
1185         unsigned int y = 0;
1186 
1187         if (!ucv_as_ulong(vm, v, &x))
1188                 return false;
1189 
1190         if (sizeof(long) > sizeof(int)) {
1191                 if (x > ((unsigned long)UINT_MAX))
1192                         return range_exception(vm, f, true);
1193         }
1194 
1195         y = (unsigned int)x;
1196         memcpy(p, &y, sizeof(y));
1197 
1198         return true;
1199 }
1200 
1201 static bool
1202 native_pack_long(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1203 {
1204         long x = 0;
1205 
1206         if (!ucv_as_long(vm, v, &x))
1207                 return false;
1208 
1209         memcpy(p, &x, sizeof(x));
1210 
1211         return true;
1212 }
1213 
1214 static bool
1215 native_pack_ulong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1216 {
1217         unsigned long x = 0;
1218 
1219         if (!ucv_as_ulong(vm, v, &x))
1220                 return false;
1221 
1222         memcpy(p, &x, sizeof(x));
1223 
1224         return true;
1225 }
1226 
1227 static bool
1228 native_pack_ssize_t(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1229 {
1230         ssize_t x = 0;
1231 
1232         if (!ucv_as_ssize_t(vm, v, &x))
1233                 return false;
1234 
1235         memcpy(p, &x, sizeof(x));
1236 
1237         return true;
1238 }
1239 
1240 static bool
1241 native_pack_size_t(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1242 {
1243         size_t x = 0;
1244 
1245         if (!ucv_as_size_t(vm, v, &x))
1246                 return false;
1247 
1248         memcpy(p, &x, sizeof(x));
1249 
1250         return true;
1251 }
1252 
1253 static bool
1254 native_pack_longlong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1255 {
1256         long long x = 0;
1257 
1258         if (!ucv_as_longlong(vm, v, &x))
1259                 return false;
1260 
1261         memcpy(p, &x, sizeof(x));
1262 
1263         return true;
1264 }
1265 
1266 static bool
1267 native_pack_ulonglong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1268 {
1269         unsigned long long x = 0;
1270 
1271         if (!ucv_as_ulonglong(vm, v, &x))
1272                 return false;
1273 
1274         memcpy(p, &x, sizeof(x));
1275 
1276         return true;
1277 }
1278 
1279 
1280 static bool
1281 native_pack_bool(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1282 {
1283         bool x = 0;
1284 
1285         x = ucv_is_truish(v);
1286 
1287         memcpy(p, &x, sizeof(x));
1288 
1289         return true;
1290 }
1291 
1292 static bool
1293 native_pack_halffloat(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1294 {
1295         double x;
1296 
1297         if (!ucv_as_double(vm, v, &x))
1298                 return false;
1299 
1300 #if __BYTE_ORDER == __LITTLE_ENDIAN
1301         return double_pack16(x, p, true);
1302 #else
1303         return double_pack16(x, p, false);
1304 #endif
1305 }
1306 
1307 static bool
1308 native_pack_float(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1309 {
1310         double d = 0.0;
1311         float x = 0.0;
1312 
1313         if (!ucv_as_double(vm, v, &d))
1314                 return false;
1315 
1316         x = (float)d;
1317         memcpy(p, &x, sizeof(x));
1318 
1319         return true;
1320 }
1321 
1322 static bool
1323 native_pack_double(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1324 {
1325         double x = 0.0;
1326 
1327         if (!ucv_as_double(vm, v, &x))
1328                 return false;
1329 
1330         memcpy(p, &x, sizeof(x));
1331 
1332         return true;
1333 }
1334 
1335 static bool
1336 native_pack_void_p(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1337 {
1338         long long int i = 0;
1339         void *x = NULL;
1340 
1341         if (!ucv_as_longlong(vm, v, &i))
1342                 return false;
1343 
1344         x = (void *)(intptr_t)i;
1345         memcpy(p, &x, sizeof(x));
1346 
1347         return true;
1348 }
1349 
1350 static const formatdef_t native_endian_table[] = {
1351         { 'x', sizeof(char), 0, NULL, NULL },
1352         { 'b', sizeof(char), 0, native_unpack_byte, native_pack_byte },
1353         { 'B', sizeof(char), 0, native_unpack_ubyte, native_pack_ubyte },
1354         { 'c', sizeof(char), 0, native_unpack_char, native_pack_char },
1355         { '*', sizeof(char), 0, NULL, NULL },
1356         { 's', sizeof(char), 0, NULL, NULL },
1357         { 'p', sizeof(char), 0, NULL, NULL },
1358         { 'h', sizeof(short), SHORT_ALIGN, native_unpack_short, native_pack_short },
1359         { 'H', sizeof(short), SHORT_ALIGN, native_unpack_ushort, native_pack_ushort },
1360         { 'i', sizeof(int),     INT_ALIGN, native_unpack_int, native_pack_int },
1361         { 'I', sizeof(int),     INT_ALIGN, native_unpack_uint, native_pack_uint },
1362         { 'l', sizeof(long), LONG_ALIGN, native_unpack_long, native_pack_long },
1363         { 'L', sizeof(long), LONG_ALIGN, native_unpack_ulong, native_pack_ulong },
1364         { 'n', sizeof(size_t), SIZE_T_ALIGN, native_unpack_ssize_t, native_pack_ssize_t },
1365         { 'N', sizeof(size_t), SIZE_T_ALIGN, native_unpack_size_t, native_pack_size_t },
1366         { 'q', sizeof(long long), LONG_LONG_ALIGN, native_unpack_longlong, native_pack_longlong },
1367         { 'Q', sizeof(long long), LONG_LONG_ALIGN, native_unpack_ulonglong,native_pack_ulonglong },
1368         { '?', sizeof(bool), BOOL_ALIGN, native_unpack_bool, native_pack_bool },
1369         { 'e', sizeof(short), SHORT_ALIGN, native_unpack_halffloat, native_pack_halffloat },
1370         { 'f', sizeof(float), FLOAT_ALIGN, native_unpack_float, native_pack_float },
1371         { 'd', sizeof(double), DOUBLE_ALIGN, native_unpack_double, native_pack_double },
1372         { 'P', sizeof(void *), VOID_P_ALIGN, native_unpack_void_p, native_pack_void_p },
1373         { 0 }
1374 };
1375 
1376 
1377 /* Big-endian routines. *****************************************************/
1378 
1379 static uc_value_t *
1380 be_unpack_int(uc_vm_t *vm, const char *p, const formatdef_t *f)
1381 {
1382         const unsigned char *bytes = (const unsigned char *)p;
1383         ssize_t i = f->size;
1384         long x = 0;
1385 
1386         do {
1387                 x = (x<<8) | *bytes++;
1388         } while (--i > 0);
1389 
1390         /* Extend the sign bit. */
1391         if ((ssize_t)sizeof(long) > f->size)
1392                 x |= -(x & (1L << ((8 * f->size) - 1)));
1393 
1394         return ucv_int64_new(x);
1395 }
1396 
1397 static uc_value_t *
1398 be_unpack_uint(uc_vm_t *vm, const char *p, const formatdef_t *f)
1399 {
1400         const unsigned char *bytes = (const unsigned char *)p;
1401         ssize_t i = f->size;
1402         unsigned long x = 0;
1403 
1404         do {
1405                 x = (x<<8) | *bytes++;
1406         } while (--i > 0);
1407 
1408         return ucv_uint64_new(x);
1409 }
1410 
1411 static uc_value_t *
1412 be_unpack_longlong(uc_vm_t *vm, const char *p, const formatdef_t *f)
1413 {
1414         const unsigned char *bytes = (const unsigned char *)p;
1415         ssize_t i = f->size;
1416         long long x = 0;
1417 
1418         do {
1419                 x = (x<<8) | *bytes++;
1420         } while (--i > 0);
1421 
1422         /* Extend the sign bit. */
1423         if ((ssize_t)sizeof(long long) > f->size)
1424                 x |= -(x & ((long long)1 << ((8 * f->size) - 1)));
1425 
1426         return ucv_int64_new(x);
1427 }
1428 
1429 static uc_value_t *
1430 be_unpack_ulonglong(uc_vm_t *vm, const char *p, const formatdef_t *f)
1431 {
1432         const unsigned char *bytes = (const unsigned char *)p;
1433         unsigned long long x = 0;
1434         ssize_t i = f->size;
1435 
1436         do {
1437                 x = (x<<8) | *bytes++;
1438         } while (--i > 0);
1439 
1440         return ucv_uint64_new(x);
1441 }
1442 
1443 static uc_value_t *
1444 be_unpack_halffloat(uc_vm_t *vm, const char *p, const formatdef_t *f)
1445 {
1446         return ucv_double_new(double_unpack16(p, false));
1447 }
1448 
1449 static uc_value_t *
1450 be_unpack_float(uc_vm_t *vm, const char *p, const formatdef_t *f)
1451 {
1452         return ucv_double_new(double_unpack32(p, false));
1453 }
1454 
1455 static uc_value_t *
1456 be_unpack_double(uc_vm_t *vm, const char *p, const formatdef_t *f)
1457 {
1458         return ucv_double_new(double_unpack64(p, false));
1459 }
1460 
1461 static uc_value_t *
1462 be_unpack_bool(uc_vm_t *vm, const char *p, const formatdef_t *f)
1463 {
1464         return ucv_boolean_new(*p != 0);
1465 }
1466 
1467 static bool
1468 be_pack_int(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1469 {
1470         unsigned char *q = (unsigned char *)p;
1471         ssize_t i = 0;
1472         long x = 0;
1473 
1474         if (!ucv_as_long(vm, v, &x))
1475                 return false;
1476 
1477         i = f->size;
1478 
1479         if (i != sizeof(long)) {
1480                 if ((i == 2) && (x < -32768 || x > 32767))
1481                         return range_exception(vm, f, false);
1482 #if UINT_MAX < ULONG_MAX
1483                 else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
1484                         return range_exception(vm, f, false);
1485 #endif
1486         }
1487 
1488         do {
1489                 q[--i] = (unsigned char)(x & 0xffL);
1490                 x >>= 8;
1491         } while (i > 0);
1492 
1493         return true;
1494 }
1495 
1496 static bool
1497 be_pack_uint(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1498 {
1499         unsigned char *q = (unsigned char *)p;
1500         unsigned long x = 0;
1501         ssize_t i = 0;
1502 
1503         if (!ucv_as_ulong(vm, v, &x))
1504                 return false;
1505 
1506         i = f->size;
1507 
1508         if (i != sizeof(long)) {
1509                 unsigned long maxint = 1;
1510                 maxint <<= (unsigned long)(i * 8);
1511                 if (x >= maxint)
1512                         return range_exception(vm, f, true);
1513         }
1514 
1515         do {
1516                 q[--i] = (unsigned char)(x & 0xffUL);
1517                 x >>= 8;
1518         } while (i > 0);
1519 
1520         return true;
1521 }
1522 
1523 static bool
1524 be_pack_longlong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1525 {
1526         unsigned char *q = (unsigned char *)p;
1527         long long x = 0;
1528         ssize_t i = 0;
1529 
1530         if (!ucv_as_longlong(vm, v, &x))
1531                 return false;
1532 
1533         i = f->size;
1534 
1535         do {
1536                 q[--i] = (unsigned char)(x & 0xffL);
1537                 x >>= 8;
1538         } while (i > 0);
1539 
1540         return true;
1541 }
1542 
1543 static bool
1544 be_pack_ulonglong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1545 {
1546         unsigned char *q = (unsigned char *)p;
1547         unsigned long long x = 0;
1548         ssize_t i = 0;
1549 
1550         if (!ucv_as_ulonglong(vm, v, &x))
1551                 return false;
1552 
1553         i = f->size;
1554 
1555         do {
1556                 q[--i] = (unsigned char)(x & 0xffUL);
1557                 x >>= 8;
1558         } while (i > 0);
1559 
1560         return true;
1561 }
1562 
1563 static bool
1564 be_pack_halffloat(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1565 {
1566         double x = 0.0;
1567 
1568         if (!ucv_as_double(vm, v, &x))
1569                 return false;
1570 
1571         return double_pack16(x, p, false);
1572 }
1573 
1574 static bool
1575 be_pack_float(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1576 {
1577         double x = 0.0;
1578 
1579         if (!ucv_as_double(vm, v, &x))
1580                 return false;
1581 
1582         if (!double_pack32(x, p, 0)) {
1583                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Argument out of range");
1584 
1585                 return false;
1586         }
1587 
1588         return true;
1589 }
1590 
1591 static bool
1592 be_pack_double(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1593 {
1594         double x = 0.0;
1595 
1596         if (!ucv_as_double(vm, v, &x))
1597                 return false;
1598 
1599         if (!double_pack64(x, p, 0)) {
1600                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Argument out of range");
1601 
1602                 return false;
1603         }
1604 
1605         return true;
1606 }
1607 
1608 static bool
1609 be_pack_bool(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1610 {
1611         *p = (char)ucv_is_truish(v);
1612 
1613         return true;
1614 }
1615 
1616 static formatdef_t big_endian_table[] = {
1617         { 'x', 1, 0, NULL, NULL },
1618         { 'b', 1, 0, native_unpack_byte, native_pack_byte },
1619         { 'B', 1, 0, native_unpack_ubyte, native_pack_ubyte },
1620         { 'c', 1, 0, native_unpack_char, native_pack_char },
1621         { '*', 1, 0, NULL, NULL },
1622         { 's', 1, 0, NULL, NULL },
1623         { 'p', 1, 0, NULL, NULL },
1624         { 'h', 2, 0, be_unpack_int, be_pack_int },
1625         { 'H', 2, 0, be_unpack_uint, be_pack_uint },
1626         { 'i', 4, 0, be_unpack_int, be_pack_int },
1627         { 'I', 4, 0, be_unpack_uint, be_pack_uint },
1628         { 'l', 4, 0, be_unpack_int, be_pack_int },
1629         { 'L', 4, 0, be_unpack_uint, be_pack_uint },
1630         { 'q', 8, 0, be_unpack_longlong, be_pack_longlong },
1631         { 'Q', 8, 0, be_unpack_ulonglong, be_pack_ulonglong },
1632         { '?', 1, 0, be_unpack_bool, be_pack_bool },
1633         { 'e', 2, 0, be_unpack_halffloat, be_pack_halffloat },
1634         { 'f', 4, 0, be_unpack_float, be_pack_float },
1635         { 'd', 8, 0, be_unpack_double, be_pack_double },
1636         { 0 }
1637 };
1638 
1639 
1640 /* Little-endian routines. *****************************************************/
1641 
1642 static uc_value_t *
1643 le_unpack_int(uc_vm_t *vm, const char *p, const formatdef_t *f)
1644 {
1645         const unsigned char *bytes = (const unsigned char *)p;
1646         ssize_t i = f->size;
1647         long x = 0;
1648 
1649         do {
1650                 x = (x<<8) | bytes[--i];
1651         } while (i > 0);
1652 
1653         /* Extend the sign bit. */
1654         if ((ssize_t)sizeof(long) > f->size)
1655                 x |= -(x & (1L << ((8 * f->size) - 1)));
1656 
1657         return ucv_int64_new(x);
1658 }
1659 
1660 static uc_value_t *
1661 le_unpack_uint(uc_vm_t *vm, const char *p, const formatdef_t *f)
1662 {
1663         const unsigned char *bytes = (const unsigned char *)p;
1664         ssize_t i = f->size;
1665         unsigned long x = 0;
1666 
1667         do {
1668                 x = (x<<8) | bytes[--i];
1669         } while (i > 0);
1670 
1671         return ucv_uint64_new(x);
1672 }
1673 
1674 static uc_value_t *
1675 le_unpack_longlong(uc_vm_t *vm, const char *p, const formatdef_t *f)
1676 {
1677         const unsigned char *bytes = (const unsigned char *)p;
1678         ssize_t i = f->size;
1679         long long x = 0;
1680 
1681         do {
1682                 x = (x<<8) | bytes[--i];
1683         } while (i > 0);
1684 
1685         /* Extend the sign bit. */
1686         if ((ssize_t)sizeof(long long) > f->size)
1687                 x |= -(x & ((long long)1 << ((8 * f->size) - 1)));
1688 
1689         return ucv_int64_new(x);
1690 }
1691 
1692 static uc_value_t *
1693 le_unpack_ulonglong(uc_vm_t *vm, const char *p, const formatdef_t *f)
1694 {
1695         const unsigned char *bytes = (const unsigned char *)p;
1696         unsigned long long x = 0;
1697         ssize_t i = f->size;
1698 
1699         do {
1700                 x = (x<<8) | bytes[--i];
1701         } while (i > 0);
1702 
1703         return ucv_uint64_new(x);
1704 }
1705 
1706 static uc_value_t *
1707 le_unpack_halffloat(uc_vm_t *vm, const char *p, const formatdef_t *f)
1708 {
1709         return ucv_double_new(double_unpack16(p, true));
1710 }
1711 
1712 static uc_value_t *
1713 le_unpack_float(uc_vm_t *vm, const char *p, const formatdef_t *f)
1714 {
1715         return ucv_double_new(double_unpack32(p, true));
1716 }
1717 
1718 static uc_value_t *
1719 le_unpack_double(uc_vm_t *vm, const char *p, const formatdef_t *f)
1720 {
1721         return ucv_double_new(double_unpack64(p, true));
1722 }
1723 
1724 static bool
1725 le_pack_int(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1726 {
1727         unsigned char *q = (unsigned char *)p;
1728         ssize_t i = 0;
1729         long x = 0;
1730 
1731         if (!ucv_as_long(vm, v, &x))
1732                 return false;
1733 
1734         i = f->size;
1735 
1736         if (i != sizeof(long)) {
1737                 if ((i == 2) && (x < -32768 || x > 32767))
1738                         return range_exception(vm, f, false);
1739 #if UINT_MAX < ULONG_MAX
1740                 else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
1741                         return range_exception(vm, f, false);
1742 #endif
1743         }
1744 
1745         do {
1746                 *q++ = (unsigned char)(x & 0xffL);
1747                 x >>= 8;
1748         } while (--i > 0);
1749 
1750         return true;
1751 }
1752 
1753 static bool
1754 le_pack_uint(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1755 {
1756         unsigned char *q = (unsigned char *)p;
1757         unsigned long x = 0;
1758         ssize_t i = 0;
1759 
1760         if (!ucv_as_ulong(vm, v, &x))
1761                 return false;
1762 
1763         i = f->size;
1764 
1765         if (i != sizeof(long)) {
1766                 unsigned long maxint = 1;
1767                 maxint <<= (unsigned long)(i * 8);
1768 
1769                 if (x >= maxint)
1770                         return range_exception(vm, f, true);
1771         }
1772 
1773         do {
1774                 *q++ = (unsigned char)(x & 0xffUL);
1775                 x >>= 8;
1776         } while (--i > 0);
1777 
1778         return true;
1779 }
1780 
1781 static bool
1782 le_pack_longlong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1783 {
1784         unsigned char *q = (unsigned char *)p;
1785         long long x = 0;
1786         ssize_t i = 0;
1787 
1788         if (!ucv_as_longlong(vm, v, &x))
1789                 return false;
1790 
1791         i = f->size;
1792 
1793         do {
1794                 *q++ = (unsigned char)(x & 0xffL);
1795                 x >>= 8;
1796         } while (--i > 0);
1797 
1798         return true;
1799 }
1800 
1801 static bool
1802 le_pack_ulonglong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1803 {
1804         unsigned char *q = (unsigned char *)p;
1805         unsigned long long x = 0;
1806         ssize_t i = 0;
1807 
1808         if (!ucv_as_ulonglong(vm, v, &x))
1809                 return false;
1810 
1811         i = f->size;
1812 
1813         do {
1814                 *q++ = (unsigned char)(x & 0xffUL);
1815                 x >>= 8;
1816         } while (--i > 0);
1817 
1818         return true;
1819 }
1820 
1821 static bool
1822 le_pack_halffloat(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1823 {
1824         double x = 0.0;
1825 
1826         if (!ucv_as_double(vm, v, &x))
1827                 return false;
1828 
1829         return double_pack16(x, p, true);
1830 }
1831 
1832 static bool
1833 le_pack_float(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1834 {
1835         double x = 0.0;
1836 
1837         if (!ucv_as_double(vm, v, &x))
1838                 return false;
1839 
1840         if (!double_pack32(x, p, 1)) {
1841                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Argument out of range");
1842 
1843                 return false;
1844         }
1845 
1846         return true;
1847 }
1848 
1849 static bool
1850 le_pack_double(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1851 {
1852         double x = 0.0;
1853 
1854         if (!ucv_as_double(vm, v, &x))
1855                 return false;
1856 
1857         if (!double_pack64(x, p, 1)) {
1858                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Argument out of range");
1859 
1860                 return false;
1861         }
1862 
1863         return true;
1864 }
1865 
1866 static formatdef_t little_endian_table[] = {
1867         { 'x', 1, 0, NULL, NULL },
1868         { 'b', 1, 0, native_unpack_byte, native_pack_byte },
1869         { 'B', 1, 0, native_unpack_ubyte, native_pack_ubyte },
1870         { 'c', 1, 0, native_unpack_char, native_pack_char },
1871         { '*', 1, 0, NULL, NULL },
1872         { 's', 1, 0, NULL, NULL },
1873         { 'p', 1, 0, NULL, NULL },
1874         { 'h', 2, 0, le_unpack_int, le_pack_int },
1875         { 'H', 2, 0, le_unpack_uint, le_pack_uint },
1876         { 'i', 4, 0, le_unpack_int, le_pack_int },
1877         { 'I', 4, 0, le_unpack_uint, le_pack_uint },
1878         { 'l', 4, 0, le_unpack_int, le_pack_int },
1879         { 'L', 4, 0, le_unpack_uint, le_pack_uint },
1880         { 'q', 8, 0, le_unpack_longlong, le_pack_longlong },
1881         { 'Q', 8, 0, le_unpack_ulonglong, le_pack_ulonglong },
1882         { '?', 1, 0, be_unpack_bool, be_pack_bool },
1883         { 'e', 2, 0, le_unpack_halffloat, le_pack_halffloat },
1884         { 'f', 4, 0, le_unpack_float, le_pack_float },
1885         { 'd', 8, 0, le_unpack_double, le_pack_double },
1886         { 0 }
1887 };
1888 
1889 
1890 static const formatdef_t *
1891 select_format_table(const char **pfmt)
1892 {
1893         const char *fmt = (*pfmt)++; /* May be backed out of later */
1894 
1895         switch (*fmt) {
1896         case '<':
1897                 return little_endian_table;
1898 
1899         case '>':
1900         case '!': /* Network byte order is big-endian */
1901                 return big_endian_table;
1902 
1903         case '=':  /* Host byte order -- different from native in alignment! */
1904 #if __BYTE_ORDER == __LITTLE_ENDIAN
1905                 return little_endian_table;
1906 #else
1907                 return big_endian_table;
1908 #endif
1909 
1910         default:
1911                 --*pfmt; /* Back out of pointer increment */
1912                 /* Fall through */
1913 
1914         case '@':
1915                 return native_endian_table;
1916         }
1917 }
1918 
1919 
1920 /* Get the table entry for a format code */
1921 
1922 static const formatdef_t *
1923 lookup_table_entry(uc_vm_t *vm, int c, const formatdef_t *table)
1924 {
1925         for (; table->format != '\0'; table++) {
1926                 if (table->format == c) {
1927                         return table;
1928                 }
1929         }
1930 
1931         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1932                 "Unrecognized character '%c' in struct format",
1933                 c);
1934 
1935         return NULL;
1936 }
1937 
1938 
1939 /* Align a size according to a format code.  Return -1 on overflow. */
1940 
1941 static ssize_t
1942 align_for_entry(ssize_t size, const formatdef_t *e)
1943 {
1944         ssize_t extra;
1945 
1946         if (e->alignment && size > 0) {
1947                 extra = (e->alignment - 1) - (size - 1) % (e->alignment);
1948 
1949                 if (extra > SSIZE_MAX - size)
1950                         return -1;
1951 
1952                 size += extra;
1953         }
1954 
1955         return size;
1956 }
1957 
1958 
1959 static void
1960 optimize_functions(void)
1961 {
1962         /* Check endian and swap in faster functions */
1963         const formatdef_t *native = native_endian_table;
1964         formatdef_t *other, *ptr;
1965 
1966 #if __BYTE_ORDER == __LITTLE_ENDIAN
1967         other = little_endian_table;
1968 #else
1969         other = big_endian_table;
1970 #endif
1971 
1972         /* Scan through the native table, find a matching
1973            entry in the endian table and swap in the
1974            native implementations whenever possible
1975            (64-bit platforms may not have "standard" sizes) */
1976         while (native->format != '\0' && other->format != '\0') {
1977                 ptr = other;
1978 
1979                 while (ptr->format != '\0') {
1980                         if (ptr->format == native->format) {
1981                                 /* Match faster when formats are
1982                                    listed in the same order */
1983                                 if (ptr == other)
1984                                         other++;
1985 
1986                                 /* Only use the trick if the
1987                                    size matches */
1988                                 if (ptr->size != native->size)
1989                                         break;
1990 
1991                                 /* Skip float and double, could be
1992                                    "unknown" float format */
1993                                 if (ptr->format == 'd' || ptr->format == 'f')
1994                                         break;
1995 
1996                                 /* Skip bool, semantics are different for standard size */
1997                                 if (ptr->format == '?')
1998                                         break;
1999 
2000                                 ptr->pack = native->pack;
2001                                 ptr->unpack = native->unpack;
2002                                 break;
2003                         }
2004 
2005                         ptr++;
2006                 }
2007 
2008                 native++;
2009         }
2010 }
2011 
2012 static formatstate_t *
2013 parse_format(uc_vm_t *vm, uc_value_t *fmtval)
2014 {
2015         ssize_t size, len, num, itemsize;
2016         const formatdef_t *e, *f;
2017         const char *fmt, *s;
2018         formatstate_t *state;
2019         formatcode_t *codes;
2020         size_t ncodes;
2021         char c;
2022 
2023         if (ucv_type(fmtval) != UC_STRING) {
2024                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2025                         "Format value not a string");
2026 
2027                 return NULL;
2028         }
2029 
2030         fmt = ucv_string_get(fmtval);
2031 
2032         if (strlen(fmt) != ucv_string_length(fmtval)) {
2033                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2034                         "Format string contains embedded null character");
2035 
2036                 return NULL;
2037         }
2038 
2039         f = select_format_table(&fmt);
2040 
2041         s = fmt;
2042         size = 0;
2043         len = 0;
2044         ncodes = 0;
2045 
2046         while ((c = *s++) != '\0') {
2047                 if (isspace(c))
2048                         continue;
2049 
2050                 if ('' <= c && c <= '9') {
2051                         num = c - '';
2052 
2053                         while ('' <= (c = *s++) && c <= '9') {
2054                                 /* overflow-safe version of
2055                                    if (num*10 + (c - '') > SSIZE_MAX) { ... } */
2056                                 if (num >= SSIZE_MAX / 10 && (
2057                                                 num > SSIZE_MAX / 10 ||
2058                                                 (c - '') > SSIZE_MAX % 10))
2059                                         goto overflow;
2060 
2061                                 num = num*10 + (c - '');
2062                         }
2063 
2064                         if (c == '\0') {
2065                                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2066                                         "Format string contains repeat count given without format specifier");
2067 
2068                                 return NULL;
2069                         }
2070                 }
2071                 else
2072                         num = 1;
2073 
2074                 e = lookup_table_entry(vm, c, f);
2075 
2076                 if (e == NULL)
2077                         return NULL;
2078 
2079                 switch (c) {
2080                 case '*': /* fall through */
2081                 case 's':
2082                 case 'p':
2083                         len++;
2084                         ncodes++;
2085                         break;
2086 
2087                 case 'x':
2088                         break;
2089 
2090                 default:
2091                         len += num;
2092 
2093                         if (num)
2094                                 ncodes++;
2095 
2096                         break;
2097                 }
2098 
2099                 itemsize = e->size;
2100                 size = align_for_entry(size, e);
2101 
2102                 if (size == -1)
2103                         goto overflow;
2104 
2105                 /* if (size + num * itemsize > SSIZE_MAX) { ... } */
2106                 if (num > (SSIZE_MAX - size) / itemsize)
2107                         goto overflow;
2108 
2109                 size += (c != '*') ? num * itemsize : 0;
2110         }
2111 
2112         /* check for overflow */
2113         if ((ncodes + 1) > ((size_t)SSIZE_MAX / sizeof(formatcode_t))) {
2114                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "Out of memory");
2115 
2116                 return NULL;
2117         }
2118 
2119         state = xalloc(sizeof(*state) + ncodes * sizeof(formatcode_t));
2120         state->len = len;
2121         state->size = size;
2122         state->ncodes = ncodes;
2123 
2124         codes = state->codes;
2125 
2126         s = fmt;
2127         size = 0;
2128 
2129         while ((c = *s++) != '\0') {
2130                 if (isspace(c))
2131                         continue;
2132 
2133                 if ('' <= c && c <= '9') {
2134                         num = c - '';
2135 
2136                         while ('' <= (c = *s++) && c <= '9')
2137                                 num = num*10 + (c - '');
2138 
2139                 }
2140                 else if (c == '*')
2141                         num = -1;
2142                 else
2143                         num = 1;
2144 
2145                 e = lookup_table_entry(vm, c, f);
2146 
2147                 if (e == NULL)
2148                         continue;
2149 
2150                 size = align_for_entry(size, e);
2151 
2152                 if (c == '*' || c == 's' || c == 'p') {
2153                         codes->offset = size;
2154                         codes->size = num;
2155                         codes->fmtdef = e;
2156                         codes->repeat = 1;
2157                         codes++;
2158                         size += (c != '*') ? num : 0;
2159                 }
2160                 else if (c == 'x') {
2161                         size += num;
2162                 }
2163                 else if (num) {
2164                         codes->offset = size;
2165                         codes->size = e->size;
2166                         codes->fmtdef = e;
2167                         codes->repeat = num;
2168                         codes++;
2169                         size += e->size * num;
2170                 }
2171         }
2172 
2173         return state;
2174 
2175 overflow:
2176         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2177                 "Total struct size too long");
2178 
2179         return NULL;
2180 }
2181 
2182 static uc_value_t *
2183 uc_pack_common(uc_vm_t *vm, size_t nargs, formatstate_t *state, size_t argoff)
2184 {
2185         size_t ncode, arg, off;
2186         formatcode_t *code;
2187         uc_string_t *buf;
2188         ssize_t size, n;
2189         const void *p;
2190 
2191         for (ncode = 0, code = &state->codes[0], arg = argoff, off = 0;
2192              ncode < state->ncodes;
2193              code = &state->codes[++ncode]) {
2194                 if (code->fmtdef->format == '*') {
2195                         uc_value_t *v = uc_fn_arg(arg++);
2196 
2197                         if (ucv_type(v) != UC_STRING)
2198                                 continue;
2199 
2200                         n = ucv_string_length(v);
2201 
2202                         if (code->size == -1 || code->size > n)
2203                                 off += n;
2204                         else
2205                                 off += code->size;
2206                 }
2207                 else {
2208                         arg += code->repeat;
2209                 }
2210         }
2211 
2212         buf = xalloc(sizeof(*buf) + state->size + off + 1);
2213         buf->header.type = UC_STRING;
2214         buf->header.refcount = 1;
2215         buf->length = state->size + off;
2216 
2217         for (ncode = 0, code = &state->codes[0], off = 0;
2218              ncode < state->ncodes;
2219              code = &state->codes[++ncode]) {
2220                 const formatdef_t *e = code->fmtdef;
2221                 char *res = buf->str + code->offset + off;
2222                 ssize_t j = code->repeat;
2223 
2224                 while (j--) {
2225                         uc_value_t *v = uc_fn_arg(argoff++);
2226 
2227                         size = code->size;
2228 
2229                         if (e->format == '*') {
2230                                 if (ucv_type(v) != UC_STRING) {
2231                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2232                                                 "Argument for '*' must be a string");
2233 
2234                                         goto err;
2235                                 }
2236 
2237                                 n = ucv_string_length(v);
2238                                 p = ucv_string_get(v);
2239 
2240                                 if (size == -1 || n < size)
2241                                         size = n;
2242                                 else if (n > size)
2243                                         n = size;
2244 
2245                                 off += size;
2246 
2247                                 if (n > 0)
2248                                         memcpy(res, p, n);
2249                         }
2250                         else if (e->format == 's') {
2251                                 if (ucv_type(v) != UC_STRING) {
2252                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2253                                                 "Argument for 's' must be a string");
2254 
2255                                         goto err;
2256                                 }
2257 
2258                                 n = ucv_string_length(v);
2259                                 p = ucv_string_get(v);
2260 
2261                                 if (n > size)
2262                                         n = size;
2263 
2264                                 if (n > 0)
2265                                         memcpy(res, p, n);
2266                         }
2267                         else if (e->format == 'p') {
2268                                 if (ucv_type(v) != UC_STRING) {
2269                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2270                                                 "Argument for 'p' must be a string");
2271 
2272                                         goto err;
2273                                 }
2274 
2275                                 n = ucv_string_length(v);
2276                                 p = ucv_string_get(v);
2277 
2278                                 if (n > (size - 1))
2279                                         n = size - 1;
2280 
2281                                 if (n > 0)
2282                                         memcpy(res + 1, p, n);
2283 
2284                                 if (n > 255)
2285                                         n = 255;
2286 
2287                                 *res = (unsigned char)n;
2288                         }
2289                         else {
2290                                 if (!e->pack(vm, res, v, e))
2291                                         goto err;
2292                         }
2293 
2294                         res += size;
2295                 }
2296         }
2297 
2298         return &buf->header;
2299 
2300 err:
2301         free(buf);
2302 
2303         return NULL;
2304 }
2305 
2306 static uc_value_t *
2307 uc_unpack_common(uc_vm_t *vm, size_t nargs, formatstate_t *state, size_t argoff)
2308 {
2309         uc_value_t *bufval = uc_fn_arg(argoff);
2310         uc_value_t *offset = uc_fn_arg(argoff + 1);
2311         const char *startfrom = NULL;
2312         ssize_t bufrem, size, n;
2313         uc_value_t *result;
2314         formatcode_t *code;
2315         size_t ncode, off;
2316 
2317         if (ucv_type(bufval) != UC_STRING) {
2318                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2319                         "Buffer value not a string");
2320 
2321                 return NULL;
2322         }
2323 
2324         startfrom = ucv_string_get(bufval);
2325         bufrem = ucv_string_length(bufval);
2326 
2327         if (offset) {
2328                 if (ucv_type(offset) != UC_INTEGER) {
2329                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2330                                 "Offset value not an integer");
2331 
2332                         return NULL;
2333                 }
2334 
2335                 n = (ssize_t)ucv_int64_get(offset);
2336 
2337                 if (n < 0)
2338                         n += bufrem;
2339 
2340                 if (n < 0 || n >= bufrem)
2341                         return NULL;
2342 
2343                 startfrom += n;
2344                 bufrem -= n;
2345         }
2346 
2347         result = ucv_array_new(vm);
2348 
2349         for (ncode = 0, code = &state->codes[0], off = 0;
2350              ncode < state->ncodes;
2351              code = &state->codes[++ncode]) {
2352                 const formatdef_t *e = code->fmtdef;
2353                 const char *res = startfrom + code->offset + off;
2354                 ssize_t j = code->repeat;
2355 
2356                 while (j--) {
2357                         uc_value_t *v = NULL;
2358 
2359                         size = code->size;
2360 
2361                         if (e->format == '*') {
2362                                 if (size == -1 || size > bufrem)
2363                                         size = bufrem;
2364 
2365                                 off += size;
2366                         }
2367                         else if (size > bufrem) {
2368                                 goto fail;
2369                         }
2370 
2371                         if (e->format == 's' || e->format == '*') {
2372                                 v = ucv_string_new_length(res, size);
2373                         }
2374                         else if (e->format == 'p') {
2375                                 n = *(unsigned char *)res;
2376 
2377                                 if (n >= size)
2378                                         n = (size > 0 ? size - 1 : 0);
2379 
2380                                 v = ucv_string_new_length(res + 1, n);
2381                         }
2382                         else {
2383                                 v = e->unpack(vm, res, e);
2384                         }
2385 
2386                         if (v == NULL)
2387                                 goto fail;
2388 
2389                         ucv_array_push(result, v);
2390 
2391                         res += size;
2392                         bufrem -= size;
2393                 }
2394         }
2395 
2396         return result;
2397 
2398 fail:
2399         ucv_put(result);
2400 
2401         return NULL;
2402 }
2403 
2404 
2405 static uc_value_t *
2406 uc_pack(uc_vm_t *vm, size_t nargs)
2407 {
2408         uc_value_t *fmtval = uc_fn_arg(0);
2409         uc_value_t *res = NULL;
2410         formatstate_t *state;
2411 
2412         state = parse_format(vm, fmtval);
2413 
2414         if (!state)
2415                 return NULL;
2416 
2417         res = uc_pack_common(vm, nargs, state, 1);
2418 
2419         free(state);
2420 
2421         return res;
2422 }
2423 
2424 static uc_value_t *
2425 uc_unpack(uc_vm_t *vm, size_t nargs)
2426 {
2427         uc_value_t *fmtval = uc_fn_arg(0);
2428         uc_value_t *res = NULL;
2429         formatstate_t *state;
2430 
2431         state = parse_format(vm, fmtval);
2432 
2433         if (!state)
2434                 return NULL;
2435 
2436         res = uc_unpack_common(vm, nargs, state, 1);
2437 
2438         free(state);
2439 
2440         return res;
2441 }
2442 
2443 
2444 static uc_value_t *
2445 uc_struct_new(uc_vm_t *vm, size_t nargs)
2446 {
2447         uc_value_t *fmtval = uc_fn_arg(0);
2448         formatstate_t *state;
2449 
2450         state = parse_format(vm, fmtval);
2451 
2452         if (!state)
2453                 return NULL;
2454 
2455         return uc_resource_new(struct_type, state);
2456 }
2457 
2458 static void
2459 uc_struct_gc(void *ud)
2460 {
2461         formatstate_t *state = ud;
2462 
2463         free(state);
2464 }
2465 
2466 static uc_value_t *
2467 uc_struct_pack(uc_vm_t *vm, size_t nargs)
2468 {
2469         formatstate_t **state = uc_fn_this("struct");
2470 
2471         if (!state || !*state)
2472                 return NULL;
2473 
2474         return uc_pack_common(vm, nargs, *state, 0);
2475 }
2476 
2477 static uc_value_t *
2478 uc_struct_unpack(uc_vm_t *vm, size_t nargs)
2479 {
2480         formatstate_t **state = uc_fn_this("struct");
2481 
2482         if (!state || !*state)
2483                 return NULL;
2484 
2485         return uc_unpack_common(vm, nargs, *state, 0);
2486 }
2487 
2488 
2489 static const uc_function_list_t struct_inst_fns[] = {
2490         { "pack",       uc_struct_pack },
2491         { "unpack",     uc_struct_unpack }
2492 };
2493 
2494 static const uc_function_list_t struct_fns[] = {
2495         { "pack",       uc_pack },
2496         { "unpack",     uc_unpack },
2497         { "new",        uc_struct_new }
2498 };
2499 
2500 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
2501 {
2502         optimize_functions();
2503 
2504         uc_function_list_register(scope, struct_fns);
2505 
2506         struct_type = uc_type_declare(vm, "struct", struct_inst_fns, uc_struct_gc);
2507 }
2508 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt