• 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 /**
 64  * # Handle Packed Binary Data
 65  *
 66  * The `struct` module provides routines for interpreting byte strings as packed
 67  * binary data.
 68  *
 69  * Functions can be individually imported and directly accessed using the
 70  * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#named_import named import}
 71  * syntax:
 72  *
 73  *   ```
 74  *   import { pack, unpack } from 'struct';
 75  *
 76  *   let buffer = pack('bhl', -13, 1234, 444555666);
 77  *   let values = unpack('bhl', buffer);
 78  *   ```
 79  *
 80  * Alternatively, the module namespace can be imported
 81  * using a wildcard import statement:
 82  *
 83  *   ```
 84  *   import * as struct from 'struct';
 85  *
 86  *   let buffer = struct.pack('bhl', -13, 1234, 444555666);
 87  *   let values = struct.unpack('bhl', buffer);
 88  *   ```
 89  *
 90  * Additionally, the struct module namespace may also be imported by invoking
 91  * the `ucode` interpreter with the `-lstruct` switch.
 92  *
 93  * ## Format Strings
 94  *
 95  * Format strings describe the data layout when packing and unpacking data.
 96  * They are built up from format-characters, which specify the type of data
 97  * being packed/unpacked. In addition, special characters control the byte
 98  * order, size and alignment.
 99  *
100  * Each format string consists of an optional prefix character which describes
101  * the overall properties of the data and one or more format characters which
102  * describe the actual data values and padding.
103  *
104  * ### Byte Order, Size, and Alignment
105  *
106  * By default, C types are represented in the machine's native format and byte
107  * order, and properly aligned by skipping pad bytes if necessary (according to
108  * the rules used by the C compiler).
109  *
110  * This behavior is chosen so that the bytes of a packed struct correspond
111  * exactly to the memory layout of the corresponding C struct.
112  *
113  * Whether to use native byte ordering and padding or standard formats depends
114  * on the application.
115  *
116  * Alternatively, the first character of the format string can be used to indicate
117  * the byte order, size and alignment of the packed data, according to the
118  * following table:
119  *
120  * | Character | Byte order             | Size     | Alignment |
121  * |-----------|------------------------|----------|-----------|
122  * | `@`       | native                 | native   | native    |
123  * | `=`       | native                 | standard | none      |
124  * | `<`       | little-endian          | standard | none      |
125  * | `>`       | big-endian             | standard | none      |
126  * | `!`       | network (= big-endian) | standard | none      |
127  *
128  * If the first character is not one of these, `'@'` is assumed.
129  *
130  * Native byte order is big-endian or little-endian, depending on the
131  * host system. For example, Intel x86, AMD64 (x86-64), and Apple M1 are
132  * little-endian; IBM z and many legacy architectures are big-endian.
133  *
134  * Native size and alignment are determined using the C compiler's
135  * `sizeof` expression. This is always combined with native byte order.
136  *
137  * Standard size depends only on the format character; see the table in
138  * the `format-characters` section.
139  *
140  * Note the difference between `'@'` and `'='`: both use native byte order,
141  * but the size and alignment of the latter is standardized.
142  *
143  * The form `'!'` represents the network byte order which is always big-endian
144  * as defined in `IETF RFC 1700`.
145  *
146  * There is no way to indicate non-native byte order (force byte-swapping); use
147  * the appropriate choice of `'<'` or `'>'`.
148  *
149  * Notes:
150  *
151  * (1) Padding is only automatically added between successive structure members.
152  *     No padding is added at the beginning or the end of the encoded struct.
153  *
154  * (2) No padding is added when using non-native size and alignment, e.g.
155  *     with '<', '>', '=', and '!'.
156  *
157  * (3) To align the end of a structure to the alignment requirement of a
158  *     particular type, end the format with the code for that type with a repeat
159  *     count of zero.
160  *
161  *
162  * ### Format Characters
163  *
164  * Format characters have the following meaning; the conversion between C and
165  * ucode values should be obvious given their types.  The 'Standard size' column
166  * refers to the size of the packed value in bytes when using standard size;
167  * that is, when the format string starts with one of `'<'`, `'>'`, `'!'` or
168  * `'='`.  When using native size, the size of the packed value is platform
169  * dependent.
170  *
171  * | Format | C Type               | Ucode type | Standard size  | Notes    |
172  * |--------|----------------------|------------|----------------|----------|
173  * | `x`    | *pad byte*           | *no value* |                | (7)      |
174  * | `c`    | `char`               | string     | 1              |          |
175  * | `b`    | `signed char`        | int        | 1              | (1), (2) |
176  * | `B`    | `unsigned char`      | int        | 1              | (2)      |
177  * | `?`    | `_Bool`              | bool       | 1              | (1)      |
178  * | `h`    | `short`              | int        | 2              | (2)      |
179  * | `H`    | `unsigned short`     | int        | 2              | (2)      |
180  * | `i`    | `int`                | int        | 4              | (2)      |
181  * | `I`    | `unsigned int`       | int        | 4              | (2)      |
182  * | `l`    | `long`               | int        | 4              | (2)      |
183  * | `L`    | `unsigned long`      | int        | 4              | (2)      |
184  * | `q`    | `long long`          | int        | 8              | (2)      |
185  * | `Q`    | `unsigned long long` | int        | 8              | (2)      |
186  * | `n`    | `ssize_t`            | int        |                | (3)      |
187  * | `N`    | `size_t`             | int        |                | (3)      |
188  * | `e`    | (6)                  | double     | 2              | (4)      |
189  * | `f`    | `float`              | double     | 4              | (4)      |
190  * | `d`    | `double`             | double     | 8              | (4)      |
191  * | `s`    | `char[]`             | double     |                | (9)      |
192  * | `p`    | `char[]`             | double     |                | (8)      |
193  * | `P`    | `void *`             | int        |                | (5)      |
194  * | `*`    | `char[]`             | string     |                | (10)     |
195  * | `X`    | `char[]`             | string     |                | (11)     |
196  * | `Z`    | `char[]`             | string     |                | (12)     |
197  *
198  * Notes:
199  *
200  * - (1) The `'?'` conversion code corresponds to the `_Bool` type defined by
201  *    C99. If this type is not available, it is simulated using a `char`. In
202  *    standard mode, it is always represented by one byte.
203  *
204  * - (2) When attempting to pack a non-integer using any of the integer
205  *    conversion codes, this module attempts to convert the given value into an
206  *    integer. If the value is not convertible, a type error exception is thrown.
207  *
208  * - (3) The `'n'` and `'N'` conversion codes are only available for the native
209  *    size (selected as the default or with the `'@'` byte order character).
210  *    For the standard size, you can use whichever of the other integer formats
211  *    fits your application.
212  *
213  * - (4) For the `'f'`, `'d'` and `'e'` conversion codes, the packed
214  *    representation uses the IEEE 754 binary32, binary64 or binary16 format
215  *    (for `'f'`, `'d'` or `'e'` respectively), regardless of the floating-point
216  *    format used by the platform.
217  *
218  * - (5) The `'P'` format character is only available for the native byte
219  *    ordering (selected as the default or with the `'@'` byte order character).
220  *    The byte order character `'='` chooses to use little- or big-endian
221  *    ordering based on the host system. The struct module does not interpret
222  *    this as native ordering, so the `'P'` format is not available.
223  *
224  * - (6) The IEEE 754 binary16 "half precision" type was introduced in the 2008
225  *    revision of the `IEEE 754` standard. It has a sign bit, a 5-bit exponent
226  *    and 11-bit precision (with 10 bits explicitly stored), and can represent
227  *    numbers between approximately `6.1e-05` and `6.5e+04` at full precision.
228  *    This type is not widely supported by C compilers: on a typical machine, an
229  *    unsigned short can be used for storage, but not for math operations. See
230  *    the Wikipedia page on the `half-precision floating-point format` for more
231  *    information.
232  *
233  * - (7) When packing, `'x'` inserts one NUL byte.
234  *
235  * - (8) The `'p'` format character encodes a "Pascal string", meaning a short
236  *    variable-length string stored in a *fixed number of bytes*, given by the
237  *    count. The first byte stored is the length of the string, or 255,
238  *    whichever is smaller.  The bytes of the string follow.  If the string
239  *    passed in to `pack()` is too long (longer than the count minus 1), only
240  *    the leading `count-1` bytes of the string are stored.  If the string is
241  *    shorter than `count-1`, it is padded with null bytes so that exactly count
242  *    bytes in all are used.  Note that for `unpack()`, the `'p'` format
243  *    character consumes `count` bytes, but that the string returned can never
244  *    contain more than 255 bytes.
245  *
246  * - (9) For the `'s'` format character, the count is interpreted as the length
247  *    of the bytes, not a repeat count like for the other format characters; for
248  *    example, `'10s'` means a single 10-byte string mapping to or from a single
249  *    ucode byte string, while `'10c'` means 10 separate one byte character
250  *    elements (e.g., `cccccccccc`) mapping to or from ten different ucode byte
251  *    strings. If a count is not given, it defaults to 1. For packing, the
252  *    string is truncated or padded with null bytes as appropriate to make it
253  *    fit. For unpacking, the resulting bytes object always has exactly the
254  *    specified number of bytes.  As a special case, `'0s'` means a single,
255  *    empty string (while `'0c'` means 0 characters).
256  *
257  * - (10) The `*` format character serves as wildcard. For `pack()` it will
258  *    append the corresponding byte argument string as-is, not applying any
259  *    padding or zero filling. When a repeat count is given, that many bytes of
260  *    the input byte string argument will be appended at most on `pack()`,
261  *    effectively truncating longer input strings. For `unpack()`, the wildcard
262  *    format will yield a byte string containing the entire remaining input data
263  *    bytes, or - when a repeat count is given - that many bytes of input data
264  *    at most.
265  *
266  * - (11) The `X` format character handles hexadecimal encoding of binary data.
267  *    On `pack()`, the argument is a hexadecimal string; with no repeat count the
268  *    entire string is decoded into binary, while a repeat count limits the
269  *    number of output bytes (truncating longer input). On `unpack()`, the input
270  *    binary data is converted into a hexadecimal string, using all remaining
271  *    bytes by default, or at most the specified number of bytes when a repeat
272  *    count is given. Decoding accepts both upper- and lowercase hex digits, but
273  *    encoding always produces lowercase output. The encoded text length is
274  *    exactly twice the number of processed binary bytes.
275  *
276  * - (12) The `Z` format character behaves like `X`, but uses base64 encoding
277  *    instead of hexadecimal. On `pack()`, the argument is a base64 string; by
278  *    default the entire string is decoded into binary, or at most the specified
279  *    number of bytes when a repeat count is given. On `unpack()`, the input
280  *    binary data is converted into a base64 string, consuming all remaining
281  *    bytes by default, or at most the repeat count if given. The encoded base64
282  *    string is approximately 1.4 times the size of the processed binary data.
283  *
284  * A format character may be preceded by an integral repeat count.  For example,
285  * the format string `'4h'` means exactly the same as `'hhhh'`.
286  *
287  * Whitespace characters between formats are ignored; a count and its format
288  * must not contain whitespace though.
289  *
290  * When packing a value `x` using one of the integer formats (`'b'`,
291  * `'B'`, `'h'`, `'H'`, `'i'`, `'I'`, `'l'`, `'L'`,
292  * `'q'`, `'Q'`), if `x` is outside the valid range for that format, a type
293  * error exception is raised.
294  *
295  * For the `'?'` format character, the return value is either `true` or `false`.
296  * When packing, the truish result value of the argument is used. Either 0 or 1
297  * in the native or standard bool representation will be packed, and any
298  * non-zero value will be `true` when unpacking.
299  *
300  * ## Examples
301  *
302  * Note:
303  *    Native byte order examples (designated by the `'@'` format prefix or
304  *    lack of any prefix character) may not match what the reader's
305  *    machine produces as
306  *    that depends on the platform and compiler.
307  *
308  * Pack and unpack integers of three different sizes, using big endian
309  * ordering:
310  *
311  * ```
312  * import { pack, unpack } from 'struct';
313  *
314  * pack(">bhl", 1, 2, 3);  // "\x01\x00\x02\x00\x00\x00\x03"
315  * unpack(">bhl", "\x01\x00\x02\x00\x00\x00\x03");  // [ 1, 2, 3 ]
316  * ```
317  *
318  * Attempt to pack an integer which is too large for the defined field:
319  *
320  * ```bash
321  * $ ucode -lstruct -p 'struct.pack(">h", 99999)'
322  * Type error: Format 'h' requires numeric argument between -32768 and 32767
323  * In [-p argument], line 1, byte 24:
324  *
325  *  `struct.pack(">h", 99999)`
326  *   Near here -------------^
327  * ```
328  *
329  * Demonstrate the difference between `'s'` and `'c'` format characters:
330  *
331  * ```
332  * import { pack } from 'struct';
333  *
334  * pack("@ccc", "1", "2", "3");  // "123"
335  * pack("@3s", "123");           // "123"
336  * ```
337  *
338  * The ordering of format characters may have an impact on size in native
339  * mode since padding is implicit. In standard mode, the user is
340  * responsible for inserting any desired padding.
341  *
342  * Note in the first `pack()` call below that three NUL bytes were added after
343  * the packed `'#'` to align the following integer on a four-byte boundary.
344  * In this example, the output was produced on a little endian machine:
345  *
346  * ```
347  * import { pack } from 'struct';
348  *
349  * pack("@ci", "#", 0x12131415);  // "#\x00\x00\x00\x15\x14\x13\x12"
350  * pack("@ic", 0x12131415, "#");  // "\x15\x14\x13\x12#"
351  * ```
352  *
353  * The following format `'ih0i'` results in two pad bytes being added at the
354  * end, assuming the platform's ints are aligned on 4-byte boundaries:
355  *
356  * ```
357  * import { pack } from 'struct';
358  *
359  * pack("ih0i", 0x01010101, 0x0202);  // "\x01\x01\x01\x01\x02\x02\x00\x00"
360  * ```
361  *
362  * Use the wildcard format to extract the remainder of the input data:
363  *
364  * ```
365  * import { unpack } from 'struct';
366  *
367  * unpack("ccc*", "foobarbaz");   // [ "f", "o", "o", "barbaz" ]
368  * unpack("ccc3*", "foobarbaz");  // [ "f", "o", "o", "bar" ]
369  * ```
370  *
371  * Use the wildcard format to pack binary stings as-is into the result data:
372  *
373  * ```
374  * import { pack } from 'struct';
375  *
376  * pack("h*h", 0x0101, "\x02\x00\x03", 0x0404);  // "\x01\x01\x02\x00\x03\x04\x04"
377  * pack("c3*c", "a", "foobar", "c");  // "afooc"
378  * ```
379  *
380  * @module struct
381  */
382 
383 #include <ctype.h>
384 #include <errno.h>
385 #include <limits.h>
386 #include <math.h>
387 #include <stdlib.h>
388 #include <float.h>
389 #include <assert.h>
390 
391 #include "ucode/module.h"
392 #include "ucode/vallist.h"
393 
394 typedef struct formatdef {
395         char format;
396         ssize_t size;
397         ssize_t alignment;
398         uc_value_t* (*unpack)(uc_vm_t *, const char *, const struct formatdef *);
399         bool (*pack)(uc_vm_t *, char *, uc_value_t *, const struct formatdef *);
400 } formatdef_t;
401 
402 typedef struct {
403         const formatdef_t *fmtdef;
404         ssize_t offset;
405         ssize_t size;
406         ssize_t repeat;
407 } formatcode_t;
408 
409 typedef struct {
410         size_t len;
411         size_t size;
412         size_t ncodes;
413         formatcode_t codes[];
414 } formatstate_t;
415 
416 typedef struct {
417         uc_resource_t resource;
418         size_t length;
419         size_t capacity;
420         size_t position;
421 } formatbuffer_t;
422 
423 
424 /* Define various structs to figure out the alignments of types */
425 
426 typedef struct { char c; short x; } st_short;
427 typedef struct { char c; int x; } st_int;
428 typedef struct { char c; long x; } st_long;
429 typedef struct { char c; float x; } st_float;
430 typedef struct { char c; double x; } st_double;
431 typedef struct { char c; void *x; } st_void_p;
432 typedef struct { char c; size_t x; } st_size_t;
433 typedef struct { char c; bool x; } st_bool;
434 typedef struct { char c; long long x; } s_long_long;
435 
436 #define SHORT_ALIGN (sizeof(st_short) - sizeof(short))
437 #define INT_ALIGN (sizeof(st_int) - sizeof(int))
438 #define LONG_ALIGN (sizeof(st_long) - sizeof(long))
439 #define FLOAT_ALIGN (sizeof(st_float) - sizeof(float))
440 #define DOUBLE_ALIGN (sizeof(st_double) - sizeof(double))
441 #define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))
442 #define SIZE_T_ALIGN (sizeof(st_size_t) - sizeof(size_t))
443 #define BOOL_ALIGN (sizeof(st_bool) - sizeof(bool))
444 #define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(long long))
445 
446 #ifdef __powerc
447 #pragma options align=reset
448 #endif
449 
450 
451 static bool
452 ucv_as_long(uc_vm_t *vm, uc_value_t *v, long *p)
453 {
454         char *s, *e;
455         int64_t i;
456         double d;
457         long x;
458 
459         errno = 0;
460 
461         switch (ucv_type(v)) {
462         case UC_INTEGER:
463                 i = ucv_int64_get(v);
464 
465                 if (i < LONG_MIN || i > LONG_MAX)
466                         errno = ERANGE;
467 
468                 x = (long)i;
469                 break;
470 
471         case UC_DOUBLE:
472                 d = ucv_double_get(v);
473                 x = (long)d;
474 
475                 if (isnan(d) || d < (double)LONG_MIN || d > (double)LONG_MAX || d - x != 0)
476                         errno = ERANGE;
477 
478                 break;
479 
480         case UC_BOOLEAN:
481                 x = (long)ucv_boolean_get(v);
482                 break;
483 
484         case UC_NULL:
485                 x = 0;
486                 break;
487 
488         case UC_STRING:
489                 s = ucv_string_get(v);
490                 x = strtol(s, &e, 0);
491 
492                 if (e == s || *e != '\0')
493                         errno = EINVAL;
494 
495                 break;
496 
497         default:
498                 errno = EINVAL;
499                 x = 0;
500                 break;
501         }
502 
503         if (errno != 0) {
504                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
505                         (errno == ERANGE)
506                                 ? "Argument out of range"
507                                 : "Argument not convertible to number");
508 
509                 return false;
510         }
511 
512         *p = x;
513 
514         return true;
515 }
516 
517 static bool
518 ucv_as_ulong(uc_vm_t *vm, uc_value_t *v, unsigned long *p)
519 {
520         unsigned long x;
521         char *s, *e;
522         uint64_t i;
523         double d;
524 
525         errno = 0;
526 
527         switch (ucv_type(v)) {
528         case UC_INTEGER:
529                 i = ucv_uint64_get(v);
530 
531                 if (i > ULONG_MAX)
532                         errno = ERANGE;
533 
534                 x = (unsigned long)i;
535                 break;
536 
537         case UC_DOUBLE:
538                 d = ucv_double_get(v);
539                 x = (unsigned long)d;
540 
541                 if (isnan(d) || d < 0 || d > (double)ULONG_MAX || d - x != 0)
542                         errno = ERANGE;
543 
544                 break;
545 
546         case UC_BOOLEAN:
547                 x = (unsigned long)ucv_boolean_get(v);
548                 break;
549 
550         case UC_NULL:
551                 x = 0;
552                 break;
553 
554         case UC_STRING:
555                 s = ucv_string_get(v);
556                 x = strtoul(s, &e, 0);
557 
558                 if (e == s || *e != '\0')
559                         errno = EINVAL;
560 
561                 break;
562 
563         default:
564                 errno = EINVAL;
565                 x = 0;
566                 break;
567         }
568 
569         if (errno != 0) {
570                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
571                         (errno == ERANGE)
572                                 ? "Argument out of range"
573                                 : "Argument not convertible to number");
574 
575                 return false;
576         }
577 
578         *p = x;
579 
580         return true;
581 }
582 
583 static bool
584 ucv_as_longlong(uc_vm_t *vm, uc_value_t *v, long long *p)
585 {
586         char *s, *e;
587         long long x;
588         int64_t i;
589         double d;
590 
591         errno = 0;
592 
593         switch (ucv_type(v)) {
594         case UC_INTEGER:
595                 i = ucv_int64_get(v);
596 
597                 if (i < LLONG_MIN || i > LLONG_MAX)
598                         errno = ERANGE;
599 
600                 x = (long long)i;
601                 break;
602 
603         case UC_DOUBLE:
604                 d = ucv_double_get(v);
605                 x = (long long)d;
606 
607                 if (isnan(d) || d < (double)LLONG_MIN || d > (double)LLONG_MAX || d - x != 0)
608                         errno = ERANGE;
609 
610                 break;
611 
612         case UC_BOOLEAN:
613                 x = (long long)ucv_boolean_get(v);
614                 break;
615 
616         case UC_NULL:
617                 x = 0;
618                 break;
619 
620         case UC_STRING:
621                 s = ucv_string_get(v);
622                 x = strtoll(s, &e, 0);
623 
624                 if (e == s || *e != '\0')
625                         errno = EINVAL;
626 
627                 break;
628 
629         default:
630                 errno = EINVAL;
631                 x = 0;
632                 break;
633         }
634 
635         if (errno != 0) {
636                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
637                         (errno == ERANGE)
638                                 ? "Argument out of range"
639                                 : "Argument not convertible to number");
640 
641                 return false;
642         }
643 
644         *p = x;
645 
646         return true;
647 }
648 
649 static bool
650 ucv_as_ulonglong(uc_vm_t *vm, uc_value_t *v, unsigned long long *p)
651 {
652         unsigned long long x;
653         char *s, *e;
654         uint64_t i;
655         double d;
656 
657         errno = 0;
658 
659         switch (ucv_type(v)) {
660         case UC_INTEGER:
661                 i = ucv_uint64_get(v);
662 
663                 if (i > ULLONG_MAX)
664                         errno = ERANGE;
665 
666                 x = (unsigned long long)i;
667                 break;
668 
669         case UC_DOUBLE:
670                 d = ucv_double_get(v);
671                 x = (unsigned long long)d;
672 
673                 if (isnan(d) || d < 0 || d > (double)ULLONG_MAX || d - x != 0)
674                         errno = ERANGE;
675 
676                 break;
677 
678         case UC_BOOLEAN:
679                 x = (unsigned long long)ucv_boolean_get(v);
680                 break;
681 
682         case UC_NULL:
683                 x = 0;
684                 break;
685 
686         case UC_STRING:
687                 s = ucv_string_get(v);
688                 x = strtoull(s, &e, 0);
689 
690                 if (e == s || *e != '\0')
691                         errno = EINVAL;
692 
693                 break;
694 
695         default:
696                 errno = EINVAL;
697                 x = 0;
698                 break;
699         }
700 
701         if (errno != 0) {
702                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
703                         (errno == ERANGE)
704                                 ? "Argument out of range"
705                                 : "Argument not convertible to number");
706 
707                 return false;
708         }
709 
710         *p = x;
711 
712         return true;
713 }
714 
715 static bool
716 ucv_as_ssize_t(uc_vm_t *vm, uc_value_t *v, ssize_t *p)
717 {
718         char *s, *e;
719         int64_t i;
720         ssize_t x;
721         double d;
722 
723         errno = 0;
724 
725         switch (ucv_type(v)) {
726         case UC_INTEGER:
727                 i = ucv_int64_get(v);
728 
729                 if (i < -1 || i > SSIZE_MAX)
730                         errno = ERANGE;
731 
732                 x = (ssize_t)i;
733                 break;
734 
735         case UC_DOUBLE:
736                 d = ucv_double_get(v);
737                 x = (ssize_t)d;
738 
739                 if (isnan(d) || d < -1 || d > (double)SSIZE_MAX || d - x != 0)
740                         errno = ERANGE;
741 
742                 break;
743 
744         case UC_BOOLEAN:
745                 x = (ssize_t)ucv_boolean_get(v);
746                 break;
747 
748         case UC_NULL:
749                 x = 0;
750                 break;
751 
752         case UC_STRING:
753                 s = ucv_string_get(v);
754                 i = strtoll(s, &e, 0);
755 
756                 if (e == s || *e != '\0')
757                         errno = EINVAL;
758                 else if (i < -1 || i > SSIZE_MAX)
759                         errno = ERANGE;
760 
761                 x = (ssize_t)i;
762                 break;
763 
764         default:
765                 errno = EINVAL;
766                 x = 0;
767                 break;
768         }
769 
770         if (errno != 0) {
771                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
772                         (errno == ERANGE)
773                                 ? "Argument out of range"
774                                 : "Argument not convertible to number");
775 
776                 return false;
777         }
778 
779         *p = x;
780 
781         return true;
782 }
783 
784 /* Same, but handling size_t */
785 
786 static bool
787 ucv_as_size_t(uc_vm_t *vm, uc_value_t *v, size_t *p)
788 {
789         char *s, *e;
790         uint64_t i;
791         double d;
792         size_t x;
793 
794         errno = 0;
795 
796         switch (ucv_type(v)) {
797         case UC_INTEGER:
798                 i = ucv_uint64_get(v);
799 
800                 if (i > SIZE_MAX)
801                         errno = ERANGE;
802 
803                 x = (size_t)i;
804                 break;
805 
806         case UC_DOUBLE:
807                 d = ucv_double_get(v);
808                 x = (size_t)d;
809 
810                 if (isnan(d) || d < 0 || d > (double)SIZE_MAX || d - x != 0)
811                         errno = ERANGE;
812 
813                 break;
814 
815         case UC_BOOLEAN:
816                 x = (size_t)ucv_boolean_get(v);
817                 break;
818 
819         case UC_NULL:
820                 x = 0;
821                 break;
822 
823         case UC_STRING:
824                 s = ucv_string_get(v);
825                 i = strtoull(s, &e, 0);
826 
827                 if (e == s || *e != '\0')
828                         errno = EINVAL;
829                 else if (i > SIZE_MAX)
830                         errno = ERANGE;
831 
832                 x = (size_t)i;
833                 break;
834 
835         default:
836                 errno = EINVAL;
837                 x = 0;
838                 break;
839         }
840 
841         if (errno != 0) {
842                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
843                         (errno == ERANGE)
844                                 ? "Argument out of range"
845                                 : "Argument not convertible to number");
846 
847                 return false;
848         }
849 
850         *p = x;
851 
852         return true;
853 }
854 
855 static bool
856 ucv_as_double(uc_vm_t *vm, uc_value_t *v, double *p)
857 {
858         char *s, *e;
859         int64_t i;
860         double x;
861 
862         errno = 0;
863 
864         switch (ucv_type(v)) {
865         case UC_INTEGER:
866                 i = ucv_int64_get(v);
867 
868                 if (errno == 0) {
869                         if (i < -DBL_MAX || i > DBL_MAX)
870                                 errno = ERANGE;
871                 }
872 
873                 x = (double)i;
874                 break;
875 
876         case UC_DOUBLE:
877                 x = ucv_double_get(v);
878                 break;
879 
880         case UC_BOOLEAN:
881                 x = (double)ucv_boolean_get(v);
882                 break;
883 
884         case UC_NULL:
885                 x = 0.0;
886                 break;
887 
888         case UC_STRING:
889                 s = ucv_string_get(v);
890                 x = strtod(s, &e);
891 
892                 if (e == s || *e != '\0')
893                         errno = EINVAL;
894 
895                 break;
896 
897         default:
898                 errno = EINVAL;
899                 x = 0.0;
900                 break;
901         }
902 
903         if (errno != 0) {
904                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
905                         (errno == ERANGE)
906                                 ? "Argument out of range"
907                                 : "Argument not convertible to number");
908 
909                 return false;
910         }
911 
912         *p = x;
913 
914         return true;
915 }
916 
917 
918 /* Floating point helpers */
919 
920 static bool
921 double_pack16(double d, char *buf, bool little_endian)
922 {
923         int32_t exponent = 0;
924         uint16_t bits = 0;
925         bool sign = false;
926         double fraction;
927         uint8_t *p;
928 
929         if (d == 0.0) {
930                 sign = (copysign(1.0, d) == -1.0);
931         }
932         else if (isnan(d)) {
933                 sign = (copysign(1.0, d) == -1.0);
934                 exponent = 0x1f;
935                 bits = 512;
936         }
937         else if (!isfinite(d)) {
938                 sign = (d < 0.0);
939                 exponent = 0x1f;
940         }
941         else {
942                 if (d < 0.0) {
943                         sign = true;
944                         d = -d;
945                 }
946 
947                 fraction = frexp(d, &exponent);
948 
949                 assert(fraction >= 0.5 && fraction < 1.0);
950 
951                 fraction *= 2.0;
952                 exponent--;
953 
954                 if (exponent >= 16) {
955                         errno = ERANGE;
956 
957                         return false;
958                 }
959                 else if (exponent < -25) {
960                         fraction = 0.0;
961                         exponent = 0;
962                 }
963                 else if (exponent < -14) {
964                         fraction = ldexp(fraction, 14 + exponent);
965                         exponent = 0;
966                 }
967                 else {
968                         fraction -= 1.0;
969                         exponent += 15;
970                 }
971 
972                 fraction *= 1024.0;
973                 bits = (uint16_t)fraction;
974 
975                 assert(bits < 1024);
976                 assert(exponent < 31);
977 
978                 if ((fraction - bits > 0.5) || ((fraction - bits == 0.5) && (bits % 2))) {
979                         if (++bits == 1024) {
980                                 bits = 0;
981 
982                                 if (++exponent == 31) {
983                                         errno = ERANGE;
984 
985                                         return false;
986                                 }
987                         }
988                 }
989         }
990 
991         bits |= (exponent << 10) | (sign << 15);
992 
993         p = (uint8_t *)buf + little_endian;
994         *p = (bits >> 8) & 0xff;
995 
996         p += (little_endian ? -1 : 1);
997         *p = bits & 0xff;
998 
999         return true;
1000 }
1001 
1002 static bool
1003 double_pack32(double d, char *buf, bool little_endian)
1004 {
1005         int8_t step = little_endian ? -1 : 1;
1006         int32_t exponent = 0;
1007         uint32_t bits = 0;
1008         bool sign = false;
1009         double fraction;
1010         uint8_t *p;
1011 
1012         if (d == 0.0) {
1013                 sign = (copysign(1.0, d) == -1.0);
1014         }
1015         else if (isnan(d)) {
1016                 sign = (copysign(1.0, d) == -1.0);
1017                 exponent = 0xff;
1018                 bits = 0x7fffff;
1019         }
1020         else if (!isfinite(d)) {
1021                 sign = (d < 0.0);
1022                 exponent = 0xff;
1023         }
1024         else {
1025                 if (d < 0.0) {
1026                         sign = true;
1027                         d = -d;
1028                 }
1029 
1030                 fraction = frexp(d, &exponent);
1031 
1032                 if (fraction == 0.0) {
1033                         exponent = 0;
1034                 }
1035                 else {
1036                         assert(fraction >= 0.5 && fraction < 1.0);
1037 
1038                         fraction *= 2.0;
1039                         exponent--;
1040                 }
1041 
1042                 if (exponent >= 128) {
1043                         errno = ERANGE;
1044 
1045                         return false;
1046                 }
1047                 else if (exponent < -126) {
1048                         fraction = ldexp(fraction, 126 + exponent);
1049                         exponent = 0;
1050                 }
1051                 else if (exponent != 0 || fraction != 0.0) {
1052                         fraction -= 1.0;
1053                         exponent += 127;
1054                 }
1055 
1056                 fraction *= 8388608.0;
1057                 bits = (uint32_t)(fraction + 0.5);
1058 
1059                 assert(bits <= 8388608);
1060 
1061                 if (bits >> 23) {
1062                         bits = 0;
1063 
1064                         if (++exponent >= 255) {
1065                                 errno = ERANGE;
1066 
1067                                 return false;
1068                         }
1069                 }
1070         }
1071 
1072         p = (uint8_t *)buf + (little_endian ? 3 : 0);
1073         *p = (sign << 7) | (exponent >> 1);
1074 
1075         p += step;
1076         *p = ((exponent & 1) << 7) | (bits >> 16);
1077 
1078         p += step;
1079         *p = (bits >> 8) & 0xff;
1080 
1081         p += step;
1082         *p = bits & 0xff;
1083 
1084         return true;
1085 }
1086 
1087 #define double_pack64 uc_double_pack
1088 
1089 static double
1090 double_unpack16(const char *buf, bool little_endian)
1091 {
1092         uint32_t fraction;
1093         int32_t exponent;
1094         uint8_t *p;
1095         bool sign;
1096         double d;
1097 
1098         p = (uint8_t *)buf + little_endian;
1099         sign = (*p >> 7) & 1;
1100         exponent = (*p & 0x7c) >> 2;
1101         fraction = (*p & 0x03) << 8;
1102 
1103         p += little_endian ? -1 : 1;
1104         fraction |= *p;
1105 
1106         if (exponent == 0x1f) {
1107                 if (fraction == 0)
1108                         return sign ? -INFINITY : INFINITY;
1109                 else
1110                         return sign ? -NAN : NAN;
1111         }
1112 
1113         d = (double)fraction / 1024.0;
1114 
1115         if (exponent == 0) {
1116                 exponent = -14;
1117         }
1118         else {
1119                 exponent -= 15;
1120                 d += 1.0;
1121         }
1122 
1123         d = ldexp(d, exponent);
1124 
1125         return sign ? -d : d;
1126 }
1127 
1128 static double
1129 double_unpack32(const char *buf, bool little_endian)
1130 {
1131         int8_t step = little_endian ? -1 : 1;
1132         uint32_t fraction;
1133         int32_t exponent;
1134         uint8_t *p;
1135         bool sign;
1136         double d;
1137 
1138         p = (uint8_t *)buf + (little_endian ? 3 : 0);
1139         sign = (*p >> 7) & 1;
1140         exponent = (*p & 0x7f) << 1;
1141 
1142         p += step;
1143         exponent |= (*p >> 7) & 1;
1144         fraction = (*p & 0x7f) << 16;
1145 
1146         p += step;
1147         fraction |= *p << 8;
1148 
1149         p += step;
1150         fraction |= *p;
1151 
1152         if (exponent == 0xff) {
1153                 if (fraction == 0)
1154                         return sign ? -INFINITY : INFINITY;
1155                 else
1156                         return sign ? -NAN : NAN;
1157         }
1158 
1159         d = (double)fraction / 8388608.0;
1160 
1161         if (exponent == 0) {
1162                 exponent = -126;
1163         }
1164         else {
1165                 exponent -= 127;
1166                 d += 1.0;
1167         }
1168 
1169         d = ldexp(d, exponent);
1170 
1171         return sign ? -d : d;
1172 }
1173 
1174 #define double_unpack64 uc_double_unpack
1175 
1176 static bool
1177 range_exception(uc_vm_t *vm, const formatdef_t *f, bool is_unsigned)
1178 {
1179         /* ulargest is the largest unsigned value with f->size bytes.
1180          * Note that the simpler:
1181          *       ((size_t)1 << (f->size * 8)) - 1
1182          * doesn't work when f->size == sizeof(size_t) because C doesn't
1183          * define what happens when a left shift count is >= the number of
1184          * bits in the integer being shifted; e.g., on some boxes it doesn't
1185          * shift at all when they're equal.
1186          */
1187         const size_t ulargest = (size_t)-1 >> ((sizeof(size_t) - f->size)*8);
1188 
1189         assert(f->size >= 1 && f->size <= (ssize_t)sizeof(size_t));
1190 
1191         if (is_unsigned) {
1192                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1193                         "Format '%c' requires numeric argument between 0 and %zu",
1194                         f->format,
1195                         ulargest);
1196         }
1197         else {
1198                 const ssize_t largest = (ssize_t)(ulargest >> 1);
1199 
1200                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1201                         "Format '%c' requires numeric argument between %zd and %zd",
1202                         f->format,
1203                         ~ largest,
1204                         largest);
1205         }
1206 
1207         return false;
1208 }
1209 
1210 
1211 /* Native mode routines. ****************************************************/
1212 
1213 static uc_value_t *
1214 native_unpack_char(uc_vm_t *vm, const char *p, const formatdef_t *f)
1215 {
1216         return ucv_string_new_length(p, 1);
1217 }
1218 
1219 static uc_value_t *
1220 native_unpack_byte(uc_vm_t *vm, const char *p, const formatdef_t *f)
1221 {
1222         return ucv_int64_new(*(signed char *)p);
1223 }
1224 
1225 static uc_value_t *
1226 native_unpack_ubyte(uc_vm_t *vm, const char *p, const formatdef_t *f)
1227 {
1228         return ucv_uint64_new(*(unsigned char *)p);
1229 }
1230 
1231 static uc_value_t *
1232 native_unpack_short(uc_vm_t *vm, const char *p, const formatdef_t *f)
1233 {
1234         short x = 0;
1235 
1236         memcpy(&x, p, sizeof(x));
1237 
1238         return ucv_int64_new(x);
1239 }
1240 
1241 static uc_value_t *
1242 native_unpack_ushort(uc_vm_t *vm, const char *p, const formatdef_t *f)
1243 {
1244         unsigned short x = 0;
1245 
1246         memcpy(&x, p, sizeof(x));
1247 
1248         return ucv_uint64_new(x);
1249 }
1250 
1251 static uc_value_t *
1252 native_unpack_int(uc_vm_t *vm, const char *p, const formatdef_t *f)
1253 {
1254         int x = 0;
1255 
1256         memcpy(&x, p, sizeof(x));
1257 
1258         return ucv_int64_new(x);
1259 }
1260 
1261 static uc_value_t *
1262 native_unpack_uint(uc_vm_t *vm, const char *p, const formatdef_t *f)
1263 {
1264         unsigned int x = 0;
1265 
1266         memcpy(&x, p, sizeof(x));
1267 
1268         return ucv_uint64_new(x);
1269 }
1270 
1271 static uc_value_t *
1272 native_unpack_long(uc_vm_t *vm, const char *p, const formatdef_t *f)
1273 {
1274         long x = 0;
1275 
1276         memcpy(&x, p, sizeof(x));
1277 
1278         return ucv_int64_new(x);
1279 }
1280 
1281 static uc_value_t *
1282 native_unpack_ulong(uc_vm_t *vm, const char *p, const formatdef_t *f)
1283 {
1284         unsigned long x = 0;
1285 
1286         memcpy(&x, p, sizeof(x));
1287 
1288         return ucv_uint64_new(x);
1289 }
1290 
1291 static uc_value_t *
1292 native_unpack_ssize_t(uc_vm_t *vm, const char *p, const formatdef_t *f)
1293 {
1294         ssize_t x = 0;
1295 
1296         memcpy(&x, p, sizeof(x));
1297 
1298         return ucv_int64_new(x);
1299 }
1300 
1301 static uc_value_t *
1302 native_unpack_size_t(uc_vm_t *vm, const char *p, const formatdef_t *f)
1303 {
1304         size_t x = 0;
1305 
1306         memcpy(&x, p, sizeof(x));
1307 
1308         return ucv_uint64_new(x);
1309 }
1310 
1311 static uc_value_t *
1312 native_unpack_longlong(uc_vm_t *vm, const char *p, const formatdef_t *f)
1313 {
1314         long long x = 0;
1315 
1316         memcpy(&x, p, sizeof(x));
1317 
1318         return ucv_int64_new(x);
1319 }
1320 
1321 static uc_value_t *
1322 native_unpack_ulonglong(uc_vm_t *vm, const char *p, const formatdef_t *f)
1323 {
1324         unsigned long long x = 0;
1325 
1326         memcpy(&x, p, sizeof(x));
1327 
1328         return ucv_uint64_new(x);
1329 }
1330 
1331 static uc_value_t *
1332 native_unpack_bool(uc_vm_t *vm, const char *p, const formatdef_t *f)
1333 {
1334         bool x = false;
1335 
1336         memcpy(&x, p, sizeof(x));
1337 
1338         return ucv_boolean_new(x != 0);
1339 }
1340 
1341 
1342 static uc_value_t *
1343 native_unpack_halffloat(uc_vm_t *vm, const char *p, const formatdef_t *f)
1344 {
1345 #if __BYTE_ORDER == __LITTLE_ENDIAN
1346         return ucv_double_new(double_unpack16(p, true));
1347 #else
1348         return ucv_double_new(double_unpack16(p, false));
1349 #endif
1350 }
1351 
1352 static uc_value_t *
1353 native_unpack_float(uc_vm_t *vm, const char *p, const formatdef_t *f)
1354 {
1355         float x = 0.0;
1356 
1357         memcpy(&x, p, sizeof(x));
1358 
1359         return ucv_double_new(x);
1360 }
1361 
1362 static uc_value_t *
1363 native_unpack_double(uc_vm_t *vm, const char *p, const formatdef_t *f)
1364 {
1365         double x = 0.0;
1366 
1367         memcpy(&x, p, sizeof(x));
1368 
1369         return ucv_double_new(x);
1370 }
1371 
1372 static uc_value_t *
1373 native_unpack_void_p(uc_vm_t *vm, const char *p, const formatdef_t *f)
1374 {
1375         void *x = NULL;
1376 
1377         memcpy(&x, p, sizeof(x));
1378 
1379         return ucv_int64_new((intptr_t)x);
1380 }
1381 
1382 static bool
1383 native_pack_byte(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1384 {
1385         long x = 0;
1386 
1387         if (!ucv_as_long(vm, v, &x))
1388                 return false;
1389 
1390         if (x < -128 || x > 127) {
1391                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1392                         "Byte format requires numeric value between -128 and 127");
1393 
1394                 return false;
1395         }
1396 
1397         *p = (char)x;
1398 
1399         return true;
1400 }
1401 
1402 static bool
1403 native_pack_ubyte(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1404 {
1405         long x = 0;
1406 
1407         if (!ucv_as_long(vm, v, &x))
1408                 return false;
1409 
1410         if (x < 0 || x > 255) {
1411                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1412                         "Unsigned byte format requires numeric value between 0 and 255");
1413 
1414                 return false;
1415         }
1416 
1417         *(unsigned char *)p = (unsigned char)x;
1418 
1419         return true;
1420 }
1421 
1422 static bool
1423 native_pack_char(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1424 {
1425         char *s = NULL;
1426 
1427         if (ucv_type(v) == UC_STRING) {
1428                 s = ucv_string_get(v);
1429                 *p = *s;
1430         }
1431         else {
1432                 s = ucv_to_string(vm, v);
1433                 *p = *s;
1434                 free(s);
1435         }
1436 
1437         return true;
1438 }
1439 
1440 static bool
1441 native_pack_short(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1442 {
1443         long x = 0;
1444         short y = 0;
1445 
1446         if (!ucv_as_long(vm, v, &x))
1447                 return false;
1448 
1449         if (x < SHRT_MIN || x > SHRT_MAX) {
1450                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1451                         "Short format requires numeric value between %d and %d",
1452                         (int)SHRT_MIN, (int)SHRT_MAX);
1453 
1454                 return false;
1455         }
1456 
1457         y = (short)x;
1458         memcpy(p, &y, sizeof(y));
1459 
1460         return true;
1461 }
1462 
1463 static bool
1464 native_pack_ushort(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1465 {
1466         unsigned short y = 0;
1467         long x = 0;
1468 
1469         if (!ucv_as_long(vm, v, &x))
1470                 return false;
1471 
1472         if (x < 0 || x > USHRT_MAX) {
1473                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
1474                         "Unsigned short format requires numeric value between 0 and %u",
1475                         (unsigned int)USHRT_MAX);
1476 
1477                 return false;
1478         }
1479 
1480         y = (unsigned short)x;
1481         memcpy(p, &y, sizeof(y));
1482 
1483         return true;
1484 }
1485 
1486 static bool
1487 native_pack_int(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1488 {
1489         long x = 0;
1490         int y = 0;
1491 
1492         if (!ucv_as_long(vm, v, &x))
1493                 return false;
1494 
1495         if (sizeof(long) > sizeof(int)) {
1496                 if ((x < ((long)INT_MIN)) || (x > ((long)INT_MAX)))
1497                         return range_exception(vm, f, false);
1498         }
1499 
1500         y = (int)x;
1501         memcpy(p, &y, sizeof(y));
1502 
1503         return true;
1504 }
1505 
1506 static bool
1507 native_pack_uint(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1508 {
1509         unsigned long x = 0;
1510         unsigned int y = 0;
1511 
1512         if (!ucv_as_ulong(vm, v, &x))
1513                 return false;
1514 
1515         if (sizeof(long) > sizeof(int)) {
1516                 if (x > ((unsigned long)UINT_MAX))
1517                         return range_exception(vm, f, true);
1518         }
1519 
1520         y = (unsigned int)x;
1521         memcpy(p, &y, sizeof(y));
1522 
1523         return true;
1524 }
1525 
1526 static bool
1527 native_pack_long(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1528 {
1529         long x = 0;
1530 
1531         if (!ucv_as_long(vm, v, &x))
1532                 return false;
1533 
1534         memcpy(p, &x, sizeof(x));
1535 
1536         return true;
1537 }
1538 
1539 static bool
1540 native_pack_ulong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1541 {
1542         unsigned long x = 0;
1543 
1544         if (!ucv_as_ulong(vm, v, &x))
1545                 return false;
1546 
1547         memcpy(p, &x, sizeof(x));
1548 
1549         return true;
1550 }
1551 
1552 static bool
1553 native_pack_ssize_t(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1554 {
1555         ssize_t x = 0;
1556 
1557         if (!ucv_as_ssize_t(vm, v, &x))
1558                 return false;
1559 
1560         memcpy(p, &x, sizeof(x));
1561 
1562         return true;
1563 }
1564 
1565 static bool
1566 native_pack_size_t(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1567 {
1568         size_t x = 0;
1569 
1570         if (!ucv_as_size_t(vm, v, &x))
1571                 return false;
1572 
1573         memcpy(p, &x, sizeof(x));
1574 
1575         return true;
1576 }
1577 
1578 static bool
1579 native_pack_longlong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1580 {
1581         long long x = 0;
1582 
1583         if (!ucv_as_longlong(vm, v, &x))
1584                 return false;
1585 
1586         memcpy(p, &x, sizeof(x));
1587 
1588         return true;
1589 }
1590 
1591 static bool
1592 native_pack_ulonglong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1593 {
1594         unsigned long long x = 0;
1595 
1596         if (!ucv_as_ulonglong(vm, v, &x))
1597                 return false;
1598 
1599         memcpy(p, &x, sizeof(x));
1600 
1601         return true;
1602 }
1603 
1604 
1605 static bool
1606 native_pack_bool(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1607 {
1608         bool x = 0;
1609 
1610         x = ucv_is_truish(v);
1611 
1612         memcpy(p, &x, sizeof(x));
1613 
1614         return true;
1615 }
1616 
1617 static bool
1618 native_pack_halffloat(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1619 {
1620         double x;
1621 
1622         if (!ucv_as_double(vm, v, &x))
1623                 return false;
1624 
1625 #if __BYTE_ORDER == __LITTLE_ENDIAN
1626         return double_pack16(x, p, true);
1627 #else
1628         return double_pack16(x, p, false);
1629 #endif
1630 }
1631 
1632 static bool
1633 native_pack_float(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1634 {
1635         double d = 0.0;
1636         float x = 0.0;
1637 
1638         if (!ucv_as_double(vm, v, &d))
1639                 return false;
1640 
1641         x = (float)d;
1642         memcpy(p, &x, sizeof(x));
1643 
1644         return true;
1645 }
1646 
1647 static bool
1648 native_pack_double(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1649 {
1650         double x = 0.0;
1651 
1652         if (!ucv_as_double(vm, v, &x))
1653                 return false;
1654 
1655         memcpy(p, &x, sizeof(x));
1656 
1657         return true;
1658 }
1659 
1660 static bool
1661 native_pack_void_p(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1662 {
1663         long long int i = 0;
1664         void *x = NULL;
1665 
1666         if (!ucv_as_longlong(vm, v, &i))
1667                 return false;
1668 
1669         x = (void *)(intptr_t)i;
1670         memcpy(p, &x, sizeof(x));
1671 
1672         return true;
1673 }
1674 
1675 static const formatdef_t native_endian_table[] = {
1676         { 'x', sizeof(char), 0, NULL, NULL },
1677         { 'b', sizeof(char), 0, native_unpack_byte, native_pack_byte },
1678         { 'B', sizeof(char), 0, native_unpack_ubyte, native_pack_ubyte },
1679         { 'c', sizeof(char), 0, native_unpack_char, native_pack_char },
1680         { '*', sizeof(char), 0, NULL, NULL },
1681         { 's', sizeof(char), 0, NULL, NULL },
1682         { 'p', sizeof(char), 0, NULL, NULL },
1683         { 'X', sizeof(char), 0, NULL, NULL },
1684         { 'Z', sizeof(char), 0, NULL, NULL },
1685         { 'h', sizeof(short), SHORT_ALIGN, native_unpack_short, native_pack_short },
1686         { 'H', sizeof(short), SHORT_ALIGN, native_unpack_ushort, native_pack_ushort },
1687         { 'i', sizeof(int),     INT_ALIGN, native_unpack_int, native_pack_int },
1688         { 'I', sizeof(int),     INT_ALIGN, native_unpack_uint, native_pack_uint },
1689         { 'l', sizeof(long), LONG_ALIGN, native_unpack_long, native_pack_long },
1690         { 'L', sizeof(long), LONG_ALIGN, native_unpack_ulong, native_pack_ulong },
1691         { 'n', sizeof(size_t), SIZE_T_ALIGN, native_unpack_ssize_t, native_pack_ssize_t },
1692         { 'N', sizeof(size_t), SIZE_T_ALIGN, native_unpack_size_t, native_pack_size_t },
1693         { 'q', sizeof(long long), LONG_LONG_ALIGN, native_unpack_longlong, native_pack_longlong },
1694         { 'Q', sizeof(long long), LONG_LONG_ALIGN, native_unpack_ulonglong,native_pack_ulonglong },
1695         { '?', sizeof(bool), BOOL_ALIGN, native_unpack_bool, native_pack_bool },
1696         { 'e', sizeof(short), SHORT_ALIGN, native_unpack_halffloat, native_pack_halffloat },
1697         { 'f', sizeof(float), FLOAT_ALIGN, native_unpack_float, native_pack_float },
1698         { 'd', sizeof(double), DOUBLE_ALIGN, native_unpack_double, native_pack_double },
1699         { 'P', sizeof(void *), VOID_P_ALIGN, native_unpack_void_p, native_pack_void_p },
1700         { 0 }
1701 };
1702 
1703 
1704 /* Big-endian routines. *****************************************************/
1705 
1706 static uc_value_t *
1707 be_unpack_int(uc_vm_t *vm, const char *p, const formatdef_t *f)
1708 {
1709         const unsigned char *bytes = (const unsigned char *)p;
1710         ssize_t i = f->size;
1711         long x = 0;
1712 
1713         do {
1714                 x = (x<<8) | *bytes++;
1715         } while (--i > 0);
1716 
1717         /* Extend the sign bit. */
1718         if ((ssize_t)sizeof(long) > f->size)
1719                 x |= -(x & (1L << ((8 * f->size) - 1)));
1720 
1721         return ucv_int64_new(x);
1722 }
1723 
1724 static uc_value_t *
1725 be_unpack_uint(uc_vm_t *vm, const char *p, const formatdef_t *f)
1726 {
1727         const unsigned char *bytes = (const unsigned char *)p;
1728         ssize_t i = f->size;
1729         unsigned long x = 0;
1730 
1731         do {
1732                 x = (x<<8) | *bytes++;
1733         } while (--i > 0);
1734 
1735         return ucv_uint64_new(x);
1736 }
1737 
1738 static uc_value_t *
1739 be_unpack_longlong(uc_vm_t *vm, const char *p, const formatdef_t *f)
1740 {
1741         const unsigned char *bytes = (const unsigned char *)p;
1742         ssize_t i = f->size;
1743         long long x = 0;
1744 
1745         do {
1746                 x = (x<<8) | *bytes++;
1747         } while (--i > 0);
1748 
1749         /* Extend the sign bit. */
1750         if ((ssize_t)sizeof(long long) > f->size)
1751                 x |= -(x & ((long long)1 << ((8 * f->size) - 1)));
1752 
1753         return ucv_int64_new(x);
1754 }
1755 
1756 static uc_value_t *
1757 be_unpack_ulonglong(uc_vm_t *vm, const char *p, const formatdef_t *f)
1758 {
1759         const unsigned char *bytes = (const unsigned char *)p;
1760         unsigned long long x = 0;
1761         ssize_t i = f->size;
1762 
1763         do {
1764                 x = (x<<8) | *bytes++;
1765         } while (--i > 0);
1766 
1767         return ucv_uint64_new(x);
1768 }
1769 
1770 static uc_value_t *
1771 be_unpack_halffloat(uc_vm_t *vm, const char *p, const formatdef_t *f)
1772 {
1773         return ucv_double_new(double_unpack16(p, false));
1774 }
1775 
1776 static uc_value_t *
1777 be_unpack_float(uc_vm_t *vm, const char *p, const formatdef_t *f)
1778 {
1779         return ucv_double_new(double_unpack32(p, false));
1780 }
1781 
1782 static uc_value_t *
1783 be_unpack_double(uc_vm_t *vm, const char *p, const formatdef_t *f)
1784 {
1785         return ucv_double_new(double_unpack64(p, false));
1786 }
1787 
1788 static uc_value_t *
1789 be_unpack_bool(uc_vm_t *vm, const char *p, const formatdef_t *f)
1790 {
1791         return ucv_boolean_new(*p != 0);
1792 }
1793 
1794 static bool
1795 be_pack_int(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1796 {
1797         unsigned char *q = (unsigned char *)p;
1798         ssize_t i = 0;
1799         long x = 0;
1800 
1801         if (!ucv_as_long(vm, v, &x))
1802                 return false;
1803 
1804         i = f->size;
1805 
1806         if (i != sizeof(long)) {
1807                 if ((i == 2) && (x < -32768 || x > 32767))
1808                         return range_exception(vm, f, false);
1809 #if UINT_MAX < ULONG_MAX
1810                 else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
1811                         return range_exception(vm, f, false);
1812 #endif
1813         }
1814 
1815         do {
1816                 q[--i] = (unsigned char)(x & 0xffL);
1817                 x >>= 8;
1818         } while (i > 0);
1819 
1820         return true;
1821 }
1822 
1823 static bool
1824 be_pack_uint(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1825 {
1826         unsigned char *q = (unsigned char *)p;
1827         unsigned long x = 0;
1828         ssize_t i = 0;
1829 
1830         if (!ucv_as_ulong(vm, v, &x))
1831                 return false;
1832 
1833         i = f->size;
1834 
1835         if (i != sizeof(long)) {
1836                 unsigned long maxint = 1;
1837                 maxint <<= (unsigned long)(i * 8);
1838                 if (x >= maxint)
1839                         return range_exception(vm, f, true);
1840         }
1841 
1842         do {
1843                 q[--i] = (unsigned char)(x & 0xffUL);
1844                 x >>= 8;
1845         } while (i > 0);
1846 
1847         return true;
1848 }
1849 
1850 static bool
1851 be_pack_longlong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1852 {
1853         unsigned char *q = (unsigned char *)p;
1854         long long x = 0;
1855         ssize_t i = 0;
1856 
1857         if (!ucv_as_longlong(vm, v, &x))
1858                 return false;
1859 
1860         i = f->size;
1861 
1862         do {
1863                 q[--i] = (unsigned char)(x & 0xffL);
1864                 x >>= 8;
1865         } while (i > 0);
1866 
1867         return true;
1868 }
1869 
1870 static bool
1871 be_pack_ulonglong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1872 {
1873         unsigned char *q = (unsigned char *)p;
1874         unsigned long long x = 0;
1875         ssize_t i = 0;
1876 
1877         if (!ucv_as_ulonglong(vm, v, &x))
1878                 return false;
1879 
1880         i = f->size;
1881 
1882         do {
1883                 q[--i] = (unsigned char)(x & 0xffUL);
1884                 x >>= 8;
1885         } while (i > 0);
1886 
1887         return true;
1888 }
1889 
1890 static bool
1891 be_pack_halffloat(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1892 {
1893         double x = 0.0;
1894 
1895         if (!ucv_as_double(vm, v, &x))
1896                 return false;
1897 
1898         return double_pack16(x, p, false);
1899 }
1900 
1901 static bool
1902 be_pack_float(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1903 {
1904         double x = 0.0;
1905 
1906         if (!ucv_as_double(vm, v, &x))
1907                 return false;
1908 
1909         if (!double_pack32(x, p, 0)) {
1910                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Argument out of range");
1911 
1912                 return false;
1913         }
1914 
1915         return true;
1916 }
1917 
1918 static bool
1919 be_pack_double(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1920 {
1921         double x = 0.0;
1922 
1923         if (!ucv_as_double(vm, v, &x))
1924                 return false;
1925 
1926         if (!double_pack64(x, p, 0)) {
1927                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Argument out of range");
1928 
1929                 return false;
1930         }
1931 
1932         return true;
1933 }
1934 
1935 static bool
1936 be_pack_bool(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
1937 {
1938         *p = (char)ucv_is_truish(v);
1939 
1940         return true;
1941 }
1942 
1943 static formatdef_t big_endian_table[] = {
1944         { 'x', 1, 0, NULL, NULL },
1945         { 'b', 1, 0, native_unpack_byte, native_pack_byte },
1946         { 'B', 1, 0, native_unpack_ubyte, native_pack_ubyte },
1947         { 'c', 1, 0, native_unpack_char, native_pack_char },
1948         { '*', 1, 0, NULL, NULL },
1949         { 's', 1, 0, NULL, NULL },
1950         { 'p', 1, 0, NULL, NULL },
1951         { 'X', 1, 0, NULL, NULL },
1952         { 'Z', 1, 0, NULL, NULL },
1953         { 'h', 2, 0, be_unpack_int, be_pack_int },
1954         { 'H', 2, 0, be_unpack_uint, be_pack_uint },
1955         { 'i', 4, 0, be_unpack_int, be_pack_int },
1956         { 'I', 4, 0, be_unpack_uint, be_pack_uint },
1957         { 'l', 4, 0, be_unpack_int, be_pack_int },
1958         { 'L', 4, 0, be_unpack_uint, be_pack_uint },
1959         { 'q', 8, 0, be_unpack_longlong, be_pack_longlong },
1960         { 'Q', 8, 0, be_unpack_ulonglong, be_pack_ulonglong },
1961         { '?', 1, 0, be_unpack_bool, be_pack_bool },
1962         { 'e', 2, 0, be_unpack_halffloat, be_pack_halffloat },
1963         { 'f', 4, 0, be_unpack_float, be_pack_float },
1964         { 'd', 8, 0, be_unpack_double, be_pack_double },
1965         { 0 }
1966 };
1967 
1968 
1969 /* Little-endian routines. *****************************************************/
1970 
1971 static uc_value_t *
1972 le_unpack_int(uc_vm_t *vm, const char *p, const formatdef_t *f)
1973 {
1974         const unsigned char *bytes = (const unsigned char *)p;
1975         ssize_t i = f->size;
1976         long x = 0;
1977 
1978         do {
1979                 x = (x<<8) | bytes[--i];
1980         } while (i > 0);
1981 
1982         /* Extend the sign bit. */
1983         if ((ssize_t)sizeof(long) > f->size)
1984                 x |= -(x & (1L << ((8 * f->size) - 1)));
1985 
1986         return ucv_int64_new(x);
1987 }
1988 
1989 static uc_value_t *
1990 le_unpack_uint(uc_vm_t *vm, const char *p, const formatdef_t *f)
1991 {
1992         const unsigned char *bytes = (const unsigned char *)p;
1993         ssize_t i = f->size;
1994         unsigned long x = 0;
1995 
1996         do {
1997                 x = (x<<8) | bytes[--i];
1998         } while (i > 0);
1999 
2000         return ucv_uint64_new(x);
2001 }
2002 
2003 static uc_value_t *
2004 le_unpack_longlong(uc_vm_t *vm, const char *p, const formatdef_t *f)
2005 {
2006         const unsigned char *bytes = (const unsigned char *)p;
2007         ssize_t i = f->size;
2008         long long x = 0;
2009 
2010         do {
2011                 x = (x<<8) | bytes[--i];
2012         } while (i > 0);
2013 
2014         /* Extend the sign bit. */
2015         if ((ssize_t)sizeof(long long) > f->size)
2016                 x |= -(x & ((long long)1 << ((8 * f->size) - 1)));
2017 
2018         return ucv_int64_new(x);
2019 }
2020 
2021 static uc_value_t *
2022 le_unpack_ulonglong(uc_vm_t *vm, const char *p, const formatdef_t *f)
2023 {
2024         const unsigned char *bytes = (const unsigned char *)p;
2025         unsigned long long x = 0;
2026         ssize_t i = f->size;
2027 
2028         do {
2029                 x = (x<<8) | bytes[--i];
2030         } while (i > 0);
2031 
2032         return ucv_uint64_new(x);
2033 }
2034 
2035 static uc_value_t *
2036 le_unpack_halffloat(uc_vm_t *vm, const char *p, const formatdef_t *f)
2037 {
2038         return ucv_double_new(double_unpack16(p, true));
2039 }
2040 
2041 static uc_value_t *
2042 le_unpack_float(uc_vm_t *vm, const char *p, const formatdef_t *f)
2043 {
2044         return ucv_double_new(double_unpack32(p, true));
2045 }
2046 
2047 static uc_value_t *
2048 le_unpack_double(uc_vm_t *vm, const char *p, const formatdef_t *f)
2049 {
2050         return ucv_double_new(double_unpack64(p, true));
2051 }
2052 
2053 static bool
2054 le_pack_int(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
2055 {
2056         unsigned char *q = (unsigned char *)p;
2057         ssize_t i = 0;
2058         long x = 0;
2059 
2060         if (!ucv_as_long(vm, v, &x))
2061                 return false;
2062 
2063         i = f->size;
2064 
2065         if (i != sizeof(long)) {
2066                 if ((i == 2) && (x < -32768 || x > 32767))
2067                         return range_exception(vm, f, false);
2068 #if UINT_MAX < ULONG_MAX
2069                 else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
2070                         return range_exception(vm, f, false);
2071 #endif
2072         }
2073 
2074         do {
2075                 *q++ = (unsigned char)(x & 0xffL);
2076                 x >>= 8;
2077         } while (--i > 0);
2078 
2079         return true;
2080 }
2081 
2082 static bool
2083 le_pack_uint(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
2084 {
2085         unsigned char *q = (unsigned char *)p;
2086         unsigned long x = 0;
2087         ssize_t i = 0;
2088 
2089         if (!ucv_as_ulong(vm, v, &x))
2090                 return false;
2091 
2092         i = f->size;
2093 
2094         if (i != sizeof(long)) {
2095                 unsigned long maxint = 1;
2096                 maxint <<= (unsigned long)(i * 8);
2097 
2098                 if (x >= maxint)
2099                         return range_exception(vm, f, true);
2100         }
2101 
2102         do {
2103                 *q++ = (unsigned char)(x & 0xffUL);
2104                 x >>= 8;
2105         } while (--i > 0);
2106 
2107         return true;
2108 }
2109 
2110 static bool
2111 le_pack_longlong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
2112 {
2113         unsigned char *q = (unsigned char *)p;
2114         long long x = 0;
2115         ssize_t i = 0;
2116 
2117         if (!ucv_as_longlong(vm, v, &x))
2118                 return false;
2119 
2120         i = f->size;
2121 
2122         do {
2123                 *q++ = (unsigned char)(x & 0xffL);
2124                 x >>= 8;
2125         } while (--i > 0);
2126 
2127         return true;
2128 }
2129 
2130 static bool
2131 le_pack_ulonglong(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
2132 {
2133         unsigned char *q = (unsigned char *)p;
2134         unsigned long long x = 0;
2135         ssize_t i = 0;
2136 
2137         if (!ucv_as_ulonglong(vm, v, &x))
2138                 return false;
2139 
2140         i = f->size;
2141 
2142         do {
2143                 *q++ = (unsigned char)(x & 0xffUL);
2144                 x >>= 8;
2145         } while (--i > 0);
2146 
2147         return true;
2148 }
2149 
2150 static bool
2151 le_pack_halffloat(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
2152 {
2153         double x = 0.0;
2154 
2155         if (!ucv_as_double(vm, v, &x))
2156                 return false;
2157 
2158         return double_pack16(x, p, true);
2159 }
2160 
2161 static bool
2162 le_pack_float(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
2163 {
2164         double x = 0.0;
2165 
2166         if (!ucv_as_double(vm, v, &x))
2167                 return false;
2168 
2169         if (!double_pack32(x, p, 1)) {
2170                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Argument out of range");
2171 
2172                 return false;
2173         }
2174 
2175         return true;
2176 }
2177 
2178 static bool
2179 le_pack_double(uc_vm_t *vm, char *p, uc_value_t *v, const formatdef_t *f)
2180 {
2181         double x = 0.0;
2182 
2183         if (!ucv_as_double(vm, v, &x))
2184                 return false;
2185 
2186         if (!double_pack64(x, p, 1)) {
2187                 uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Argument out of range");
2188 
2189                 return false;
2190         }
2191 
2192         return true;
2193 }
2194 
2195 static formatdef_t little_endian_table[] = {
2196         { 'x', 1, 0, NULL, NULL },
2197         { 'b', 1, 0, native_unpack_byte, native_pack_byte },
2198         { 'B', 1, 0, native_unpack_ubyte, native_pack_ubyte },
2199         { 'c', 1, 0, native_unpack_char, native_pack_char },
2200         { '*', 1, 0, NULL, NULL },
2201         { 's', 1, 0, NULL, NULL },
2202         { 'p', 1, 0, NULL, NULL },
2203         { 'X', 1, 0, NULL, NULL },
2204         { 'Z', 1, 0, NULL, NULL },
2205         { 'h', 2, 0, le_unpack_int, le_pack_int },
2206         { 'H', 2, 0, le_unpack_uint, le_pack_uint },
2207         { 'i', 4, 0, le_unpack_int, le_pack_int },
2208         { 'I', 4, 0, le_unpack_uint, le_pack_uint },
2209         { 'l', 4, 0, le_unpack_int, le_pack_int },
2210         { 'L', 4, 0, le_unpack_uint, le_pack_uint },
2211         { 'q', 8, 0, le_unpack_longlong, le_pack_longlong },
2212         { 'Q', 8, 0, le_unpack_ulonglong, le_pack_ulonglong },
2213         { '?', 1, 0, be_unpack_bool, be_pack_bool },
2214         { 'e', 2, 0, le_unpack_halffloat, le_pack_halffloat },
2215         { 'f', 4, 0, le_unpack_float, le_pack_float },
2216         { 'd', 8, 0, le_unpack_double, le_pack_double },
2217         { 0 }
2218 };
2219 
2220 
2221 static const formatdef_t *
2222 select_format_table(const char **pfmt)
2223 {
2224         const char *fmt = (*pfmt)++; /* May be backed out of later */
2225 
2226         switch (*fmt) {
2227         case '<':
2228                 return little_endian_table;
2229 
2230         case '>':
2231         case '!': /* Network byte order is big-endian */
2232                 return big_endian_table;
2233 
2234         case '=':  /* Host byte order -- different from native in alignment! */
2235 #if __BYTE_ORDER == __LITTLE_ENDIAN
2236                 return little_endian_table;
2237 #else
2238                 return big_endian_table;
2239 #endif
2240 
2241         default:
2242                 --*pfmt; /* Back out of pointer increment */
2243                 /* Fall through */
2244 
2245         case '@':
2246                 return native_endian_table;
2247         }
2248 }
2249 
2250 
2251 /* Get the table entry for a format code */
2252 
2253 static const formatdef_t *
2254 lookup_table_entry(uc_vm_t *vm, int c, const formatdef_t *table)
2255 {
2256         for (; table->format != '\0'; table++) {
2257                 if (table->format == c) {
2258                         return table;
2259                 }
2260         }
2261 
2262         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2263                 "Unrecognized character '%c' in struct format",
2264                 c);
2265 
2266         return NULL;
2267 }
2268 
2269 
2270 /* Align a size according to a format code.  Return -1 on overflow. */
2271 
2272 static ssize_t
2273 align_for_entry(ssize_t size, const formatdef_t *e)
2274 {
2275         ssize_t extra;
2276 
2277         if (e->alignment && size > 0) {
2278                 extra = (e->alignment - 1) - (size - 1) % (e->alignment);
2279 
2280                 if (extra > SSIZE_MAX - size)
2281                         return -1;
2282 
2283                 size += extra;
2284         }
2285 
2286         return size;
2287 }
2288 
2289 
2290 static void
2291 optimize_functions(void)
2292 {
2293         /* Check endian and swap in faster functions */
2294         const formatdef_t *native = native_endian_table;
2295         formatdef_t *other, *ptr;
2296 
2297 #if __BYTE_ORDER == __LITTLE_ENDIAN
2298         other = little_endian_table;
2299 #else
2300         other = big_endian_table;
2301 #endif
2302 
2303         /* Scan through the native table, find a matching
2304            entry in the endian table and swap in the
2305            native implementations whenever possible
2306            (64-bit platforms may not have "standard" sizes) */
2307         while (native->format != '\0' && other->format != '\0') {
2308                 ptr = other;
2309 
2310                 while (ptr->format != '\0') {
2311                         if (ptr->format == native->format) {
2312                                 /* Match faster when formats are
2313                                    listed in the same order */
2314                                 if (ptr == other)
2315                                         other++;
2316 
2317                                 /* Only use the trick if the
2318                                    size matches */
2319                                 if (ptr->size != native->size)
2320                                         break;
2321 
2322                                 /* Skip float and double, could be
2323                                    "unknown" float format */
2324                                 if (ptr->format == 'd' || ptr->format == 'f')
2325                                         break;
2326 
2327                                 /* Skip bool, semantics are different for standard size */
2328                                 if (ptr->format == '?')
2329                                         break;
2330 
2331                                 ptr->pack = native->pack;
2332                                 ptr->unpack = native->unpack;
2333                                 break;
2334                         }
2335 
2336                         ptr++;
2337                 }
2338 
2339                 native++;
2340         }
2341 }
2342 
2343 static formatstate_t *
2344 parse_format(uc_vm_t *vm, uc_value_t *fmtval)
2345 {
2346         ssize_t size, num, itemsize;
2347         const formatdef_t *e, *f;
2348         const char *fmt, *s;
2349         formatstate_t *state;
2350         formatcode_t *codes;
2351         size_t ncodes;
2352         char c;
2353 
2354         if (ucv_type(fmtval) != UC_STRING) {
2355                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2356                         "Format value not a string");
2357 
2358                 return NULL;
2359         }
2360 
2361         fmt = ucv_string_get(fmtval);
2362 
2363         if (strlen(fmt) != ucv_string_length(fmtval)) {
2364                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2365                         "Format string contains embedded null character");
2366 
2367                 return NULL;
2368         }
2369 
2370         f = select_format_table(&fmt);
2371 
2372         s = fmt;
2373         size = 0;
2374         ncodes = 0;
2375 
2376         while ((c = *s++) != '\0') {
2377                 if (isspace(c))
2378                         continue;
2379 
2380                 if ('' <= c && c <= '9') {
2381                         num = c - '';
2382 
2383                         while ('' <= (c = *s++) && c <= '9') {
2384                                 /* overflow-safe version of
2385                                    if (num*10 + (c - '') > SSIZE_MAX) { ... } */
2386                                 if (num >= SSIZE_MAX / 10 && (
2387                                                 num > SSIZE_MAX / 10 ||
2388                                                 (c - '') > SSIZE_MAX % 10))
2389                                         goto overflow;
2390 
2391                                 num = num*10 + (c - '');
2392                         }
2393 
2394                         if (c == '\0') {
2395                                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2396                                         "Format string contains repeat count given without format specifier");
2397 
2398                                 return NULL;
2399                         }
2400                 }
2401                 else if (c == '*' || c == 'X' || c == 'Z')
2402                         num = -1;
2403                 else
2404                         num = 1;
2405 
2406                 e = lookup_table_entry(vm, c, f);
2407 
2408                 if (e == NULL)
2409                         return NULL;
2410 
2411                 switch (c) {
2412                 case '*': /* fall through */
2413                 case 's':
2414                 case 'p':
2415                 case 'X':
2416                 case 'Z':
2417                         ncodes++;
2418                         break;
2419 
2420                 case 'x':
2421                         break;
2422 
2423                 default:
2424                         if (num)
2425                                 ncodes++;
2426 
2427                         break;
2428                 }
2429 
2430                 itemsize = e->size;
2431                 size = align_for_entry(size, e);
2432 
2433                 if (size == -1)
2434                         goto overflow;
2435 
2436                 /* if (size + num * itemsize > SSIZE_MAX) { ... } */
2437                 if (num > (SSIZE_MAX - size) / itemsize)
2438                         goto overflow;
2439 
2440                 size += (c != '*' && c != 'X' && c != 'Z') ? num * itemsize : 0;
2441         }
2442 
2443         /* check for overflow */
2444         if ((ncodes + 1) > ((size_t)SSIZE_MAX / sizeof(formatcode_t))) {
2445                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "Out of memory");
2446 
2447                 return NULL;
2448         }
2449 
2450         state = xalloc(sizeof(*state) + ncodes * sizeof(formatcode_t));
2451         state->size = size;
2452         state->ncodes = ncodes;
2453 
2454         codes = state->codes;
2455 
2456         s = fmt;
2457         size = 0;
2458 
2459         while ((c = *s++) != '\0') {
2460                 if (isspace(c))
2461                         continue;
2462 
2463                 if ('' <= c && c <= '9') {
2464                         num = c - '';
2465 
2466                         while ('' <= (c = *s++) && c <= '9')
2467                                 num = num*10 + (c - '');
2468 
2469                 }
2470                 else if (c == '*' || c == 'X' || c == 'Z')
2471                         num = -1;
2472                 else
2473                         num = 1;
2474 
2475                 e = lookup_table_entry(vm, c, f);
2476 
2477                 if (e == NULL)
2478                         continue;
2479 
2480                 size = align_for_entry(size, e);
2481 
2482                 if (c == '*' || c == 's' || c == 'p' || c == 'X' || c == 'Z') {
2483                         codes->offset = size;
2484                         codes->size = num;
2485                         codes->fmtdef = e;
2486                         codes->repeat = 1;
2487                         codes++;
2488                         size += (c == 's' || c == 'p') ? num : 0;
2489                 }
2490                 else if (c == 'x') {
2491                         size += num;
2492                 }
2493                 else if (num) {
2494                         codes->offset = size;
2495                         codes->size = e->size;
2496                         codes->fmtdef = e;
2497                         codes->repeat = num;
2498                         codes++;
2499                         size += e->size * num;
2500                 }
2501         }
2502 
2503         return state;
2504 
2505 overflow:
2506         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2507                 "Total struct size too long");
2508 
2509         return NULL;
2510 }
2511 
2512 static bool
2513 grow_buffer(uc_vm_t *vm, void **buf, size_t *bufsz, size_t length)
2514 {
2515         const size_t overhead = sizeof(uc_string_t) + 1;
2516 
2517         if (length > *bufsz) {
2518                 size_t old_size = *bufsz;
2519                 size_t new_size = (length + 7u) & ~7u;
2520 
2521                 if (*buf != NULL) {
2522                         new_size = *bufsz;
2523 
2524                         while (length > new_size) {
2525                                 if (new_size > SIZE_MAX - (new_size >> 1)) {
2526                                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2527                                                 "Overflow reallocating buffer from %zu to %zu bytes",
2528                                                 *bufsz, length);
2529 
2530                                         return false;
2531                                 }
2532 
2533                                 new_size += ((new_size >> 1) + 7u) & ~7u;
2534                         }
2535                 }
2536 
2537                 char *tmp = realloc(*buf, new_size + overhead);
2538 
2539                 if (!tmp) {
2540                         uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
2541                                 "Error reallocating buffer to %zu+%zu bytes: %m",
2542                                 new_size, overhead);
2543 
2544                         return false;
2545                 }
2546 
2547                 if (*buf)
2548                         memset(tmp + overhead + old_size - 1, 0, new_size - old_size + 1);
2549                 else
2550                         memset(tmp, 0, new_size + overhead);
2551 
2552                 *buf = tmp;
2553                 *bufsz = new_size;
2554         }
2555 
2556         return true;
2557 }
2558 
2559 /* -------------------------------------------------------------------------
2560  * The following base64 encoding and decoding routines are taken from
2561  * https://git.openwrt.org/?p=project/libubox.git;a=blob;f=base64.c
2562  * and modified for use in ucode.
2563  *
2564  * Original copyright and license statements below.
2565  */
2566 
2567 /*
2568  * base64 - libubox base64 functions
2569  *
2570  * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
2571  *
2572  * Permission to use, copy, modify, and/or distribute this software for any
2573  * purpose with or without fee is hereby granted, provided that the above
2574  * copyright notice and this permission notice appear in all copies.
2575  *
2576  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2577  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2578  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2579  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2580  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2581  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2582  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2583  */
2584 
2585 /*      $OpenBSD: base64.c,v 1.7 2013/12/31 02:32:56 tedu Exp $ */
2586 
2587 /*
2588  * Copyright (c) 1996 by Internet Software Consortium.
2589  *
2590  * Permission to use, copy, modify, and distribute this software for any
2591  * purpose with or without fee is hereby granted, provided that the above
2592  * copyright notice and this permission notice appear in all copies.
2593  *
2594  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
2595  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
2596  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
2597  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
2598  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
2599  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
2600  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2601  * SOFTWARE.
2602  */
2603 
2604 /*
2605  * Portions Copyright (c) 1995 by International Business Machines, Inc.
2606  *
2607  * International Business Machines, Inc. (hereinafter called IBM) grants
2608  * permission under its copyrights to use, copy, modify, and distribute this
2609  * Software with or without fee, provided that the above copyright notice and
2610  * all paragraphs of this notice appear in all copies, and that the name of IBM
2611  * not be used in connection with the marketing of any product incorporating
2612  * the Software or modifications thereof, without specific, written prior
2613  * permission.
2614  *
2615  * To the extent it has a right to do so, IBM grants an immunity from suit
2616  * under its patents, if any, for the use, sale or manufacture of products to
2617  * the extent that such products are used for performing Domain Name System
2618  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
2619  * granted for any product per se or for any other function of any product.
2620  *
2621  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
2622  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2623  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
2624  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
2625  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
2626  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
2627  */
2628 
2629 /* skips all whitespace anywhere.
2630    converts characters, four at a time, starting at (or after)
2631    src from base - 64 numbers into three 8 bit bytes in the target area.
2632    it returns the number of data bytes stored at the target, or -1 on error.
2633  */
2634 
2635 static bool
2636 b64dec(char *dest, size_t *dest_len, const char *src, size_t src_len,
2637        const char **errp)
2638 {
2639         enum { BYTE1, BYTE2, BYTE3, BYTE4 } state = BYTE1;
2640         unsigned int ch = 0;
2641         size_t dest_off = 0;
2642         size_t src_off = 0;
2643         uint8_t val;
2644 
2645         for (; src_off < src_len; src_off++) {
2646                 ch = (unsigned char)src[src_off];
2647 
2648                 if (isspace(ch))        /* Skip whitespace anywhere. */
2649                         continue;
2650 
2651                 if (ch == '=' || dest_off >= *dest_len)
2652                         break;
2653 
2654                 if (ch >= 'A' && ch <= 'Z')
2655                         val = ch - 'A';
2656                 else if (ch >= 'a' && ch <= 'z')
2657                         val = ch - 'a' + 26;
2658                 else if (ch >= '' && ch <= '9')
2659                         val = ch - '' + 52;
2660                 else if (ch == '+')
2661                         val = 62;
2662                 else if (ch == '/')
2663                         val = 63;
2664                 else
2665                         return *errp = "Invalid character", false;
2666 
2667                 switch (state) {
2668                 case BYTE1:
2669                         dest[dest_off] = val << 2;
2670                         state = BYTE2;
2671                         break;
2672 
2673                 case BYTE2:
2674                         dest[dest_off++] |= val >> 4;
2675                         dest[dest_off] = (val & 0x0f) << 4;
2676                         state = BYTE3;
2677                         break;
2678 
2679                 case BYTE3:
2680                         dest[dest_off++] |= val >> 2;
2681                         dest[dest_off] = (val & 0x03) << 6;
2682                         state = BYTE4;
2683                         break;
2684 
2685                 case BYTE4:
2686                         dest[dest_off++] |= val;
2687                         state = BYTE1;
2688                         break;
2689                 }
2690         }
2691 
2692         /*
2693          * We are done decoding Base-64 chars.  Let's see if we ended
2694          * on a byte boundary, and/or with erroneous trailing characters.
2695          */
2696 
2697         if (ch == '=') {                        /* We got a pad char. */
2698                 if (src_off >= src_len)
2699                         return *errp = "Invalid padding", false;
2700 
2701                 src_off++;      /* Skip it, get next. */
2702 
2703                 switch (state) {
2704                 case BYTE1:             /* Invalid = in first position */
2705                 case BYTE2:             /* Invalid = in second position */
2706                         return false;
2707 
2708                 case BYTE3:             /* Valid, means one byte of info */
2709                         ch = 0;
2710 
2711                         while (src_off < src_len) {
2712                                 ch = (unsigned char)src[src_off];
2713 
2714                                 if (!isspace(ch))
2715                                         break;
2716                         }
2717 
2718                         /* Make sure there is another trailing = sign. */
2719                         if (ch != '=')
2720                                 return *errp = "Invalid padding", false;
2721 
2722                         src_off++; /* Skip the = */
2723 
2724                         /* Fall through to "single trailing =" case. */
2725                         /* FALLTHROUGH */
2726 
2727                 case BYTE4:             /* Valid, means two bytes of info */
2728                         /*
2729                          * We know this char is an =.  Is there anything but
2730                          * whitespace after it?
2731                          */
2732                         while (src_off < src_len)
2733                                 if (!isspace(src[src_off]))
2734                                         return *errp = "Trailing data", false;
2735 
2736                         /*
2737                          * Now make sure for cases BYTE3 and BYTE4 that the "extra"
2738                          * bits that slopped past the last full byte were
2739                          * zeros.  If we don't check them, they become a
2740                          * subliminal channel.
2741                          */
2742                         if (dest_off < *dest_len && dest[dest_off] != 0)
2743                                 return *errp = "Extraneous bits", false;
2744                 }
2745         }
2746         else {
2747                 /*
2748                  * We ended by seeing the end of the string.  Make sure we
2749                  * have no partial bytes lying around.
2750                  */
2751                 if (state != BYTE1 && *dest_len == SIZE_MAX)
2752                         return *errp = "Input string too long", false;
2753         }
2754 
2755         return *dest_len = dest_off, *errp = NULL, true;
2756 }
2757 
2758 static const char Base64[] =
2759         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2760 
2761 static size_t
2762 b64len(const char *src, size_t src_len)
2763 {
2764         size_t padding_len = 0;
2765         size_t total_len = 0;
2766         size_t i = 0;
2767 
2768         for (; i < src_len; i++) {
2769                 if (isspace(src[i]))
2770                         continue;
2771 
2772                 if ((src[i] >= 'A' && src[i] <= 'Z') ||
2773                     (src[i] >= 'a' && src[i] <= 'z') ||
2774                     (src[i] >= '' && src[i] <= '9') ||
2775                     (src[i] == '+') || (src[i] == '/'))
2776                         total_len++;
2777                 else
2778                         break;
2779         }
2780 
2781         for (; i < src_len; i++) {
2782                 if (isspace(src[i]))
2783                         continue;
2784 
2785                 if (src[i] == '=')
2786                         total_len++, padding_len++;
2787                 else
2788                         return 0;
2789         }
2790 
2791         if ((total_len % 4) != 0 || total_len < 4 || padding_len > 2)
2792                 return 0;
2793 
2794         return (total_len / 4) * 3 - padding_len;
2795 }
2796 
2797 static uc_value_t *
2798 b64enc(const char *src, size_t src_len)
2799 {
2800         unsigned char input[3] = {0};
2801         uc_stringbuf_t *buf;
2802         char output[4];
2803         size_t i;
2804 
2805         buf = ucv_stringbuf_new();
2806 
2807         while (2 < src_len) {
2808                 input[0] = (unsigned char)*src++;
2809                 input[1] = (unsigned char)*src++;
2810                 input[2] = (unsigned char)*src++;
2811                 src_len -= 3;
2812 
2813                 output[0] = Base64[input[0] >> 2];
2814                 output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
2815                 output[2] = Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
2816                 output[3] = Base64[input[2] & 0x3f];
2817 
2818                 ucv_stringbuf_addstr(buf, output, sizeof(output));
2819         }
2820 
2821         /* Now we worry about padding. */
2822         if (0 != src_len) {
2823                 /* Get what's left. */
2824                 input[0] = input[1] = input[2] = '\0';
2825                 for (i = 0; i < src_len; i++)
2826                         input[i] = *src++;
2827 
2828                 output[0] = Base64[input[0] >> 2];
2829                 output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
2830                 output[2] = (src_len == 1) ? '=' : Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
2831                 output[3] = '=';
2832 
2833                 ucv_stringbuf_addstr(buf, output, sizeof(output));
2834         }
2835 
2836         return ucv_stringbuf_finish(buf);
2837 }
2838 
2839 static bool
2840 uc_pack_common(uc_vm_t *vm, size_t nargs, formatstate_t *state, size_t argoff,
2841                void **buf, size_t *pos, size_t *capacity)
2842 {
2843         size_t ncode, arg, off, new_pos;
2844         formatcode_t *code;
2845         ssize_t size, n;
2846         const void *p;
2847 
2848         for (ncode = 0, code = &state->codes[0], arg = argoff, off = 0;
2849              ncode < state->ncodes;
2850              code = &state->codes[++ncode]) {
2851                 if (code->fmtdef->format == '*') {
2852                         uc_value_t *v = uc_fn_arg(arg++);
2853 
2854                         if (ucv_type(v) != UC_STRING)
2855                                 continue;
2856 
2857                         n = ucv_string_length(v);
2858 
2859                         if (code->size == -1 || code->size > n)
2860                                 off += n;
2861                         else
2862                                 off += code->size;
2863                 }
2864                 else if (code->fmtdef->format == 'X') {
2865                         uc_value_t *v = uc_fn_arg(arg++);
2866 
2867                         if (ucv_type(v) != UC_STRING)
2868                                 continue;
2869 
2870                         n = ucv_string_length(v) / 2;
2871 
2872                         if (code->size == -1 || code->size > n)
2873                                 off += n;
2874                         else
2875                                 off += code->size;
2876                 }
2877                 else if (code->fmtdef->format == 'Z') {
2878                         uc_value_t *v = uc_fn_arg(arg++);
2879 
2880                         if (ucv_type(v) != UC_STRING)
2881                                 continue;
2882 
2883                         n = b64len(ucv_string_get(v), ucv_string_length(v));
2884 
2885                         if (code->size == -1 || code->size > n)
2886                                 off += n;
2887                         else
2888                                 off += code->size;
2889                 }
2890                 else {
2891                         arg += code->repeat;
2892                 }
2893         }
2894 
2895         new_pos = *pos + state->size + off;
2896 
2897         if (!grow_buffer(vm, buf, capacity, new_pos))
2898                 return NULL;
2899 
2900         for (ncode = 0, code = &state->codes[0], off = 0;
2901              ncode < state->ncodes;
2902              code = &state->codes[++ncode]) {
2903                 const formatdef_t *e = code->fmtdef;
2904                 char *res = *buf + sizeof(uc_string_t) + *pos + code->offset + off;
2905                 ssize_t j = code->repeat;
2906 
2907                 while (j--) {
2908                         uc_value_t *v = uc_fn_arg(argoff++);
2909 
2910                         size = code->size;
2911 
2912                         if (e->format == '*') {
2913                                 if (ucv_type(v) != UC_STRING) {
2914                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2915                                                 "Argument for '*' must be a string");
2916 
2917                                         return false;
2918                                 }
2919 
2920                                 n = ucv_string_length(v);
2921                                 p = ucv_string_get(v);
2922 
2923                                 if (size == -1 || n < size)
2924                                         size = n;
2925                                 else if (n > size)
2926                                         n = size;
2927 
2928                                 off += size;
2929 
2930                                 if (n > 0)
2931                                         memcpy(res, p, n);
2932                         }
2933                         else if (e->format == 's') {
2934                                 if (ucv_type(v) != UC_STRING) {
2935                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2936                                                 "Argument for 's' must be a string");
2937 
2938                                         return false;
2939                                 }
2940 
2941                                 n = ucv_string_length(v);
2942                                 p = ucv_string_get(v);
2943 
2944                                 if (n > size)
2945                                         n = size;
2946 
2947                                 if (n > 0)
2948                                         memcpy(res, p, n);
2949                         }
2950                         else if (e->format == 'p') {
2951                                 if (ucv_type(v) != UC_STRING) {
2952                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2953                                                 "Argument for 'p' must be a string");
2954 
2955                                         return false;
2956                                 }
2957 
2958                                 n = ucv_string_length(v);
2959                                 p = ucv_string_get(v);
2960 
2961                                 if (n > (size - 1))
2962                                         n = size - 1;
2963 
2964                                 if (n > 0)
2965                                         memcpy(res + 1, p, n);
2966 
2967                                 if (n > 255)
2968                                         n = 255;
2969 
2970                                 *res = (unsigned char)n;
2971                         }
2972                         else if (e->format == 'X') {
2973                                 if (ucv_type(v) != UC_STRING) {
2974                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2975                                                 "Argument for 'X' must be a string");
2976 
2977                                         return false;
2978                                 }
2979 
2980                                 n = ucv_string_length(v);
2981                                 p = ucv_string_get(v);
2982 
2983                                 if (n % 2) {
2984                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
2985                                                 "String length must be multiple of 2");
2986 
2987                                         return false;
2988                                 }
2989 
2990                                 if (size == -1 || n / 2 < size)
2991                                         size = n / 2;
2992                                 else if (n > size * 2)
2993                                         n = size * 2;
2994 
2995                                 for (ssize_t i = 0; i < n; i += 2) {
2996                                         uint8_t c1 = ((uint8_t *)p)[i + 0];
2997                                         uint8_t c2 = ((uint8_t *)p)[i + 1];
2998 
2999                                         if (!isxdigit(c1) || !isxdigit(c2)) {
3000                                                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
3001                                                         "Invalid hexadecimal string");
3002 
3003                                                 return false;
3004                                         }
3005 
3006                                         c1 |= 32; c1 = (c1 >= 'a') ? 10 + c1 - 'a' : c1 - '';
3007                                         c2 |= 32; c2 = (c2 >= 'a') ? 10 + c2 - 'a' : c2 - '';
3008 
3009                                         ((uint8_t *)res)[i >> 1] = (c1 << 4) | c2;
3010                                 }
3011                         }
3012                         else if (e->format == 'Z') {
3013                                 if (ucv_type(v) != UC_STRING) {
3014                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
3015                                                 "Argument for 'Z' must be a string");
3016 
3017                                         return false;
3018                                 }
3019 
3020                                 n = ucv_string_length(v);
3021                                 p = ucv_string_get(v);
3022 
3023                                 size_t len = (size == -1) ? SIZE_MAX : (size_t)size;
3024                                 const char *err = NULL;
3025 
3026                                 if (!b64dec(res, &len, p, n, &err)) {
3027                                         uc_vm_raise_exception(vm, EXCEPTION_TYPE,
3028                                                 "Invalid base64 string: %s", err);
3029 
3030                                         return false;
3031                                 }
3032 
3033                                 if (size == -1 || len < (size_t)size)
3034                                         size = len;
3035                         }
3036                         else {
3037                                 if (!e->pack(vm, res, v, e))
3038                                         return false;
3039                         }
3040 
3041                         res += size;
3042                 }
3043         }
3044 
3045         *pos = new_pos;
3046 
3047         return true;
3048 }
3049 
3050 static uc_value_t *
3051 hexenc(const char *src, size_t src_len)
3052 {
3053         uc_string_t *us = xalloc(sizeof(*us) + src_len * 2 + 1);
3054         const char *hexdigits = "0123456789abcdef";
3055 
3056         us->header.type = UC_STRING;
3057         us->header.refcount = 1;
3058         us->length = src_len * 2;
3059 
3060         for (size_t i = 0; i < src_len; i++) {
3061                 uint8_t c = (uint8_t)src[i];
3062 
3063                 us->str[(i << 1) + 0] = hexdigits[c >> 4];
3064                 us->str[(i << 1) + 1] = hexdigits[c & 0x0f];
3065         }
3066 
3067         return &us->header;
3068 }
3069 
3070 static uc_value_t *
3071 uc_unpack_common(uc_vm_t *vm, size_t nargs, formatstate_t *state,
3072                  const char *buf, long long pos, size_t *rem, bool single)
3073 {
3074         uc_value_t *result;
3075         formatcode_t *code;
3076         size_t ncode, off;
3077         ssize_t size, n;
3078 
3079         if (pos < 0)
3080                 pos += *rem;
3081 
3082         if (pos < 0 || (size_t)pos >= *rem)
3083                 return NULL;
3084 
3085         buf += pos;
3086         *rem -= pos;
3087 
3088         result = single ? NULL : ucv_array_new(vm);
3089 
3090         for (ncode = 0, code = &state->codes[0], off = 0;
3091              ncode < state->ncodes;
3092              code = &state->codes[++ncode]) {
3093                 const formatdef_t *e = code->fmtdef;
3094                 const char *res = buf + code->offset + off;
3095                 ssize_t j = code->repeat;
3096 
3097                 while (j--) {
3098                         uc_value_t *v = NULL;
3099 
3100                         size = code->size;
3101 
3102                         if (e->format == '*' || e->format == 'X' || e->format == 'Z') {
3103                                 if (size == -1 || (size_t)size > *rem)
3104                                         size = *rem;
3105 
3106                                 off += size;
3107                         }
3108                         else if (size >= 0 && (size_t)size > *rem) {
3109                                 goto fail;
3110                         }
3111 
3112                         if (e->format == 's' || e->format == '*') {
3113                                 v = ucv_string_new_length(res, size);
3114                         }
3115                         else if (e->format == 'p') {
3116                                 n = *(unsigned char *)res;
3117 
3118                                 if (n >= size)
3119                                         n = (size > 0 ? size - 1 : 0);
3120 
3121                                 v = ucv_string_new_length(res + 1, n);
3122                         }
3123                         else if (e->format == 'X') {
3124                                 v = hexenc(res, size);
3125                         }
3126                         else if (e->format == 'Z') {
3127                                 v = b64enc(res, size);
3128                         }
3129                         else {
3130                                 v = e->unpack(vm, res, e);
3131                         }
3132 
3133                         if (v == NULL)
3134                                 goto fail;
3135 
3136                         res += size;
3137                         *rem -= size;
3138 
3139                         if (single)
3140                                 return v;
3141 
3142                         ucv_array_push(result, v);
3143                 }
3144         }
3145 
3146         return result;
3147 
3148 fail:
3149         ucv_put(result);
3150 
3151         return NULL;
3152 }
3153 
3154 
3155 /**
3156  * Pack given values according to specified format.
3157  *
3158  * The `pack()` function creates a byte string containing the argument values
3159  * packed according to the given format string.
3160  *
3161  * Returns the packed string.
3162  *
3163  * Raises a runtime exception if a given argument value does not match the
3164  * required type of the corresponding format string directive or if and invalid
3165  * format string is provided.
3166  *
3167  * @function module:struct#pack
3168  *
3169  * @param {string} format
3170  * The format string.
3171  *
3172  * @param {...*} values
3173  * Variable number of values to pack.
3174  *
3175  * @returns {string}
3176  *
3177  * @example
3178  * // Pack the values 1, 2, 3 as three consecutive unsigned int values
3179  * // in network byte order.
3180  * const data = pack('!III', 1, 2, 3);
3181  */
3182 static uc_value_t *
3183 uc_pack(uc_vm_t *vm, size_t nargs)
3184 {
3185         uc_value_t *fmtval = uc_fn_arg(0);
3186         size_t pos = 0, capacity = 0;
3187         uc_string_t *us = NULL;
3188         formatstate_t *state;
3189 
3190         state = parse_format(vm, fmtval);
3191 
3192         if (!state)
3193                 return NULL;
3194 
3195         if (!uc_pack_common(vm, nargs, state, 1, (void **)&us, &pos, &capacity)) {
3196                 free(state);
3197                 free(us);
3198 
3199                 return NULL;
3200         }
3201 
3202         free(state);
3203 
3204         us->header.type = UC_STRING;
3205         us->header.refcount = 1;
3206         us->length = pos;
3207 
3208         return &us->header;
3209 }
3210 
3211 /**
3212  * Unpack given byte string according to specified format.
3213  *
3214  * The `unpack()` function interpretes a byte string according to the given
3215  * format string and returns the resulting values. If the optional offset
3216  * argument is given, unpacking starts from this byte position within the input.
3217  * If not specified, the start offset defaults to `0`, the start of the given
3218  * input string.
3219  *
3220  * Returns an array of unpacked values.
3221  *
3222  * Raises a runtime exception if the format string is invalid or if an invalid
3223  * input string or offset value is given.
3224  *
3225  * @function module:struct#unpack
3226  *
3227  * @param {string} format
3228  * The format string.
3229  *
3230  * @param {string} input
3231  * The input string to unpack.
3232  *
3233  * @param {number} [offset=0]
3234  * The offset within the input string to start unpacking from.
3235  *
3236  * @returns {array}
3237  *
3238  * @example
3239  * // Unpack three consecutive unsigned int values in network byte order.
3240  * const numbers =
3241  *   unpack('!III', '\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03');
3242  * print(numbers, "\n"); // [ 1, 2, 3 ]
3243  */
3244 static uc_value_t *
3245 uc_unpack(uc_vm_t *vm, size_t nargs)
3246 {
3247         uc_value_t *fmtval = uc_fn_arg(0);
3248         uc_value_t *bufval = uc_fn_arg(1);
3249         uc_value_t *offset = uc_fn_arg(2);
3250         uc_value_t *res = NULL;
3251         formatstate_t *state;
3252         long long pos = 0;
3253         size_t rem;
3254         char *buf;
3255 
3256         if (ucv_type(bufval) != UC_STRING) {
3257                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
3258                         "Buffer value not a string");
3259 
3260                 return NULL;
3261         }
3262 
3263         if (offset && !ucv_as_longlong(vm, offset, &pos))
3264                 return NULL;
3265 
3266         state = parse_format(vm, fmtval);
3267 
3268         if (!state)
3269                 return NULL;
3270 
3271         buf = ucv_string_get(bufval);
3272         rem = ucv_string_length(bufval);
3273         res = uc_unpack_common(vm, nargs, state, buf, pos, &rem, false);
3274 
3275         free(state);
3276 
3277         return res;
3278 }
3279 
3280 
3281 /**
3282  * Represents a struct instance created by `new()`.
3283  *
3284  * @class module:struct.instance
3285  * @hideconstructor
3286  *
3287  * @see {@link module:struct#new|new()}
3288  *
3289  * @example
3290  *
3291  * const fmt = struct.new(…);
3292  *
3293  * fmt.pack(…);
3294  *
3295  * const values = fmt.unpack(…);
3296  */
3297 
3298 /**
3299  * Precompile format string.
3300  *
3301  * The `new()` function precompiles the given format string argument and returns
3302  * a `struct` object instance useful for packing and unpacking multiple items
3303  * without having to recompute the internal format each time.
3304  *
3305  * Returns an precompiled struct format instance.
3306  *
3307  * Raises a runtime exception if the format string is invalid.
3308  *
3309  * @function module:struct#new
3310  *
3311  * @param {string} format
3312  * The format string.
3313  *
3314  * @returns {module:struct.instance}
3315  *
3316  * @example
3317  * // Create a format of three consecutive unsigned int values in network byte order.
3318  * const fmt = struct.new('!III');
3319  * const buf = fmt.pack(1, 2, 3);  // "\x00\x00\x00\x01…"
3320  * print(fmt.unpack(buf), "\n");   // [ 1, 2, 3 ]
3321  */
3322 static uc_value_t *
3323 uc_struct_new(uc_vm_t *vm, size_t nargs)
3324 {
3325         uc_value_t *fmtval = uc_fn_arg(0);
3326         formatstate_t *state;
3327 
3328         state = parse_format(vm, fmtval);
3329 
3330         if (!state)
3331                 return NULL;
3332 
3333         return ucv_resource_create(vm, "struct.format", state);
3334 }
3335 
3336 /**
3337  * Pack given values.
3338  *
3339  * The `pack()` function creates a byte string containing the argument values
3340  * packed according to the given format instance.
3341  *
3342  * Returns the packed string.
3343  *
3344  * Raises a runtime exception if a given argument value does not match the
3345  * required type of the corresponding format string directive.
3346  *
3347  * @function module:struct.instance#pack
3348  *
3349  * @param {...*} values
3350  * Variable number of values to pack.
3351  *
3352  * @returns {string}
3353  *
3354  * @example
3355  * const fmt = struct.new(…);
3356  * const data = fmt.pack(…);
3357  */
3358 static uc_value_t *
3359 uc_struct_pack(uc_vm_t *vm, size_t nargs)
3360 {
3361         formatstate_t **state = uc_fn_this("struct.format");
3362         size_t pos = 0, capacity = 0;
3363         uc_string_t *us = NULL;
3364 
3365         if (!state || !*state)
3366                 return NULL;
3367 
3368         if (!uc_pack_common(vm, nargs, *state, 0, (void **)&us, &pos, &capacity)) {
3369                 free(us);
3370 
3371                 return NULL;
3372         }
3373 
3374         us->header.type = UC_STRING;
3375         us->header.refcount = 1;
3376         us->length = pos;
3377 
3378         return &us->header;
3379 }
3380 
3381 /**
3382  * Unpack given byte string.
3383  *
3384  * The `unpack()` function interpretes a byte string according to the given
3385  * format instance and returns the resulting values. If the optional offset
3386  * argument is given, unpacking starts from this byte position within the input.
3387  * If not specified, the start offset defaults to `0`, the start of the given
3388  * input string.
3389  *
3390  * Returns an array of unpacked values.
3391  *
3392  * Raises a runtime exception if an invalid input string or offset value is
3393  * given.
3394  *
3395  * @function module:struct.instance#unpack
3396  *
3397  * @param {string} input
3398  * The input string to unpack.
3399  *
3400  * @param {number} [offset=0]
3401  * The offset within the input string to start unpacking from.
3402  *
3403  * @returns {array}
3404  *
3405  * @example
3406  * const fmt = struct.new(…);
3407  * const values = fmt.unpack(…);
3408  */
3409 static uc_value_t *
3410 uc_struct_unpack(uc_vm_t *vm, size_t nargs)
3411 {
3412         formatstate_t **state = uc_fn_this("struct.format");
3413         uc_value_t *bufval = uc_fn_arg(0);
3414         uc_value_t *offset = uc_fn_arg(1);
3415         long long pos = 0;
3416         size_t rem;
3417         char *buf;
3418 
3419         if (!state || !*state)
3420                 return NULL;
3421 
3422         if (ucv_type(bufval) != UC_STRING) {
3423                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
3424                         "Buffer value not a string");
3425 
3426                 return NULL;
3427         }
3428 
3429         if (offset && !ucv_as_longlong(vm, offset, &pos))
3430                 return NULL;
3431 
3432         buf = ucv_string_get(bufval);
3433         rem = ucv_string_length(bufval);
3434 
3435         return uc_unpack_common(vm, nargs, *state, buf, pos, &rem, false);
3436 }
3437 
3438 
3439 /**
3440  * Represents a struct buffer instance created by `buffer()`.
3441  *
3442  * @class module:struct.buffer
3443  * @hideconstructor
3444  *
3445  * @see {@link module:struct#buffer|buffer()}
3446  *
3447  * @example
3448  *
3449  * const buf = struct.buffer();
3450  *
3451  * buf.put('I', 12345);
3452  *
3453  * const value = buf.get('I');
3454  */
3455 
3456 /**
3457  * Creates a new struct buffer instance.
3458  *
3459  * The `buffer()` function creates a new struct buffer object that can be used
3460  * for incremental packing and unpacking of binary data. If an initial data
3461  * string is provided, the buffer is initialized with this content.
3462  *
3463  * Note that even when initial data is provided, the buffer position is always
3464  * set to zero. This design assumes that the primary intent when initializing
3465  * a buffer with data is to read (unpack) from the beginning. If you want to
3466  * append data to a pre-initialized buffer, you need to explicitly move the
3467  * position to the end, either by calling `end()` or by setting the position
3468  * manually with `pos()`.
3469  *
3470  * Returns a new struct buffer instance.
3471  *
3472  * @function module:struct#buffer
3473  *
3474  * @param {string} [initialData]
3475  * Optional initial data to populate the buffer with.
3476  *
3477  * @returns {module:struct.buffer}
3478  *
3479  * @example
3480  * // Create an empty buffer
3481  * const emptyBuf = struct.buffer();
3482  *
3483  * // Create a buffer with initial data
3484  * const dataBuf = struct.buffer("\x01\x02\x03\x04");
3485  *
3486  * // Read from the beginning of the initialized buffer
3487  * const value = dataBuf.get('I');
3488  *
3489  * // Append data to the initialized buffer
3490  * dataBuf.end().put('I', 5678);
3491  *
3492  * // Alternative chained syntax for initializing and appending
3493  * const buf = struct.buffer("\x01\x02\x03\x04").end().put('I', 5678);
3494  */
3495 static uc_value_t *
3496 uc_fmtbuf_new(uc_vm_t *vm, size_t nargs)
3497 {
3498         formatbuffer_t *buffer = xalloc(sizeof(*buffer));
3499         uc_value_t *init_data = uc_fn_arg(0);
3500 
3501         buffer->resource.header.type = UC_RESOURCE;
3502         buffer->resource.header.refcount = 1;
3503         buffer->resource.type = ucv_resource_type_lookup(vm, "struct.buffer");
3504 
3505         if (ucv_type(init_data) == UC_STRING)  {
3506                 char *buf = ucv_string_get(init_data);
3507                 size_t len = ucv_string_length(init_data);
3508 
3509                 if (!grow_buffer(vm, &buffer->resource.data, &buffer->capacity, len)) {
3510                         free(buffer);
3511 
3512                         return NULL;
3513                 }
3514 
3515                 buffer->length = len;
3516                 memcpy((char *)buffer->resource.data + sizeof(uc_string_t), buf, len);
3517         }
3518 
3519         return &buffer->resource.header;
3520 }
3521 
3522 static formatbuffer_t *
3523 formatbuffer_ctx(uc_vm_t *vm)
3524 {
3525         uc_value_t *ctx = vm->callframes.entries[vm->callframes.count - 1].ctx;
3526 
3527         if (ucv_type(ctx) != UC_RESOURCE)
3528                 return NULL;
3529 
3530         uc_resource_t *res = (uc_resource_t *)ctx;
3531 
3532         if (!res->type || strcmp(res->type->name, "struct.buffer") != 0)
3533                 return NULL;
3534 
3535         return (formatbuffer_t *)res;
3536 }
3537 
3538 /**
3539  * Get or set the current position in the buffer.
3540  *
3541  * If called without arguments, returns the current position.
3542  * If called with a position argument, sets the current position to that value.
3543  *
3544  * @function module:struct.buffer#pos
3545  *
3546  * @param {number} [position]
3547  * The position to set. If omitted, the current position is returned.
3548  *
3549  * @returns {number|module:struct.buffer}
3550  * If called without arguments, returns the current position.
3551  * If called with a position argument, returns the buffer instance for chaining.
3552  *
3553  * @example
3554  * const currentPos = buf.pos();
3555  * buf.pos(10);  // Set position to 10
3556  */
3557 static uc_value_t *
3558 uc_fmtbuf_pos(uc_vm_t *vm, size_t nargs)
3559 {
3560         formatbuffer_t *buffer = formatbuffer_ctx(vm);
3561         uc_value_t *new_pos = uc_fn_arg(0);
3562 
3563         if (!buffer)
3564                 return NULL;
3565 
3566         if (new_pos) {
3567                 long long pos;
3568 
3569                 if (!ucv_as_longlong(vm, new_pos, &pos))
3570                         return NULL;
3571 
3572                 if (pos < 0) pos += buffer->length;
3573                 if (pos < 0) pos = 0;
3574 
3575                 if (!grow_buffer(vm, &buffer->resource.data, &buffer->capacity, pos))
3576                         return NULL;
3577 
3578                 buffer->position = pos;
3579 
3580                 if (buffer->position > buffer->length)
3581                         buffer->length = buffer->position;
3582 
3583                 return ucv_get(&buffer->resource.header);
3584         }
3585 
3586         return ucv_uint64_new(buffer->position);
3587 }
3588 
3589 /**
3590  * Get or set the current buffer length.
3591  *
3592  * If called without arguments, returns the current length of the buffer.
3593  * If called with a length argument, sets the buffer length to that value,
3594  * padding the data with trailing zero bytes or truncating it depending on
3595  * whether the updated length is larger or smaller than the current length
3596  * respectively.
3597  *
3598  * In case the updated length is smaller than the current buffer offset, the
3599  * position is updated accordingly, so that it points to the new end of the
3600  * truncated buffer data.
3601  *
3602  * @function module:struct.buffer#length
3603  *
3604  * @param {number} [length]
3605  * The length to set. If omitted, the current length is returned.
3606  *
3607  * @returns {number|module:struct.buffer}
3608  * If called without arguments, returns the current length.
3609  * If called with a length argument, returns the buffer instance for chaining.
3610  *
3611  * @example
3612  * const buf = struct.buffer("abc"); // Initialize buffer with three bytes
3613  * const currentLen = buf.length();  // Returns 3
3614  *
3615  * buf.length(6);                    // Extend to 6 bytes
3616  * buf.slice();                      // Trailing null bytes: "abc\x00\x00\x00"
3617  *
3618  * buf.length(2);                    // Truncate to 2 bytes
3619  * buf.slice();                      // Truncated data: "ab"
3620  */
3621 static uc_value_t *
3622 uc_fmtbuf_length(uc_vm_t *vm, size_t nargs)
3623 {
3624         formatbuffer_t *buffer = formatbuffer_ctx(vm);
3625         uc_value_t *new_len = uc_fn_arg(0);
3626 
3627         if (!buffer)
3628                 return NULL;
3629 
3630         if (new_len) {
3631                 size_t len;
3632 
3633                 if (!ucv_as_size_t(vm, new_len, &len))
3634                         return NULL;
3635 
3636                 if (len > buffer->length) {
3637                         if (!grow_buffer(vm, &buffer->resource.data, &buffer->capacity, len))
3638                                 return NULL;
3639 
3640                         buffer->length = len;
3641                 }
3642                 else if (len < buffer->length) {
3643                         memset((char *)buffer->resource.data + sizeof(uc_string_t) + len,
3644                                 0, buffer->length - len);
3645 
3646                         buffer->length = len;
3647 
3648                         if (len < buffer->position)
3649                                 buffer->position = len;
3650                 }
3651 
3652                 return ucv_get(&buffer->resource.header);
3653         }
3654 
3655         return ucv_uint64_new(buffer->length);
3656 }
3657 
3658 /**
3659  * Set the buffer position to the start (0).
3660  *
3661  * @function module:struct.buffer#start
3662  *
3663  * @returns {module:struct.buffer}
3664  * The buffer instance.
3665  *
3666  * @example
3667  * buf.start();
3668  */
3669 static uc_value_t *
3670 uc_fmtbuf_start(uc_vm_t *vm, size_t nargs)
3671 {
3672         formatbuffer_t *buffer = formatbuffer_ctx(vm);
3673 
3674         if (!buffer)
3675                 return NULL;
3676 
3677         buffer->position = 0;
3678 
3679         return ucv_get(&buffer->resource.header);
3680 }
3681 
3682 /**
3683  * Set the buffer position to the end.
3684  *
3685  * @function module:struct.buffer#end
3686  *
3687  * @returns {module:struct.buffer}
3688  * The buffer instance.
3689  *
3690  * @example
3691  * buf.end();
3692  */
3693 static uc_value_t *
3694 uc_fmtbuf_end(uc_vm_t *vm, size_t nargs)
3695 {
3696         formatbuffer_t *buffer = formatbuffer_ctx(vm);
3697 
3698         if (!buffer)
3699                 return NULL;
3700 
3701         buffer->position = buffer->length;
3702 
3703         return ucv_get(&buffer->resource.header);
3704 }
3705 
3706 /**
3707  * Pack data into the buffer at the current position.
3708  *
3709  * The `put()` function packs the given values into the buffer according to
3710  * the specified format string, starting at the current buffer position.
3711  * The format string follows the same syntax as used in `struct.pack()`.
3712  *
3713  * For a detailed explanation of the format string syntax, refer to the
3714  * ["Format Strings" section]{@link module:struct} in the module
3715  * documentation.
3716  *
3717  * @function module:struct.buffer#put
3718  *
3719  * @param {string} format
3720  * The format string specifying how to pack the data.
3721  *
3722  * @param {...*} values
3723  * The values to pack into the buffer.
3724  *
3725  * @returns {module:struct.buffer}
3726  * The buffer instance.
3727  *
3728  * @see {@link module:struct#pack|struct.pack()}
3729  *
3730  * @example
3731  * buf.put('II', 1234, 5678);
3732  */
3733 static uc_value_t *
3734 uc_fmtbuf_put(uc_vm_t *vm, size_t nargs)
3735 {
3736         formatbuffer_t *buffer = formatbuffer_ctx(vm);
3737         uc_value_t *fmt = uc_fn_arg(0);
3738         formatstate_t *state;
3739         bool res;
3740 
3741         if (!buffer)
3742                 return NULL;
3743 
3744         state = parse_format(vm, fmt);
3745 
3746         if (!state)
3747                 return NULL;
3748 
3749         res = uc_pack_common(vm, nargs, state, 1,
3750                 &buffer->resource.data, &buffer->position, &buffer->capacity);
3751 
3752         free(state);
3753 
3754         if (!res)
3755                 return NULL;
3756 
3757         if (buffer->position > buffer->length)
3758                 buffer->length = buffer->position;
3759 
3760         return ucv_get(&buffer->resource.header);
3761 }
3762 
3763 static uc_value_t *
3764 fmtbuf_get_common(uc_vm_t *vm, size_t nargs, bool single)
3765 {
3766         formatbuffer_t *buffer = formatbuffer_ctx(vm);
3767         uc_value_t *fmt = uc_fn_arg(0);
3768         formatstate_t *state;
3769         uc_value_t *result;
3770         size_t rem;
3771         char *buf;
3772 
3773         if (!buffer)
3774                 return NULL;
3775 
3776         if (single && ucv_type(fmt) == UC_INTEGER) {
3777                 int64_t len = ucv_int64_get(fmt);
3778 
3779                 if (errno != 0)
3780                         goto ebounds;
3781 
3782                 size_t spos, epos;
3783 
3784                 if (len < 0) {
3785                         if (len == INT64_MIN)
3786                                 goto ebounds;
3787 
3788                         if ((uint64_t)-len > buffer->position)
3789                                 return NULL;
3790 
3791                         spos = buffer->position + len;
3792                         epos = buffer->position;
3793                 }
3794                 else {
3795                         if ((uint64_t)len > (SIZE_MAX - buffer->position))
3796                                 goto ebounds;
3797 
3798                         if (buffer->position + len > buffer->length)
3799                                 return NULL;
3800 
3801                         spos = buffer->position;
3802                         epos = buffer->position + len;
3803 
3804                         buffer->position = epos;
3805                 }
3806 
3807                 return ucv_string_new_length(
3808                         (char *)buffer->resource.data + sizeof(uc_string_t) + spos,
3809                         epos - spos);
3810 
3811 ebounds:
3812                 uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
3813                         "Length value out of bounds");
3814 
3815                 return NULL;
3816         }
3817 
3818         state = parse_format(vm, fmt);
3819 
3820         if (!state)
3821                 return NULL;
3822 
3823         if (single && (state->ncodes != 1 || state->codes[0].repeat != 1)) {
3824                 free(state);
3825                 uc_vm_raise_exception(vm, EXCEPTION_TYPE,
3826                         "get() expects a format string for a single value. "
3827                         "Use read() for multiple values.");
3828 
3829                 return NULL;
3830         }
3831 
3832         rem = buffer->length;
3833         buf = (char *)buffer->resource.data + sizeof(uc_string_t);
3834 
3835         result = uc_unpack_common(vm, nargs, state,
3836                 buf, buffer->position, &rem, single);
3837 
3838         if (result)
3839                 buffer->position = buffer->length - rem;
3840 
3841         free(state);
3842 
3843         return result;
3844 }
3845 
3846 /**
3847  * Unpack a single value from the buffer at the current position.
3848  *
3849  * The `get()` function unpacks a single value from the buffer according to the
3850  * specified format string, starting at the current buffer position.
3851  * The format string follows the same syntax as used in `struct.unpack()`.
3852  *
3853  * For a detailed explanation of the format string syntax, refer to the
3854  * ["Format Strings" section]{@link module:struct} in the module documentation.
3855  *
3856  * Alternatively, `get()` accepts a postive or negative integer as format, which
3857  * specifies the length of a string to unpack before or after the current
3858  * position. Negative values extract that many bytes before the current offset
3859  * while postive ones extracts that many bytes after.
3860  *
3861  * @function module:struct.buffer#get
3862  *
3863  * @param {string|number} format
3864  * The format string specifying how to unpack the data.
3865  *
3866  * @returns {*}
3867  * The unpacked value.
3868  *
3869  * @see {@link module:struct#unpack|struct.unpack()}
3870  *
3871  * @example
3872  * const val = buf.get('I');
3873  * const str = buf.get(5);    // equivalent to buf.get('5s')
3874  * const str = buf.get(-3);   // equivalent to buf.pos(buf.pos() - 3).get('3s')
3875  */
3876 static uc_value_t *
3877 uc_fmtbuf_get(uc_vm_t *vm, size_t nargs)
3878 {
3879         return fmtbuf_get_common(vm, nargs, true);
3880 }
3881 
3882 /**
3883  * Unpack multiple values from the buffer at the current position.
3884  *
3885  * The `read()` function unpacks multiple values from the buffer according to
3886  * the specified format string, starting at the current buffer position.
3887  * The format string follows the same syntax as used in `struct.unpack()`.
3888  *
3889  * For a detailed explanation of the format string syntax, refer to the
3890  * ["Format Strings" section]{@link module:struct} in the module documentation.
3891  *
3892  * @function module:struct.buffer#get
3893  *
3894  * @param {string} format
3895  * The format string specifying how to unpack the data.
3896  *
3897  * @returns {array}
3898  * An array containing the unpacked values.
3899  *
3900  * @see {@link module:struct#unpack|struct.unpack()}
3901  *
3902  * @example
3903  * const values = buf.get('II');
3904  */
3905 static uc_value_t *
3906 uc_fmtbuf_read(uc_vm_t *vm, size_t nargs)
3907 {
3908         return fmtbuf_get_common(vm, nargs, false);
3909 }
3910 
3911 /**
3912  * Extract a slice of the buffer content.
3913  *
3914  * The `slice()` function returns a substring of the buffer content
3915  * between the specified start and end positions.
3916  *
3917  * Both the start and end position values may be negative, in which case they're
3918  * relative to the end of the buffer, e.g. `slice(-3)` will extract the last
3919  * three bytes of data.
3920  *
3921  * @function module:struct.buffer#slice
3922  *
3923  * @param {number} [start=0]
3924  * The starting position of the slice.
3925  *
3926  * @param {number} [end=buffer.length()]
3927  * The ending position of the slice (exclusive).
3928  *
3929  * @returns {string}
3930  * A string containing the specified slice of the buffer content.
3931  *
3932  * @example
3933  * const slice = buf.slice(4, 8);
3934  */
3935 static uc_value_t *
3936 uc_fmtbuf_slice(uc_vm_t *vm, size_t nargs)
3937 {
3938         formatbuffer_t *buffer = formatbuffer_ctx(vm);
3939         uc_value_t *from = uc_fn_arg(0);
3940         uc_value_t *to = uc_fn_arg(1);
3941         long long spos, epos;
3942         char *buf;
3943 
3944         if (!buffer)
3945                 return NULL;
3946 
3947         spos = 0;
3948         epos = buffer->length;
3949 
3950         if (from && !ucv_as_longlong(vm, from, &spos))
3951                 return NULL;
3952 
3953         if (to && !ucv_as_longlong(vm, to, &epos))
3954                 return NULL;
3955 
3956         if (spos < 0) spos += buffer->length;
3957         if (spos < 0) spos = 0;
3958         if ((unsigned long long)spos > buffer->length) spos = buffer->length;
3959 
3960         if (epos < 0) epos += buffer->length;
3961         if (epos < spos) epos = spos;
3962         if ((unsigned long long)epos > buffer->length) epos = buffer->length;
3963 
3964         buf = (char *)buffer->resource.data + sizeof(uc_string_t) + spos;
3965 
3966         return ucv_string_new_length(buf, epos - spos);
3967 }
3968 
3969 /**
3970  * Set a slice of the buffer content to given byte value.
3971  *
3972  * The `set()` function overwrites a substring of the buffer content with the
3973  * given byte value, similar to the C `memset()` function, between the specified
3974  * start and end positions.
3975  *
3976  * Both the start and end position values may be negative, in which case they're
3977  * relative to the end of the buffer, e.g. `set(0, -2)` will overwrite the last
3978  * two bytes of data with `\x00`.
3979  *
3980  * When the start or end positions are beyond the current buffer length, the
3981  * buffer is grown accordingly.
3982  *
3983  * @function module:struct.buffer#set
3984  *
3985  * @param {number|string} [value=0]
3986  * The byte value to use when overwriting buffer contents. When a string is
3987  * given, the first character is used as value.
3988  *
3989  * @param {number} [start=0]
3990  * The position to start overwriting from.
3991  *
3992  * @param {number} [end=buffer.length()]
3993  * The position to end overwriting (exclusive).
3994  *
3995  * @returns {module:struct.buffer}
3996  * The buffer instance.
3997  *
3998  * @example
3999  * const buf = struct.buffer("abcde");
4000  * buf.set("X", 2, 4).slice();  // Buffer content is now "abXXe"
4001  * buf.set().slice();           // Buffer content is now "\x00\x00\x00\x00\x00"
4002  */
4003 static uc_value_t *
4004 uc_fmtbuf_set(uc_vm_t *vm, size_t nargs)
4005 {
4006         formatbuffer_t *buffer = formatbuffer_ctx(vm);
4007         uc_value_t *byte = uc_fn_arg(0);
4008         uc_value_t *from = uc_fn_arg(1);
4009         uc_value_t *to = uc_fn_arg(2);
4010         long long spos, epos;
4011         long bval;
4012 
4013         if (!buffer)
4014                 return NULL;
4015 
4016         bval = 0;
4017         spos = 0;
4018         epos = buffer->length;
4019 
4020         if (ucv_type(byte) == UC_STRING)
4021                 bval = *ucv_string_get(byte);
4022         else if (byte && !ucv_as_long(vm, byte, &bval))
4023                 return NULL;
4024 
4025         if (from && !ucv_as_longlong(vm, from, &spos))
4026                 return NULL;
4027 
4028         if (to && !ucv_as_longlong(vm, to, &epos))
4029                 return NULL;
4030 
4031         if (spos < 0) spos += buffer->length;
4032         if (spos < 0) spos = 0;
4033 
4034         if (epos < 0) epos += buffer->length;
4035 
4036         if (epos > spos) {
4037                 if ((unsigned long long)epos > buffer->length) {
4038                         if (!grow_buffer(vm, &buffer->resource.data, &buffer->capacity, epos))
4039                                 return NULL;
4040 
4041                         buffer->length = epos;
4042                 }
4043 
4044                 memset((char *)buffer->resource.data + sizeof(uc_string_t) + spos,
4045                         bval, epos - spos);
4046         }
4047 
4048         return ucv_get(&buffer->resource.header);
4049 }
4050 
4051 /**
4052  * Extract and remove all content from the buffer.
4053  *
4054  * The `pull()` function returns all content of the buffer as a string
4055  * and resets the buffer to an empty state.
4056  *
4057  * @function module:struct.buffer#pull
4058  *
4059  * @returns {string}
4060  * A string containing all the buffer content.
4061  *
4062  * @example
4063  * const allData = buf.pull();
4064  */
4065 static uc_value_t *
4066 uc_fmtbuf_pull(uc_vm_t *vm, size_t nargs)
4067 {
4068         formatbuffer_t *buffer = formatbuffer_ctx(vm);
4069         uc_string_t *us;
4070 
4071         if (!buffer)
4072                 return NULL;
4073 
4074         if (!buffer->resource.data)
4075                 return ucv_string_new_length("", 0);
4076 
4077         us = buffer->resource.data;
4078         us->header.type = UC_STRING;
4079         us->header.refcount = 1;
4080         us->length = buffer->length;
4081 
4082         buffer->resource.data = NULL;
4083         buffer->capacity = 0;
4084         buffer->position = 0;
4085         buffer->length = 0;
4086 
4087         return &us->header;
4088 }
4089 
4090 
4091 static const uc_function_list_t struct_inst_fns[] = {
4092         { "pack",       uc_struct_pack },
4093         { "unpack",     uc_struct_unpack }
4094 };
4095 
4096 static const uc_function_list_t buffer_inst_fns[] = {
4097         { "pos",        uc_fmtbuf_pos },
4098         { "length", uc_fmtbuf_length },
4099         { "start",      uc_fmtbuf_start },
4100         { "end",        uc_fmtbuf_end },
4101         { "set",        uc_fmtbuf_set },
4102         { "put",        uc_fmtbuf_put },
4103         { "get",        uc_fmtbuf_get },
4104         { "read",       uc_fmtbuf_read },
4105         { "slice",      uc_fmtbuf_slice },
4106         { "pull",       uc_fmtbuf_pull },
4107 };
4108 
4109 static const uc_function_list_t struct_fns[] = {
4110         { "pack",       uc_pack },
4111         { "unpack",     uc_unpack },
4112         { "new",        uc_struct_new },
4113         { "buffer",     uc_fmtbuf_new }
4114 };
4115 
4116 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
4117 {
4118         optimize_functions();
4119 
4120         uc_function_list_register(scope, struct_fns);
4121 
4122         uc_type_declare(vm, "struct.format", struct_inst_fns, free);
4123         uc_type_declare(vm, "struct.buffer", buffer_inst_fns, free);
4124 }
4125 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt