blob: 1388ca8a3b5210b9b73ce15ce4dbf93daa82c41d (
plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509 | #include "prism/pack.h" // We optionally support parsing String#pack templates. For systems that don't // want or need this functionality, it can be turned off with the // PRISM_EXCLUDE_PACK define. #ifdef PRISM_EXCLUDE_PACK void pm_pack_parse(void) {} #else #include <stdbool.h> #include <errno.h> static uintmax_t strtoumaxc(const char **format) { uintmax_t value = 0; while (**format >= '0' && **format <= '9') { if (value > UINTMAX_MAX / 10) { errno = ERANGE; } value = value * 10 + ((uintmax_t) (**format - '0')); (*format)++; } return value; } PRISM_EXPORTED_FUNCTION pm_pack_result pm_pack_parse( pm_pack_variant variant, const char **format, const char *format_end, pm_pack_type *type, pm_pack_signed *signed_type, pm_pack_endian *endian, pm_pack_size *size, pm_pack_length_type *length_type, uint64_t *length, pm_pack_encoding *encoding ) { if (*encoding == PM_PACK_ENCODING_START) { *encoding = PM_PACK_ENCODING_US_ASCII; } if (*format == format_end) { *type = PM_PACK_END; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; *length_type = PM_PACK_LENGTH_NA; return PM_PACK_OK; } *length_type = PM_PACK_LENGTH_FIXED; *length = 1; bool length_changed_allowed = true; char directive = **format; (*format)++; switch (directive) { case ' ': case '\t': case '\n': case '\v': case '\f': case '\r': *type = PM_PACK_SPACE; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; *length_type = PM_PACK_LENGTH_NA; *length = 0; return PM_PACK_OK; case '#': while ((*format < format_end) && (**format != '\n')) { (*format)++; } *type = PM_PACK_COMMENT; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; *length_type = PM_PACK_LENGTH_NA; *length = 0; return PM_PACK_OK; case 'C': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_AGNOSTIC_ENDIAN; *size = PM_PACK_SIZE_8; break; case 'S': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_16; break; case 'L': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_32; break; case 'Q': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_64; break; case 'J': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_P; break; case 'c': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_SIGNED; *endian = PM_PACK_AGNOSTIC_ENDIAN; *size = PM_PACK_SIZE_8; break; case 's': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_SIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_16; break; case 'l': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_SIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_32; break; case 'q': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_SIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_64; break; case 'j': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_SIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_P; break; case 'I': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_INT; break; case 'i': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_SIGNED; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_INT; break; case 'n': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_BIG_ENDIAN; *size = PM_PACK_SIZE_16; length_changed_allowed = false; break; case 'N': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_BIG_ENDIAN; *size = PM_PACK_SIZE_32; length_changed_allowed = false; break; case 'v': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_LITTLE_ENDIAN; *size = PM_PACK_SIZE_16; length_changed_allowed = false; break; case 'V': *type = PM_PACK_INTEGER; *signed_type = PM_PACK_UNSIGNED; *endian = PM_PACK_LITTLE_ENDIAN; *size = PM_PACK_SIZE_32; length_changed_allowed = false; break; case 'U': *type = PM_PACK_UTF8; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'w': *type = PM_PACK_BER; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'D': case 'd': *type = PM_PACK_FLOAT; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_64; break; case 'F': case 'f': *type = PM_PACK_FLOAT; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_NATIVE_ENDIAN; *size = PM_PACK_SIZE_32; break; case 'E': *type = PM_PACK_FLOAT; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_LITTLE_ENDIAN; *size = PM_PACK_SIZE_64; break; case 'e': *type = PM_PACK_FLOAT; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_LITTLE_ENDIAN; *size = PM_PACK_SIZE_32; break; case 'G': *type = PM_PACK_FLOAT; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_BIG_ENDIAN; *size = PM_PACK_SIZE_64; break; case 'g': *type = PM_PACK_FLOAT; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_BIG_ENDIAN; *size = PM_PACK_SIZE_32; break; case 'A': *type = PM_PACK_STRING_SPACE_PADDED; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'a': *type = PM_PACK_STRING_NULL_PADDED; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'Z': *type = PM_PACK_STRING_NULL_TERMINATED; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'B': *type = PM_PACK_STRING_MSB; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'b': *type = PM_PACK_STRING_LSB; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'H': *type = PM_PACK_STRING_HEX_HIGH; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'h': *type = PM_PACK_STRING_HEX_LOW; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'u': *type = PM_PACK_STRING_UU; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'M': *type = PM_PACK_STRING_MIME; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'm': *type = PM_PACK_STRING_BASE64; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'P': *type = PM_PACK_STRING_FIXED; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'p': *type = PM_PACK_STRING_POINTER; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case '@': *type = PM_PACK_MOVE; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'X': *type = PM_PACK_BACK; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case 'x': *type = PM_PACK_NULL; *signed_type = PM_PACK_SIGNED_NA; *endian = PM_PACK_ENDIAN_NA; *size = PM_PACK_SIZE_NA; break; case '%': return PM_PACK_ERROR_UNSUPPORTED_DIRECTIVE; default: return PM_PACK_ERROR_UNKNOWN_DIRECTIVE; } bool explicit_endian = false; while (*format < format_end) { switch (**format) { case '_': case '!': (*format)++; if (*type != PM_PACK_INTEGER || !length_changed_allowed) { return PM_PACK_ERROR_BANG_NOT_ALLOWED; } switch (*size) { case PM_PACK_SIZE_SHORT: case PM_PACK_SIZE_INT: case PM_PACK_SIZE_LONG: case PM_PACK_SIZE_LONG_LONG: break; case PM_PACK_SIZE_16: *size = PM_PACK_SIZE_SHORT; break; case PM_PACK_SIZE_32: *size = PM_PACK_SIZE_LONG; break; case PM_PACK_SIZE_64: *size = PM_PACK_SIZE_LONG_LONG; break; case PM_PACK_SIZE_P: break; default: return PM_PACK_ERROR_BANG_NOT_ALLOWED; } break; case '<': (*format)++; if (explicit_endian) { return PM_PACK_ERROR_DOUBLE_ENDIAN; } *endian = PM_PACK_LITTLE_ENDIAN; explicit_endian = true; break; case '>': (*format)++; if (explicit_endian) { return PM_PACK_ERROR_DOUBLE_ENDIAN; } *endian = PM_PACK_BIG_ENDIAN; explicit_endian = true; break; default: goto exit_modifier_loop; } } exit_modifier_loop: if (variant == PM_PACK_VARIANT_UNPACK && *type == PM_PACK_MOVE) { *length = 0; } if (*format < format_end) { if (**format == '*') { switch (*type) { case PM_PACK_NULL: case PM_PACK_BACK: switch (variant) { case PM_PACK_VARIANT_PACK: *length_type = PM_PACK_LENGTH_FIXED; break; case PM_PACK_VARIANT_UNPACK: *length_type = PM_PACK_LENGTH_MAX; break; } *length = 0; break; case PM_PACK_MOVE: switch (variant) { case PM_PACK_VARIANT_PACK: *length_type = PM_PACK_LENGTH_FIXED; break; case PM_PACK_VARIANT_UNPACK: *length_type = PM_PACK_LENGTH_RELATIVE; break; } *length = 0; break; case PM_PACK_STRING_UU: *length_type = PM_PACK_LENGTH_FIXED; *length = 0; break; case PM_PACK_STRING_FIXED: switch (variant) { case PM_PACK_VARIANT_PACK: *length_type = PM_PACK_LENGTH_FIXED; *length = 1; break; case PM_PACK_VARIANT_UNPACK: *length_type = PM_PACK_LENGTH_MAX; *length = 0; break; } break; case PM_PACK_STRING_MIME: case PM_PACK_STRING_BASE64: *length_type = PM_PACK_LENGTH_FIXED; *length = 1; break; default: *length_type = PM_PACK_LENGTH_MAX; *length = 0; break; } (*format)++; } else if (**format >= '0' && **format <= '9') { errno = 0; *length_type = PM_PACK_LENGTH_FIXED; #if UINTMAX_MAX < UINT64_MAX #error "prism's design assumes uintmax_t is at least as large as uint64_t" #endif uintmax_t length_max = strtoumaxc(format); if (errno || length_max > UINT64_MAX) { return PM_PACK_ERROR_LENGTH_TOO_BIG; } *length = (uint64_t) length_max; } } switch (*type) { case PM_PACK_UTF8: /* if encoding is US-ASCII, upgrade to UTF-8 */ if (*encoding == PM_PACK_ENCODING_US_ASCII) { *encoding = PM_PACK_ENCODING_UTF_8; } break; case PM_PACK_STRING_MIME: case PM_PACK_STRING_BASE64: case PM_PACK_STRING_UU: /* keep US-ASCII (do nothing) */ break; default: /* fall back to BINARY */ *encoding = PM_PACK_ENCODING_ASCII_8BIT; break; } return PM_PACK_OK; } PRISM_EXPORTED_FUNCTION size_t pm_size_to_native(pm_pack_size size) { switch (size) { case PM_PACK_SIZE_SHORT: return sizeof(short); case PM_PACK_SIZE_INT: return sizeof(int); case PM_PACK_SIZE_LONG: return sizeof(long); case PM_PACK_SIZE_LONG_LONG: return sizeof(long long); case PM_PACK_SIZE_8: return 1; case PM_PACK_SIZE_16: return 2; case PM_PACK_SIZE_32: return 4; case PM_PACK_SIZE_64: return 8; case PM_PACK_SIZE_P: return sizeof(void *); default: return 0; } } #endif
|