--- /dev/null
+/*-\r
+ * Copyright (c) 2003-2014 Lev Walkin <vlm@lionet.info>.\r
+ * All rights reserved.\r
+ * Redistribution and modifications are permitted subject to BSD license.\r
+ */\r
+#include <asn_internal.h>\r
+#include <INTEGER.h>\r
+#include <asn_codecs_prim.h> /* Encoder and decoder of a primitive type */\r
+#include <errno.h>\r
+\r
+/*\r
+ * INTEGER basic type description.\r
+ */\r
+static const ber_tlv_tag_t asn_DEF_INTEGER_tags[] = {\r
+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2))\r
+};\r
+asn_TYPE_operation_t asn_OP_INTEGER = {\r
+ INTEGER_free,\r
+ INTEGER_print,\r
+ INTEGER_compare,\r
+ ber_decode_primitive,\r
+ INTEGER_encode_der,\r
+ INTEGER_decode_xer,\r
+ INTEGER_encode_xer,\r
+#ifdef ASN_DISABLE_OER_SUPPORT\r
+ 0,\r
+ 0,\r
+#else\r
+ INTEGER_decode_oer, /* OER decoder */\r
+ INTEGER_encode_oer, /* Canonical OER encoder */\r
+#endif /* ASN_DISABLE_OER_SUPPORT */\r
+#ifdef ASN_DISABLE_PER_SUPPORT\r
+ 0,\r
+ 0,\r
+ 0,\r
+ 0,\r
+#else\r
+ INTEGER_decode_uper, /* Unaligned PER decoder */\r
+ INTEGER_encode_uper, /* Unaligned PER encoder */\r
+ INTEGER_decode_aper, /* Aligned PER decoder */\r
+ INTEGER_encode_aper, /* Aligned PER encoder */\r
+#endif /* ASN_DISABLE_PER_SUPPORT */\r
+ INTEGER_random_fill,\r
+ 0 /* Use generic outmost tag fetcher */\r
+};\r
+asn_TYPE_descriptor_t asn_DEF_INTEGER = {\r
+ "INTEGER",\r
+ "INTEGER",\r
+ &asn_OP_INTEGER,\r
+ asn_DEF_INTEGER_tags,\r
+ sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]),\r
+ asn_DEF_INTEGER_tags, /* Same as above */\r
+ sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]),\r
+ { 0, 0, asn_generic_no_constraint },\r
+ 0, 0, /* No members */\r
+ 0 /* No specifics */\r
+};\r
+\r
+/*\r
+ * Encode INTEGER type using DER.\r
+ */\r
+asn_enc_rval_t\r
+INTEGER_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr,\r
+ int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb,\r
+ void *app_key) {\r
+ const INTEGER_t *st = (const INTEGER_t *)sptr;\r
+ asn_enc_rval_t rval;\r
+ INTEGER_t effective_integer;\r
+\r
+ ASN_DEBUG("%s %s as INTEGER (tm=%d)",\r
+ cb?"Encoding":"Estimating", td->name, tag_mode);\r
+\r
+ /*\r
+ * Canonicalize integer in the buffer.\r
+ * (Remove too long sign extension, remove some first 0x00 bytes)\r
+ */\r
+ if(st->buf) {\r
+ uint8_t *buf = st->buf;\r
+ uint8_t *end1 = buf + st->size - 1;\r
+ int shift;\r
+\r
+ /* Compute the number of superfluous leading bytes */\r
+ for(; buf < end1; buf++) {\r
+ /*\r
+ * If the contents octets of an integer value encoding\r
+ * consist of more than one octet, then the bits of the\r
+ * first octet and bit 8 of the second octet:\r
+ * a) shall not all be ones; and\r
+ * b) shall not all be zero.\r
+ */\r
+ switch(*buf) {\r
+ case 0x00: if((buf[1] & 0x80) == 0)\r
+ continue;\r
+ break;\r
+ case 0xff: if((buf[1] & 0x80))\r
+ continue;\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ /* Remove leading superfluous bytes from the integer */\r
+ shift = buf - st->buf;\r
+ if(shift) {\r
+ union {\r
+ const uint8_t *c_buf;\r
+ uint8_t *nc_buf;\r
+ } unconst;\r
+ unconst.c_buf = st->buf;\r
+ effective_integer.buf = unconst.nc_buf + shift;\r
+ effective_integer.size = st->size - shift;\r
+\r
+ st = &effective_integer;\r
+ }\r
+ }\r
+\r
+ rval = der_encode_primitive(td, st, tag_mode, tag, cb, app_key);\r
+ if(rval.structure_ptr == &effective_integer) {\r
+ rval.structure_ptr = sptr;\r
+ }\r
+ return rval;\r
+}\r
+\r
+static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(\r
+ const asn_INTEGER_specifics_t *specs, const char *lstart,\r
+ const char *lstop);\r
+\r
+/*\r
+ * INTEGER specific human-readable output.\r
+ */\r
+static ssize_t\r
+INTEGER__dump(const asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) {\r
+ const asn_INTEGER_specifics_t *specs =\r
+ (const asn_INTEGER_specifics_t *)td->specifics;\r
+ char scratch[32];\r
+ uint8_t *buf = st->buf;\r
+ uint8_t *buf_end = st->buf + st->size;\r
+ intmax_t value;\r
+ ssize_t wrote = 0;\r
+ char *p;\r
+ int ret;\r
+\r
+ if(specs && specs->field_unsigned)\r
+ ret = asn_INTEGER2umax(st, (uintmax_t *)&value);\r
+ else\r
+ ret = asn_INTEGER2imax(st, &value);\r
+\r
+ /* Simple case: the integer size is small */\r
+ if(ret == 0) {\r
+ const asn_INTEGER_enum_map_t *el;\r
+ el = (value >= 0 || !specs || !specs->field_unsigned)\r
+ ? INTEGER_map_value2enum(specs, value) : 0;\r
+ if(el) {\r
+ if(plainOrXER == 0)\r
+ return asn__format_to_callback(cb, app_key,\r
+ "%" ASN_PRIdMAX " (%s)", value, el->enum_name);\r
+ else\r
+ return asn__format_to_callback(cb, app_key,\r
+ "<%s/>", el->enum_name);\r
+ } else if(plainOrXER && specs && specs->strict_enumeration) {\r
+ ASN_DEBUG("ASN.1 forbids dealing with "\r
+ "unknown value of ENUMERATED type");\r
+ errno = EPERM;\r
+ return -1;\r
+ } else {\r
+ return asn__format_to_callback(cb, app_key,\r
+ (specs && specs->field_unsigned)\r
+ ? "%" ASN_PRIuMAX\r
+ : "%" ASN_PRIdMAX,\r
+ value);\r
+ }\r
+ } else if(plainOrXER && specs && specs->strict_enumeration) {\r
+ /*\r
+ * Here and earlier, we cannot encode the ENUMERATED values\r
+ * if there is no corresponding identifier.\r
+ */\r
+ ASN_DEBUG("ASN.1 forbids dealing with "\r
+ "unknown value of ENUMERATED type");\r
+ errno = EPERM;\r
+ return -1;\r
+ }\r
+\r
+ /* Output in the long xx:yy:zz... format */\r
+ /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */\r
+ for(p = scratch; buf < buf_end; buf++) {\r
+ const char * const h2c = "0123456789ABCDEF";\r
+ if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) {\r
+ /* Flush buffer */\r
+ if(cb(scratch, p - scratch, app_key) < 0)\r
+ return -1;\r
+ wrote += p - scratch;\r
+ p = scratch;\r
+ }\r
+ *p++ = h2c[*buf >> 4];\r
+ *p++ = h2c[*buf & 0x0F];\r
+ *p++ = 0x3a; /* ":" */\r
+ }\r
+ if(p != scratch)\r
+ p--; /* Remove the last ":" */\r
+\r
+ wrote += p - scratch;\r
+ return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote;\r
+}\r
+\r
+/*\r
+ * INTEGER specific human-readable output.\r
+ */\r
+int\r
+INTEGER_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,\r
+ asn_app_consume_bytes_f *cb, void *app_key) {\r
+ const INTEGER_t *st = (const INTEGER_t *)sptr;\r
+ ssize_t ret;\r
+\r
+ (void)ilevel;\r
+\r
+ if(!st || !st->buf)\r
+ ret = cb("<absent>", 8, app_key);\r
+ else\r
+ ret = INTEGER__dump(td, st, cb, app_key, 0);\r
+\r
+ return (ret < 0) ? -1 : 0;\r
+}\r
+\r
+struct e2v_key {\r
+ const char *start;\r
+ const char *stop;\r
+ const asn_INTEGER_enum_map_t *vemap;\r
+ const unsigned int *evmap;\r
+};\r
+static int\r
+INTEGER__compar_enum2value(const void *kp, const void *am) {\r
+ const struct e2v_key *key = (const struct e2v_key *)kp;\r
+ const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;\r
+ const char *ptr, *end, *name;\r
+\r
+ /* Remap the element (sort by different criterion) */\r
+ el = key->vemap + key->evmap[el - key->vemap];\r
+\r
+ /* Compare strings */\r
+ for(ptr = key->start, end = key->stop, name = el->enum_name;\r
+ ptr < end; ptr++, name++) {\r
+ if(*ptr != *name || !*name)\r
+ return *(const unsigned char *)ptr\r
+ - *(const unsigned char *)name;\r
+ }\r
+ return name[0] ? -1 : 0;\r
+}\r
+\r
+static const asn_INTEGER_enum_map_t *\r
+INTEGER_map_enum2value(const asn_INTEGER_specifics_t *specs, const char *lstart,\r
+ const char *lstop) {\r
+ const asn_INTEGER_enum_map_t *el_found;\r
+ int count = specs ? specs->map_count : 0;\r
+ struct e2v_key key;\r
+ const char *lp;\r
+\r
+ if(!count) return NULL;\r
+\r
+ /* Guaranteed: assert(lstart < lstop); */\r
+ /* Figure out the tag name */\r
+ for(lstart++, lp = lstart; lp < lstop; lp++) {\r
+ switch(*lp) {\r
+ case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */\r
+ case 0x2f: /* '/' */ case 0x3e: /* '>' */\r
+ break;\r
+ default:\r
+ continue;\r
+ }\r
+ break;\r
+ }\r
+ if(lp == lstop) return NULL; /* No tag found */\r
+ lstop = lp;\r
+\r
+ key.start = lstart;\r
+ key.stop = lstop;\r
+ key.vemap = specs->value2enum;\r
+ key.evmap = specs->enum2value;\r
+ el_found = (asn_INTEGER_enum_map_t *)bsearch(&key,\r
+ specs->value2enum, count, sizeof(specs->value2enum[0]),\r
+ INTEGER__compar_enum2value);\r
+ if(el_found) {\r
+ /* Remap enum2value into value2enum */\r
+ el_found = key.vemap + key.evmap[el_found - key.vemap];\r
+ }\r
+ return el_found;\r
+}\r
+\r
+static int\r
+INTEGER__compar_value2enum(const void *kp, const void *am) {\r
+ long a = *(const long *)kp;\r
+ const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;\r
+ long b = el->nat_value;\r
+ if(a < b) return -1;\r
+ else if(a == b) return 0;\r
+ else return 1;\r
+}\r
+\r
+const asn_INTEGER_enum_map_t *\r
+INTEGER_map_value2enum(const asn_INTEGER_specifics_t *specs, long value) {\r
+ int count = specs ? specs->map_count : 0;\r
+ if(!count) return 0;\r
+ return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum,\r
+ count, sizeof(specs->value2enum[0]),\r
+ INTEGER__compar_value2enum);\r
+}\r
+\r
+static int\r
+INTEGER_st_prealloc(INTEGER_t *st, int min_size) {\r
+ void *p = MALLOC(min_size + 1);\r
+ if(p) {\r
+ void *b = st->buf;\r
+ st->size = 0;\r
+ st->buf = p;\r
+ FREEMEM(b);\r
+ return 0;\r
+ } else {\r
+ return -1;\r
+ }\r
+}\r
+\r
+/*\r
+ * Decode the chunk of XML text encoding INTEGER.\r
+ */\r
+static enum xer_pbd_rval\r
+INTEGER__xer_body_decode(const asn_TYPE_descriptor_t *td, void *sptr,\r
+ const void *chunk_buf, size_t chunk_size) {\r
+ const asn_INTEGER_specifics_t *specs =\r
+ (const asn_INTEGER_specifics_t *)td->specifics;\r
+ INTEGER_t *st = (INTEGER_t *)sptr;\r
+ intmax_t dec_value;\r
+ intmax_t hex_value = 0;\r
+ const char *lp;\r
+ const char *lstart = (const char *)chunk_buf;\r
+ const char *lstop = lstart + chunk_size;\r
+ enum {\r
+ ST_LEADSPACE,\r
+ ST_SKIPSPHEX,\r
+ ST_WAITDIGITS,\r
+ ST_DIGITS,\r
+ ST_DIGITS_TRAILSPACE,\r
+ ST_HEXDIGIT1,\r
+ ST_HEXDIGIT2,\r
+ ST_HEXDIGITS_TRAILSPACE,\r
+ ST_HEXCOLON,\r
+ ST_END_ENUM,\r
+ ST_UNEXPECTED\r
+ } state = ST_LEADSPACE;\r
+ const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */\r
+ const char *dec_value_end = 0;\r
+\r
+ if(chunk_size)\r
+ ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x",\r
+ (long)chunk_size, *lstart, lstop[-1]);\r
+\r
+ if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))\r
+ return XPBD_SYSTEM_FAILURE;\r
+\r
+ /*\r
+ * We may have received a tag here. It will be processed inline.\r
+ * Use strtoul()-like code and serialize the result.\r
+ */\r
+ for(lp = lstart; lp < lstop; lp++) {\r
+ int lv = *lp;\r
+ switch(lv) {\r
+ case 0x09: case 0x0a: case 0x0d: case 0x20:\r
+ switch(state) {\r
+ case ST_LEADSPACE:\r
+ case ST_DIGITS_TRAILSPACE:\r
+ case ST_HEXDIGITS_TRAILSPACE:\r
+ case ST_SKIPSPHEX:\r
+ continue;\r
+ case ST_DIGITS:\r
+ dec_value_end = lp;\r
+ state = ST_DIGITS_TRAILSPACE;\r
+ continue;\r
+ case ST_HEXCOLON:\r
+ state = ST_HEXDIGITS_TRAILSPACE;\r
+ continue;\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ case 0x2d: /* '-' */\r
+ if(state == ST_LEADSPACE) {\r
+ dec_value = 0;\r
+ dec_value_start = lp;\r
+ state = ST_WAITDIGITS;\r
+ continue;\r
+ }\r
+ break;\r
+ case 0x2b: /* '+' */\r
+ if(state == ST_LEADSPACE) {\r
+ dec_value = 0;\r
+ dec_value_start = lp;\r
+ state = ST_WAITDIGITS;\r
+ continue;\r
+ }\r
+ break;\r
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:\r
+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:\r
+ switch(state) {\r
+ case ST_DIGITS: continue;\r
+ case ST_SKIPSPHEX: /* Fall through */\r
+ case ST_HEXDIGIT1:\r
+ hex_value = (lv - 0x30) << 4;\r
+ state = ST_HEXDIGIT2;\r
+ continue;\r
+ case ST_HEXDIGIT2:\r
+ hex_value += (lv - 0x30);\r
+ state = ST_HEXCOLON;\r
+ st->buf[st->size++] = (uint8_t)hex_value;\r
+ continue;\r
+ case ST_HEXCOLON:\r
+ return XPBD_BROKEN_ENCODING;\r
+ case ST_LEADSPACE:\r
+ dec_value = 0;\r
+ dec_value_start = lp;\r
+ /* FALL THROUGH */\r
+ case ST_WAITDIGITS:\r
+ state = ST_DIGITS;\r
+ continue;\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ case 0x3c: /* '<', start of XML encoded enumeration */\r
+ if(state == ST_LEADSPACE) {\r
+ const asn_INTEGER_enum_map_t *el;\r
+ el = INTEGER_map_enum2value(\r
+ (const asn_INTEGER_specifics_t *)\r
+ td->specifics, lstart, lstop);\r
+ if(el) {\r
+ ASN_DEBUG("Found \"%s\" => %ld",\r
+ el->enum_name, el->nat_value);\r
+ dec_value = el->nat_value;\r
+ state = ST_END_ENUM;\r
+ lp = lstop - 1;\r
+ continue;\r
+ }\r
+ ASN_DEBUG("Unknown identifier for INTEGER");\r
+ }\r
+ return XPBD_BROKEN_ENCODING;\r
+ case 0x3a: /* ':' */\r
+ if(state == ST_HEXCOLON) {\r
+ /* This colon is expected */\r
+ state = ST_HEXDIGIT1;\r
+ continue;\r
+ } else if(state == ST_DIGITS) {\r
+ /* The colon here means that we have\r
+ * decoded the first two hexadecimal\r
+ * places as a decimal value.\r
+ * Switch decoding mode. */\r
+ ASN_DEBUG("INTEGER re-evaluate as hex form");\r
+ state = ST_SKIPSPHEX;\r
+ dec_value_start = 0;\r
+ lp = lstart - 1;\r
+ continue;\r
+ } else {\r
+ ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart));\r
+ break;\r
+ }\r
+ /* [A-Fa-f] */\r
+ case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:\r
+ case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:\r
+ switch(state) {\r
+ case ST_SKIPSPHEX:\r
+ case ST_LEADSPACE: /* Fall through */\r
+ case ST_HEXDIGIT1:\r
+ hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61);\r
+ hex_value += 10;\r
+ hex_value <<= 4;\r
+ state = ST_HEXDIGIT2;\r
+ continue;\r
+ case ST_HEXDIGIT2:\r
+ hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61);\r
+ hex_value += 10;\r
+ st->buf[st->size++] = (uint8_t)hex_value;\r
+ state = ST_HEXCOLON;\r
+ continue;\r
+ case ST_DIGITS:\r
+ ASN_DEBUG("INTEGER re-evaluate as hex form");\r
+ state = ST_SKIPSPHEX;\r
+ dec_value_start = 0;\r
+ lp = lstart - 1;\r
+ continue;\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ /* Found extra non-numeric stuff */\r
+ ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld",\r
+ lv, (long)(lp - lstart));\r
+ state = ST_UNEXPECTED;\r
+ break;\r
+ }\r
+\r
+ switch(state) {\r
+ case ST_END_ENUM:\r
+ /* Got a complete and valid enumeration encoded as a tag. */\r
+ break;\r
+ case ST_DIGITS:\r
+ dec_value_end = lstop;\r
+ /* FALL THROUGH */\r
+ case ST_DIGITS_TRAILSPACE:\r
+ /* The last symbol encountered was a digit. */\r
+ switch(asn_strtoimax_lim(dec_value_start, &dec_value_end, &dec_value)) {\r
+ case ASN_STRTOX_OK:\r
+ if(specs && specs->field_unsigned && (uintmax_t) dec_value <= ULONG_MAX) {\r
+ break;\r
+ } else if(dec_value >= LONG_MIN && dec_value <= LONG_MAX) {\r
+ break;\r
+ } else {\r
+ /*\r
+ * We model INTEGER on long for XER,\r
+ * to avoid rewriting all the tests at once.\r
+ */\r
+ ASN_DEBUG("INTEGER exceeds long range");\r
+ }\r
+ /* Fall through */\r
+ case ASN_STRTOX_ERROR_RANGE:\r
+ ASN_DEBUG("INTEGER decode %s hit range limit", td->name);\r
+ return XPBD_DECODER_LIMIT;\r
+ case ASN_STRTOX_ERROR_INVAL:\r
+ case ASN_STRTOX_EXPECT_MORE:\r
+ case ASN_STRTOX_EXTRA_DATA:\r
+ return XPBD_BROKEN_ENCODING;\r
+ }\r
+ break;\r
+ case ST_HEXCOLON:\r
+ case ST_HEXDIGITS_TRAILSPACE:\r
+ st->buf[st->size] = 0; /* Just in case termination */\r
+ return XPBD_BODY_CONSUMED;\r
+ case ST_HEXDIGIT1:\r
+ case ST_HEXDIGIT2:\r
+ case ST_SKIPSPHEX:\r
+ return XPBD_BROKEN_ENCODING;\r
+ case ST_LEADSPACE:\r
+ /* Content not found */\r
+ return XPBD_NOT_BODY_IGNORE;\r
+ case ST_WAITDIGITS:\r
+ case ST_UNEXPECTED:\r
+ ASN_DEBUG("INTEGER: No useful digits (state %d)", state);\r
+ return XPBD_BROKEN_ENCODING; /* No digits */\r
+ }\r
+\r
+ /*\r
+ * Convert the result of parsing of enumeration or a straight\r
+ * decimal value into a BER representation.\r
+ */\r
+ if(asn_imax2INTEGER(st, dec_value)) {\r
+ ASN_DEBUG("INTEGER decode %s conversion failed", td->name);\r
+ return XPBD_SYSTEM_FAILURE;\r
+ }\r
+\r
+ return XPBD_BODY_CONSUMED;\r
+}\r
+\r
+asn_dec_rval_t\r
+INTEGER_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,\r
+ const asn_TYPE_descriptor_t *td, void **sptr,\r
+ const char *opt_mname, const void *buf_ptr, size_t size) {\r
+ return xer_decode_primitive(opt_codec_ctx, td,\r
+ sptr, sizeof(INTEGER_t), opt_mname,\r
+ buf_ptr, size, INTEGER__xer_body_decode);\r
+}\r
+\r
+asn_enc_rval_t\r
+INTEGER_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,\r
+ int ilevel, enum xer_encoder_flags_e flags,\r
+ asn_app_consume_bytes_f *cb, void *app_key) {\r
+ const INTEGER_t *st = (const INTEGER_t *)sptr;\r
+ asn_enc_rval_t er = {0,0,0};\r
+\r
+ (void)ilevel;\r
+ (void)flags;\r
+ \r
+ if(!st || !st->buf)\r
+ ASN__ENCODE_FAILED;\r
+\r
+ er.encoded = INTEGER__dump(td, st, cb, app_key, 1);\r
+ if(er.encoded < 0) ASN__ENCODE_FAILED;\r
+\r
+ ASN__ENCODED_OK(er);\r
+}\r
+\r
+#ifndef ASN_DISABLE_PER_SUPPORT\r
+\r
+asn_dec_rval_t\r
+INTEGER_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,\r
+ const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints, void **sptr,\r
+ asn_per_data_t *pd) {\r
+ const asn_INTEGER_specifics_t *specs =\r
+ (const asn_INTEGER_specifics_t *)td->specifics;\r
+ asn_dec_rval_t rval = { RC_OK, 0 };\r
+ INTEGER_t *st = (INTEGER_t *)*sptr;\r
+ const asn_per_constraint_t *ct;\r
+ int repeat;\r
+\r
+ (void)opt_codec_ctx;\r
+\r
+ if(!st) {\r
+ st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));\r
+ if(!st) ASN__DECODE_FAILED;\r
+ }\r
+\r
+ if(!constraints) constraints = td->encoding_constraints.per_constraints;\r
+ ct = constraints ? &constraints->value : 0;\r
+\r
+ if(ct && ct->flags & APC_EXTENSIBLE) {\r
+ int inext = per_get_few_bits(pd, 1);\r
+ if(inext < 0) ASN__DECODE_STARVED;\r
+ if(inext) ct = 0;\r
+ }\r
+\r
+ FREEMEM(st->buf);\r
+ st->buf = 0;\r
+ st->size = 0;\r
+ if(ct) {\r
+ if(ct->flags & APC_SEMI_CONSTRAINED) {\r
+ st->buf = (uint8_t *)CALLOC(1, 2);\r
+ if(!st->buf) ASN__DECODE_FAILED;\r
+ st->size = 1;\r
+ } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) {\r
+ size_t size = (ct->range_bits + 7) >> 3;\r
+ st->buf = (uint8_t *)MALLOC(1 + size + 1);\r
+ if(!st->buf) ASN__DECODE_FAILED;\r
+ st->size = size;\r
+ }\r
+ }\r
+\r
+ /* X.691-2008/11, #13.2.2, constrained whole number */\r
+ if(ct && ct->flags != APC_UNCONSTRAINED) {\r
+ /* #11.5.6 */\r
+ ASN_DEBUG("Integer with range %d bits", ct->range_bits);\r
+ if(ct->range_bits >= 0) {\r
+ if((size_t)ct->range_bits > 8 * sizeof(unsigned long))\r
+ ASN__DECODE_FAILED;\r
+\r
+ if(specs && specs->field_unsigned) {\r
+ unsigned long uvalue = 0;\r
+ if(uper_get_constrained_whole_number(pd,\r
+ &uvalue, ct->range_bits))\r
+ ASN__DECODE_STARVED;\r
+ ASN_DEBUG("Got value %lu + low %ld",\r
+ uvalue, ct->lower_bound);\r
+ uvalue += ct->lower_bound;\r
+ if(asn_ulong2INTEGER(st, uvalue))\r
+ ASN__DECODE_FAILED;\r
+ } else {\r
+ unsigned long uvalue = 0;\r
+ long svalue;\r
+ if(uper_get_constrained_whole_number(pd,\r
+ &uvalue, ct->range_bits))\r
+ ASN__DECODE_STARVED;\r
+ ASN_DEBUG("Got value %lu + low %ld",\r
+ uvalue, ct->lower_bound);\r
+ if(per_long_range_unrebase(uvalue, ct->lower_bound,\r
+ ct->upper_bound, &svalue)\r
+ || asn_long2INTEGER(st, svalue)) {\r
+ ASN__DECODE_FAILED;\r
+ }\r
+ }\r
+ return rval;\r
+ }\r
+ } else {\r
+ ASN_DEBUG("Decoding unconstrained integer %s", td->name);\r
+ }\r
+\r
+ /* X.691, #12.2.3, #12.2.4 */\r
+ do {\r
+ ssize_t len = 0;\r
+ void *p = NULL;\r
+ int ret = 0;\r
+\r
+ /* Get the PER length */\r
+ len = uper_get_length(pd, -1, 0, &repeat);\r
+ if(len < 0) ASN__DECODE_STARVED;\r
+\r
+ p = REALLOC(st->buf, st->size + len + 1);\r
+ if(!p) ASN__DECODE_FAILED;\r
+ st->buf = (uint8_t *)p;\r
+\r
+ ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len);\r
+ if(ret < 0) ASN__DECODE_STARVED;\r
+ st->size += len;\r
+ } while(repeat);\r
+ st->buf[st->size] = 0; /* JIC */\r
+\r
+ /* #12.2.3 */\r
+ if(ct && ct->lower_bound) {\r
+ /*\r
+ * TODO: replace by in-place arithmetics.\r
+ */\r
+ long value = 0;\r
+ if(asn_INTEGER2long(st, &value))\r
+ ASN__DECODE_FAILED;\r
+ if(asn_imax2INTEGER(st, value + ct->lower_bound))\r
+ ASN__DECODE_FAILED;\r
+ }\r
+\r
+ return rval;\r
+}\r
+\r
+asn_enc_rval_t\r
+INTEGER_encode_uper(const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints, const void *sptr,\r
+ asn_per_outp_t *po) {\r
+ const asn_INTEGER_specifics_t *specs =\r
+ (const asn_INTEGER_specifics_t *)td->specifics;\r
+ asn_enc_rval_t er = {0,0,0};\r
+ const INTEGER_t *st = (const INTEGER_t *)sptr;\r
+ const uint8_t *buf;\r
+ const uint8_t *end;\r
+ const asn_per_constraint_t *ct;\r
+ long value = 0;\r
+\r
+ if(!st || st->size == 0) ASN__ENCODE_FAILED;\r
+\r
+ if(!constraints) constraints = td->encoding_constraints.per_constraints;\r
+ ct = constraints ? &constraints->value : 0;\r
+\r
+ er.encoded = 0;\r
+\r
+ if(ct) {\r
+ int inext = 0;\r
+ if(specs && specs->field_unsigned) {\r
+ unsigned long uval;\r
+ if(asn_INTEGER2ulong(st, &uval))\r
+ ASN__ENCODE_FAILED;\r
+ /* Check proper range */\r
+ if(ct->flags & APC_SEMI_CONSTRAINED) {\r
+ if(uval < (unsigned long)ct->lower_bound)\r
+ inext = 1;\r
+ } else if(ct->range_bits >= 0) {\r
+ if(uval < (unsigned long)ct->lower_bound\r
+ || uval > (unsigned long)ct->upper_bound)\r
+ inext = 1;\r
+ }\r
+ ASN_DEBUG("Value %lu (%02x/%" ASN_PRI_SIZE ") lb %lu ub %lu %s",\r
+ uval, st->buf[0], st->size,\r
+ ct->lower_bound, ct->upper_bound,\r
+ inext ? "ext" : "fix");\r
+ value = uval;\r
+ } else {\r
+ if(asn_INTEGER2long(st, &value))\r
+ ASN__ENCODE_FAILED;\r
+ /* Check proper range */\r
+ if(ct->flags & APC_SEMI_CONSTRAINED) {\r
+ if(value < ct->lower_bound)\r
+ inext = 1;\r
+ } else if(ct->range_bits >= 0) {\r
+ if(value < ct->lower_bound\r
+ || value > ct->upper_bound)\r
+ inext = 1;\r
+ }\r
+ ASN_DEBUG("Value %ld (%02x/%" ASN_PRI_SIZE ") lb %ld ub %ld %s",\r
+ value, st->buf[0], st->size,\r
+ ct->lower_bound, ct->upper_bound,\r
+ inext ? "ext" : "fix");\r
+ }\r
+ if(ct->flags & APC_EXTENSIBLE) {\r
+ if(per_put_few_bits(po, inext, 1))\r
+ ASN__ENCODE_FAILED;\r
+ if(inext) ct = 0;\r
+ } else if(inext) {\r
+ ASN__ENCODE_FAILED;\r
+ }\r
+ }\r
+\r
+\r
+ /* X.691-11/2008, #13.2.2, test if constrained whole number */\r
+ if(ct && ct->range_bits >= 0) {\r
+ unsigned long v;\r
+ /* #11.5.6 -> #11.3 */\r
+ ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits",\r
+ value, value - ct->lower_bound, ct->range_bits);\r
+ if(specs && specs->field_unsigned) {\r
+ if ( ((unsigned long)ct->lower_bound > (unsigned long)(ct->upper_bound)\r
+ || ((unsigned long)value < (unsigned long)ct->lower_bound))\r
+ || ((unsigned long)value > (unsigned long)ct->upper_bound)\r
+ ) {\r
+ ASN_DEBUG("Value %lu to-be-encoded is outside the bounds [%lu, %lu]!",\r
+ value, ct->lower_bound, ct->upper_bound);\r
+ ASN__ENCODE_FAILED;\r
+ }\r
+ v = (unsigned long)value - (unsigned long)ct->lower_bound;\r
+ } else {\r
+ if(per_long_range_rebase(value, ct->lower_bound, ct->upper_bound, &v)) {\r
+ ASN__ENCODE_FAILED;\r
+ }\r
+ }\r
+ if(uper_put_constrained_whole_number_u(po, v, ct->range_bits))\r
+ ASN__ENCODE_FAILED;\r
+ ASN__ENCODED_OK(er);\r
+ }\r
+\r
+ if(ct && ct->lower_bound) {\r
+ ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound);\r
+ /* TODO: adjust lower bound */\r
+ ASN__ENCODE_FAILED;\r
+ }\r
+\r
+ for(buf = st->buf, end = st->buf + st->size; buf < end;) {\r
+ int need_eom = 0;\r
+ ssize_t mayEncode = uper_put_length(po, end - buf, &need_eom);\r
+ if(mayEncode < 0)\r
+ ASN__ENCODE_FAILED;\r
+ if(per_put_many_bits(po, buf, 8 * mayEncode))\r
+ ASN__ENCODE_FAILED;\r
+ buf += mayEncode;\r
+ if(need_eom && uper_put_length(po, 0, 0)) ASN__ENCODE_FAILED;\r
+ }\r
+\r
+ ASN__ENCODED_OK(er);\r
+}\r
+\r
+asn_dec_rval_t\r
+INTEGER_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,\r
+ const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {\r
+ const asn_INTEGER_specifics_t *specs = (const asn_INTEGER_specifics_t *)td->specifics;\r
+ asn_dec_rval_t rval = { RC_OK, 0 };\r
+ INTEGER_t *st = (INTEGER_t *)*sptr;\r
+ const asn_per_constraint_t *ct;\r
+ int repeat;\r
+\r
+ (void)opt_codec_ctx;\r
+\r
+ if(!st) {\r
+ st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));\r
+ if(!st) ASN__DECODE_FAILED;\r
+ }\r
+\r
+ if(!constraints) constraints = td->encoding_constraints.per_constraints;\r
+ ct = constraints ? &constraints->value : 0;\r
+\r
+ if(ct && ct->flags & APC_EXTENSIBLE) {\r
+ int inext = per_get_few_bits(pd, 1);\r
+ if(inext < 0) ASN__DECODE_STARVED;\r
+ if(inext) ct = 0;\r
+ }\r
+\r
+ FREEMEM(st->buf);\r
+ st->buf = 0;\r
+ st->size = 0;\r
+ if(ct) {\r
+ if(ct->flags & APC_SEMI_CONSTRAINED) {\r
+ st->buf = (uint8_t *)CALLOC(1, 2);\r
+ if(!st->buf) ASN__DECODE_FAILED;\r
+ st->size = 1;\r
+ } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) {\r
+ size_t size = (ct->range_bits + 7) >> 3;\r
+ st->buf = (uint8_t *)MALLOC(1 + size + 1);\r
+ if(!st->buf) ASN__DECODE_FAILED;\r
+ st->size = size;\r
+ }\r
+ }\r
+\r
+ /* X.691, #12.2.2 */\r
+ if(ct && ct->flags != APC_UNCONSTRAINED) {\r
+ /* #10.5.6 */\r
+ ASN_DEBUG("Integer with range %d bits", ct->range_bits);\r
+ if(ct->range_bits >= 0) {\r
+ if (ct->range_bits > 16) {\r
+ int max_range_bytes = (ct->range_bits >> 3) +\r
+ (((ct->range_bits % 8) > 0) ? 1 : 0);\r
+ int length = 0, i;\r
+ long value = 0;\r
+\r
+ for (i = 1; ; i++) {\r
+ int upper = 1 << i;\r
+ if (upper >= max_range_bytes)\r
+ break;\r
+ }\r
+ ASN_DEBUG("Can encode %d (%d bytes) in %d bits", ct->range_bits,\r
+ max_range_bytes, i);\r
+\r
+ if ((length = per_get_few_bits(pd, i)) < 0)\r
+ ASN__DECODE_FAILED;\r
+\r
+ /* X.691 #12.2.6 length determinant + lb (1) */\r
+ length += 1;\r
+ ASN_DEBUG("Got length %d", length);\r
+ if (aper_get_align(pd) != 0)\r
+ ASN__DECODE_FAILED;\r
+ while (length--) {\r
+ int buf = per_get_few_bits(pd, 8);\r
+ if (buf < 0)\r
+ ASN__DECODE_FAILED;\r
+ value += (((long)buf) << (8 * length));\r
+ }\r
+\r
+ value += ct->lower_bound;\r
+ if((specs && specs->field_unsigned)\r
+ ? asn_uint642INTEGER(st, (unsigned long)value)\r
+ : asn_int642INTEGER(st, value))\r
+ ASN__DECODE_FAILED;\r
+ ASN_DEBUG("Got value %ld + low %ld",\r
+ value, ct->lower_bound);\r
+ } else {\r
+ long value = 0;\r
+ if (ct->range_bits < 8) {\r
+ value = per_get_few_bits(pd, ct->range_bits);\r
+ if(value < 0) ASN__DECODE_STARVED;\r
+ } else if (ct->range_bits == 8) {\r
+ if (aper_get_align(pd) < 0)\r
+ ASN__DECODE_FAILED;\r
+ value = per_get_few_bits(pd, ct->range_bits);\r
+ if(value < 0) ASN__DECODE_STARVED;\r
+ } else {\r
+ /* Align */\r
+ if (aper_get_align(pd) < 0)\r
+ ASN__DECODE_FAILED;\r
+ value = per_get_few_bits(pd, 16);\r
+ if(value < 0) ASN__DECODE_STARVED;\r
+ }\r
+ value += ct->lower_bound;\r
+ if((specs && specs->field_unsigned)\r
+ ? asn_ulong2INTEGER(st, value)\r
+ : asn_long2INTEGER(st, value))\r
+ ASN__DECODE_FAILED;\r
+ ASN_DEBUG("Got value %ld + low %ld",\r
+ value, ct->lower_bound);\r
+ }\r
+ return rval;\r
+ } else {\r
+ ASN__DECODE_FAILED;\r
+ }\r
+ } else {\r
+ ASN_DEBUG("Decoding unconstrained integer %s", td->name);\r
+ }\r
+\r
+ /* X.691, #12.2.3, #12.2.4 */\r
+ do {\r
+ ssize_t len;\r
+ void *p;\r
+ int ret;\r
+\r
+ /* Get the PER length */\r
+ len = aper_get_length(pd, -1, -1, &repeat);\r
+ if(len < 0) ASN__DECODE_STARVED;\r
+\r
+ p = REALLOC(st->buf, st->size + len + 1);\r
+ if(!p) ASN__DECODE_FAILED;\r
+ st->buf = (uint8_t *)p;\r
+\r
+ ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len);\r
+ if(ret < 0) ASN__DECODE_STARVED;\r
+ st->size += len;\r
+ } while(repeat);\r
+ st->buf[st->size] = 0; /* JIC */\r
+\r
+ /* #12.2.3 */\r
+ if(ct && ct->lower_bound) {\r
+ /*\r
+ * TODO: replace by in-place arithmetics.\r
+ */\r
+ long value;\r
+ if(asn_INTEGER2long(st, &value))\r
+ ASN__DECODE_FAILED;\r
+ if(asn_long2INTEGER(st, value + ct->lower_bound))\r
+ ASN__DECODE_FAILED;\r
+ }\r
+\r
+ return rval;\r
+}\r
+\r
+asn_enc_rval_t\r
+INTEGER_encode_aper(const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints,\r
+ const void *sptr, asn_per_outp_t *po) {\r
+ const asn_INTEGER_specifics_t *specs = (const asn_INTEGER_specifics_t *)td->specifics;\r
+ asn_enc_rval_t er = {0,0,0};\r
+ const INTEGER_t *st = (const INTEGER_t *)sptr;\r
+ const uint8_t *buf;\r
+ const uint8_t *end;\r
+ const asn_per_constraint_t *ct;\r
+ long value = 0;\r
+\r
+ if(!st || st->size == 0) ASN__ENCODE_FAILED;\r
+\r
+ if(!constraints) constraints = td->encoding_constraints.per_constraints;\r
+ ct = constraints ? &constraints->value : 0;\r
+\r
+ er.encoded = 0;\r
+\r
+ if(ct) {\r
+ int inext = 0;\r
+ if(specs && specs->field_unsigned) {\r
+ unsigned long uval;\r
+ if(asn_INTEGER2ulong(st, &uval))\r
+ ASN__ENCODE_FAILED;\r
+ /* Check proper range */\r
+ if(ct->flags & APC_SEMI_CONSTRAINED) {\r
+ if(uval < (unsigned long)ct->lower_bound)\r
+ inext = 1;\r
+ } else if(ct->range_bits >= 0) {\r
+ if(uval < (unsigned long)ct->lower_bound\r
+ || uval > (unsigned long)ct->upper_bound)\r
+ inext = 1;\r
+ }\r
+ ASN_DEBUG("Value %lu (%02x/%lu) lb %ld ub %ld %s",\r
+ uval, st->buf[0], st->size,\r
+ ct->lower_bound, ct->upper_bound,\r
+ inext ? "ext" : "fix");\r
+ value = uval;\r
+ } else {\r
+ if(asn_INTEGER2long(st, &value)) ASN__ENCODE_FAILED;\r
+ /* Check proper range */\r
+ if(ct->flags & APC_SEMI_CONSTRAINED) {\r
+ if(value < ct->lower_bound)\r
+ inext = 1;\r
+ } else if(ct->range_bits >= 0) {\r
+ if(value < ct->lower_bound\r
+ || value > ct->upper_bound)\r
+ inext = 1;\r
+ }\r
+ ASN_DEBUG("Value %lu (%02x/%lu) lb %ld ub %ld %s",\r
+ value, st->buf[0], st->size,\r
+ ct->lower_bound, ct->upper_bound,\r
+ inext ? "ext" : "fix");\r
+ }\r
+ if(ct->flags & APC_EXTENSIBLE) {\r
+ if(per_put_few_bits(po, inext, 1))\r
+ ASN__ENCODE_FAILED;\r
+ if(inext) ct = 0;\r
+ } else if(inext) {\r
+ ASN__ENCODE_FAILED;\r
+ }\r
+ }\r
+\r
+ /* X.691, #12.2.2 */\r
+ if(ct && ct->range_bits >= 0) {\r
+ unsigned long v;\r
+\r
+ /* #10.5.6 */\r
+ ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits",\r
+ value, value - ct->lower_bound, ct->range_bits);\r
+\r
+ v = value - ct->lower_bound;\r
+\r
+ /* #12 <= 8 -> alignment ? */\r
+ if (ct->range_bits < 8) {\r
+ if(per_put_few_bits(po, 0x00 | v, ct->range_bits))\r
+ ASN__ENCODE_FAILED;\r
+ } else if (ct->range_bits == 8) {\r
+ if(aper_put_align(po) < 0)\r
+ ASN__ENCODE_FAILED;\r
+ if(per_put_few_bits(po, 0x00 | v, ct->range_bits))\r
+ ASN__ENCODE_FAILED;\r
+ } else if (ct->range_bits <= 16) {\r
+ /* Consume the bytes to align on octet */\r
+ if(aper_put_align(po) < 0)\r
+ ASN__ENCODE_FAILED;\r
+ if(per_put_few_bits(po, 0x0000 | v,\r
+ 16))\r
+ ASN__ENCODE_FAILED;\r
+ } else {\r
+ /* TODO: extend to >64 bits */\r
+ int64_t v64 = v;\r
+ int i, j;\r
+ int max_range_bytes = (ct->range_bits >> 3) +\r
+ (((ct->range_bits % 8) > 0) ? 1 : 0);\r
+\r
+ for (i = 1; ; i++) {\r
+ int upper = 1 << i;\r
+ if (upper >= max_range_bytes)\r
+ break;\r
+ }\r
+\r
+ for (j = sizeof(int64_t) -1; j != 0; j--) {\r
+ int64_t val;\r
+ val = v64 >> (j * 8);\r
+ if (val != 0)\r
+ break;\r
+ }\r
+\r
+ /* Putting length in the minimum number of bits ex: 5 = 3bits */\r
+ if (per_put_few_bits(po, j, i))\r
+ ASN__ENCODE_FAILED;\r
+\r
+ /* Consume the bits to align on octet */\r
+ if (aper_put_align(po) < 0)\r
+ ASN__ENCODE_FAILED;\r
+ /* Put the value */\r
+ for (i = 0; i <= j; i++) {\r
+ if(per_put_few_bits(po, (v64 >> (8 * (j - i))) & 0xff, 8))\r
+ ASN__ENCODE_FAILED;\r
+ }\r
+ }\r
+ ASN__ENCODED_OK(er);\r
+ }\r
+\r
+ if(ct && ct->lower_bound) {\r
+ ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound);\r
+ /* TODO: adjust lower bound */\r
+ ASN__ENCODE_FAILED;\r
+ }\r
+\r
+ for(buf = st->buf, end = st->buf + st->size; buf < end;) {\r
+ ssize_t mayEncode = aper_put_length(po, -1, end - buf);\r
+ if(mayEncode < 0)\r
+ ASN__ENCODE_FAILED;\r
+ if(per_put_many_bits(po, buf, 8 * mayEncode))\r
+ ASN__ENCODE_FAILED;\r
+ buf += mayEncode;\r
+ }\r
+\r
+ ASN__ENCODED_OK(er);\r
+}\r
+\r
+#endif /* ASN_DISABLE_PER_SUPPORT */\r
+\r
+static intmax_t\r
+asn__integer_convert(const uint8_t *b, const uint8_t *end) {\r
+ uintmax_t value;\r
+\r
+ /* Perform the sign initialization */\r
+ /* Actually value = -(*b >> 7); gains nothing, yet unreadable! */\r
+ if((*b >> 7)) {\r
+ value = (uintmax_t)(-1);\r
+ } else {\r
+ value = 0;\r
+ }\r
+\r
+ /* Conversion engine */\r
+ for(; b < end; b++) {\r
+ value = (value << 8) | *b;\r
+ }\r
+\r
+ return value;\r
+}\r
+\r
+int\r
+asn_INTEGER2imax(const INTEGER_t *iptr, intmax_t *lptr) {\r
+ uint8_t *b, *end;\r
+ size_t size;\r
+\r
+ /* Sanity checking */\r
+ if(!iptr || !iptr->buf || !lptr) {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+ /* Cache the begin/end of the buffer */\r
+ b = iptr->buf; /* Start of the INTEGER buffer */\r
+ size = iptr->size;\r
+ end = b + size; /* Where to stop */\r
+\r
+ if(size > sizeof(intmax_t)) {\r
+ uint8_t *end1 = end - 1;\r
+ /*\r
+ * Slightly more advanced processing,\r
+ * able to process INTEGERs with >sizeof(intmax_t) bytes\r
+ * when the actual value is small, e.g. for intmax_t == int32_t\r
+ * (0x0000000000abcdef INTEGER would yield a fine 0x00abcdef int32_t)\r
+ */\r
+ /* Skip out the insignificant leading bytes */\r
+ for(; b < end1; b++) {\r
+ switch(*b) {\r
+ case 0x00: if((b[1] & 0x80) == 0) continue; break;\r
+ case 0xff: if((b[1] & 0x80) != 0) continue; break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ size = end - b;\r
+ if(size > sizeof(intmax_t)) {\r
+ /* Still cannot fit the sizeof(intmax_t) */\r
+ errno = ERANGE;\r
+ return -1;\r
+ }\r
+ }\r
+\r
+ /* Shortcut processing of a corner case */\r
+ if(end == b) {\r
+ *lptr = 0;\r
+ return 0;\r
+ }\r
+\r
+ *lptr = asn__integer_convert(b, end);\r
+ return 0;\r
+}\r
+\r
+/* FIXME: negative INTEGER values are silently interpreted as large unsigned ones. */\r
+int\r
+asn_INTEGER2umax(const INTEGER_t *iptr, uintmax_t *lptr) {\r
+ uint8_t *b, *end;\r
+ uintmax_t value;\r
+ size_t size;\r
+\r
+ if(!iptr || !iptr->buf || !lptr) {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+ b = iptr->buf;\r
+ size = iptr->size;\r
+ end = b + size;\r
+\r
+ /* If all extra leading bytes are zeroes, ignore them */\r
+ for(; size > sizeof(value); b++, size--) {\r
+ if(*b) {\r
+ /* Value won't fit into uintmax_t */\r
+ errno = ERANGE;\r
+ return -1;\r
+ }\r
+ }\r
+\r
+ /* Conversion engine */\r
+ for(value = 0; b < end; b++)\r
+ value = (value << 8) | *b;\r
+\r
+ *lptr = value;\r
+ return 0;\r
+}\r
+\r
+int\r
+asn_umax2INTEGER(INTEGER_t *st, uintmax_t value) {\r
+ uint8_t *buf;\r
+ uint8_t *end;\r
+ uint8_t *b;\r
+ int shr;\r
+\r
+ if(value <= ((~(uintmax_t)0) >> 1)) {\r
+ return asn_imax2INTEGER(st, value);\r
+ }\r
+\r
+ buf = (uint8_t *)MALLOC(1 + sizeof(value));\r
+ if(!buf) return -1;\r
+\r
+ end = buf + (sizeof(value) + 1);\r
+ buf[0] = 0; /* INTEGERs are signed. 0-byte indicates positive. */\r
+ for(b = buf + 1, shr = (sizeof(value) - 1) * 8; b < end; shr -= 8, b++)\r
+ *b = (uint8_t)(value >> shr);\r
+\r
+ if(st->buf) FREEMEM(st->buf);\r
+ st->buf = buf;\r
+ st->size = 1 + sizeof(value);\r
+\r
+ return 0;\r
+}\r
+\r
+int\r
+asn_imax2INTEGER(INTEGER_t *st, intmax_t value) {\r
+ uint8_t *buf, *bp;\r
+ uint8_t *p;\r
+ uint8_t *pstart;\r
+ uint8_t *pend1;\r
+ int littleEndian = 1; /* Run-time detection */\r
+ int add;\r
+\r
+ if(!st) {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+ buf = (uint8_t *)(long *)MALLOC(sizeof(value));\r
+ if(!buf) return -1;\r
+\r
+ if(*(char *)&littleEndian) {\r
+ pstart = (uint8_t *)&value + sizeof(value) - 1;\r
+ pend1 = (uint8_t *)&value;\r
+ add = -1;\r
+ } else {\r
+ pstart = (uint8_t *)&value;\r
+ pend1 = pstart + sizeof(value) - 1;\r
+ add = 1;\r
+ }\r
+\r
+ /*\r
+ * If the contents octet consists of more than one octet,\r
+ * then bits of the first octet and bit 8 of the second octet:\r
+ * a) shall not all be ones; and\r
+ * b) shall not all be zero.\r
+ */\r
+ for(p = pstart; p != pend1; p += add) {\r
+ switch(*p) {\r
+ case 0x00: if((*(p+add) & 0x80) == 0)\r
+ continue;\r
+ break;\r
+ case 0xff: if((*(p+add) & 0x80))\r
+ continue;\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ /* Copy the integer body */\r
+ for(bp = buf, pend1 += add; p != pend1; p += add)\r
+ *bp++ = *p;\r
+\r
+ if(st->buf) FREEMEM(st->buf);\r
+ st->buf = buf;\r
+ st->size = bp - buf;\r
+\r
+ return 0;\r
+}\r
+\r
+int\r
+asn_INTEGER2long(const INTEGER_t *iptr, long *l) {\r
+ intmax_t v;\r
+ if(asn_INTEGER2imax(iptr, &v) == 0) {\r
+ if(v < LONG_MIN || v > LONG_MAX) {\r
+ errno = ERANGE;\r
+ return -1;\r
+ }\r
+ *l = v;\r
+ return 0;\r
+ } else {\r
+ return -1;\r
+ }\r
+}\r
+\r
+int\r
+asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *l) {\r
+ uintmax_t v;\r
+ if(asn_INTEGER2umax(iptr, &v) == 0) {\r
+ if(v > ULONG_MAX) {\r
+ errno = ERANGE;\r
+ return -1;\r
+ }\r
+ *l = v;\r
+ return 0;\r
+ } else {\r
+ return -1;\r
+ }\r
+}\r
+\r
+int\r
+asn_long2INTEGER(INTEGER_t *st, long value) {\r
+ return asn_imax2INTEGER(st, value);\r
+}\r
+\r
+int\r
+asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) {\r
+ return asn_imax2INTEGER(st, value);\r
+}\r
+\r
+\r
+int\r
+asn_uint642INTEGER(INTEGER_t *st, uint64_t value) {\r
+ uint8_t *buf;\r
+ uint8_t *end;\r
+ uint8_t *b;\r
+ int shr;\r
+\r
+ if(value <= INT64_MAX)\r
+ return asn_int642INTEGER(st, value);\r
+\r
+ buf = (uint8_t *)MALLOC(1 + sizeof(value));\r
+ if(!buf) return -1;\r
+\r
+ end = buf + (sizeof(value) + 1);\r
+ buf[0] = 0;\r
+ for(b = buf + 1, shr = (sizeof(value)-1)*8; b < end; shr -= 8, b++)\r
+ *b = (uint8_t)(value >> shr);\r
+\r
+ if(st->buf) FREEMEM(st->buf);\r
+ st->buf = buf;\r
+ st->size = 1 + sizeof(value);\r
+\r
+ return 0;\r
+}\r
+\r
+int\r
+asn_int642INTEGER(INTEGER_t *st, int64_t value) {\r
+ uint8_t *buf, *bp;\r
+ uint8_t *p;\r
+ uint8_t *pstart;\r
+ uint8_t *pend1;\r
+ int littleEndian = 1; /* Run-time detection */\r
+ int add;\r
+\r
+ if(!st) {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+ buf = (uint8_t *)MALLOC(sizeof(value));\r
+ if(!buf) return -1;\r
+\r
+ if(*(char *)&littleEndian) {\r
+ pstart = (uint8_t *)&value + sizeof(value) - 1;\r
+ pend1 = (uint8_t *)&value;\r
+ add = -1;\r
+ } else {\r
+ pstart = (uint8_t *)&value;\r
+ pend1 = pstart + sizeof(value) - 1;\r
+ add = 1;\r
+ }\r
+\r
+ /*\r
+ * If the contents octet consists of more than one octet,\r
+ * then bits of the first octet and bit 8 of the second octet:\r
+ * a) shall not all be ones; and\r
+ * b) shall not all be zero.\r
+ */\r
+ for(p = pstart; p != pend1; p += add) {\r
+ switch(*p) {\r
+ case 0x00: if((*(p+add) & 0x80) == 0)\r
+ continue;\r
+ break;\r
+ case 0xff: if((*(p+add) & 0x80))\r
+ continue;\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ /* Copy the integer body */\r
+ for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add)\r
+ *bp++ = *p;\r
+\r
+ if(st->buf) FREEMEM(st->buf);\r
+ st->buf = buf;\r
+ st->size = bp - buf;\r
+\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * Parse the number in the given string until the given *end position,\r
+ * returning the position after the last parsed character back using the\r
+ * same (*end) pointer.\r
+ * WARNING: This behavior is different from the standard strtol/strtoimax(3).\r
+ */\r
+enum asn_strtox_result_e\r
+asn_strtoimax_lim(const char *str, const char **end, intmax_t *intp) {\r
+ int sign = 1;\r
+ intmax_t value;\r
+\r
+#define ASN1_INTMAX_MAX ((~(uintmax_t)0) >> 1)\r
+ const intmax_t upper_boundary = ASN1_INTMAX_MAX / 10;\r
+ intmax_t last_digit_max = ASN1_INTMAX_MAX % 10;\r
+#undef ASN1_INTMAX_MAX\r
+\r
+ if(str >= *end) return ASN_STRTOX_ERROR_INVAL;\r
+\r
+ switch(*str) {\r
+ case '-':\r
+ last_digit_max++;\r
+ sign = -1;\r
+ /* FALL THROUGH */\r
+ case '+':\r
+ str++;\r
+ if(str >= *end) {\r
+ *end = str;\r
+ return ASN_STRTOX_EXPECT_MORE;\r
+ }\r
+ }\r
+\r
+ for(value = 0; str < (*end); str++) {\r
+ switch(*str) {\r
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:\r
+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {\r
+ int d = *str - '0';\r
+ if(value < upper_boundary) {\r
+ value = value * 10 + d;\r
+ } else if(value == upper_boundary) {\r
+ if(d <= last_digit_max) {\r
+ if(sign > 0) {\r
+ value = value * 10 + d;\r
+ } else {\r
+ sign = 1;\r
+ value = -value * 10 - d;\r
+ }\r
+ } else {\r
+ *end = str;\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ }\r
+ } else {\r
+ *end = str;\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ }\r
+ }\r
+ continue;\r
+ default:\r
+ *end = str;\r
+ *intp = sign * value;\r
+ return ASN_STRTOX_EXTRA_DATA;\r
+ }\r
+ }\r
+\r
+ *end = str;\r
+ *intp = sign * value;\r
+ return ASN_STRTOX_OK;\r
+}\r
+\r
+/*\r
+ * Parse the number in the given string until the given *end position,\r
+ * returning the position after the last parsed character back using the\r
+ * same (*end) pointer.\r
+ * WARNING: This behavior is different from the standard strtoul/strtoumax(3).\r
+ */\r
+enum asn_strtox_result_e\r
+asn_strtoumax_lim(const char *str, const char **end, uintmax_t *uintp) {\r
+ uintmax_t value;\r
+\r
+#define ASN1_UINTMAX_MAX ((~(uintmax_t)0))\r
+ const uintmax_t upper_boundary = ASN1_UINTMAX_MAX / 10;\r
+ uintmax_t last_digit_max = ASN1_UINTMAX_MAX % 10;\r
+#undef ASN1_UINTMAX_MAX\r
+\r
+ if(str >= *end) return ASN_STRTOX_ERROR_INVAL;\r
+\r
+ switch(*str) {\r
+ case '-':\r
+ return ASN_STRTOX_ERROR_INVAL;\r
+ case '+':\r
+ str++;\r
+ if(str >= *end) {\r
+ *end = str;\r
+ return ASN_STRTOX_EXPECT_MORE;\r
+ }\r
+ }\r
+\r
+ for(value = 0; str < (*end); str++) {\r
+ switch(*str) {\r
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:\r
+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {\r
+ unsigned int d = *str - '0';\r
+ if(value < upper_boundary) {\r
+ value = value * 10 + d;\r
+ } else if(value == upper_boundary) {\r
+ if(d <= last_digit_max) {\r
+ value = value * 10 + d;\r
+ } else {\r
+ *end = str;\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ }\r
+ } else {\r
+ *end = str;\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ }\r
+ }\r
+ continue;\r
+ default:\r
+ *end = str;\r
+ *uintp = value;\r
+ return ASN_STRTOX_EXTRA_DATA;\r
+ }\r
+ }\r
+\r
+ *end = str;\r
+ *uintp = value;\r
+ return ASN_STRTOX_OK;\r
+}\r
+\r
+enum asn_strtox_result_e\r
+asn_strtol_lim(const char *str, const char **end, long *lp) {\r
+ intmax_t value;\r
+ switch(asn_strtoimax_lim(str, end, &value)) {\r
+ case ASN_STRTOX_ERROR_RANGE:\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ case ASN_STRTOX_ERROR_INVAL:\r
+ return ASN_STRTOX_ERROR_INVAL;\r
+ case ASN_STRTOX_EXPECT_MORE:\r
+ return ASN_STRTOX_EXPECT_MORE;\r
+ case ASN_STRTOX_OK:\r
+ if(value >= LONG_MIN && value <= LONG_MAX) {\r
+ *lp = value;\r
+ return ASN_STRTOX_OK;\r
+ } else {\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ }\r
+ case ASN_STRTOX_EXTRA_DATA:\r
+ if(value >= LONG_MIN && value <= LONG_MAX) {\r
+ *lp = value;\r
+ return ASN_STRTOX_EXTRA_DATA;\r
+ } else {\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ }\r
+ }\r
+\r
+ assert(!"Unreachable");\r
+ return ASN_STRTOX_ERROR_INVAL;\r
+}\r
+\r
+enum asn_strtox_result_e\r
+asn_strtoul_lim(const char *str, const char **end, unsigned long *ulp) {\r
+ uintmax_t value;\r
+ switch(asn_strtoumax_lim(str, end, &value)) {\r
+ case ASN_STRTOX_ERROR_RANGE:\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ case ASN_STRTOX_ERROR_INVAL:\r
+ return ASN_STRTOX_ERROR_INVAL;\r
+ case ASN_STRTOX_EXPECT_MORE:\r
+ return ASN_STRTOX_EXPECT_MORE;\r
+ case ASN_STRTOX_OK:\r
+ if(value <= ULONG_MAX) {\r
+ *ulp = value;\r
+ return ASN_STRTOX_OK;\r
+ } else {\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ }\r
+ case ASN_STRTOX_EXTRA_DATA:\r
+ if(value <= ULONG_MAX) {\r
+ *ulp = value;\r
+ return ASN_STRTOX_EXTRA_DATA;\r
+ } else {\r
+ return ASN_STRTOX_ERROR_RANGE;\r
+ }\r
+ }\r
+\r
+ assert(!"Unreachable");\r
+ return ASN_STRTOX_ERROR_INVAL;\r
+}\r
+\r
+int\r
+INTEGER_compare(const asn_TYPE_descriptor_t *td, const void *aptr,\r
+ const void *bptr) {\r
+ const INTEGER_t *a = aptr;\r
+ const INTEGER_t *b = bptr;\r
+\r
+ (void)td;\r
+\r
+ if(a && b) {\r
+ if(a->size && b->size) {\r
+ int sign_a = (a->buf[0] & 0x80) ? -1 : 1;\r
+ int sign_b = (b->buf[0] & 0x80) ? -1 : 1;\r
+\r
+ if(sign_a < sign_b) return -1;\r
+ if(sign_a > sign_b) return 1;\r
+\r
+ /* The shortest integer wins, unless comparing negatives */\r
+ if(a->size < b->size) {\r
+ return -1 * sign_a;\r
+ } else if(a->size > b->size) {\r
+ return 1 * sign_b;\r
+ }\r
+\r
+ return sign_a * memcmp(a->buf, b->buf, a->size);\r
+ } else if(a->size) {\r
+ int sign = (a->buf[0] & 0x80) ? -1 : 1;\r
+ return (1) * sign;\r
+ } else if(b->size) {\r
+ int sign = (a->buf[0] & 0x80) ? -1 : 1;\r
+ return (-1) * sign;\r
+ } else {\r
+ return 0;\r
+ }\r
+ } else if(!a && !b) {\r
+ return 0;\r
+ } else if(!a) {\r
+ return -1;\r
+ } else {\r
+ return 1;\r
+ }\r
+\r
+}\r
+\r
+asn_random_fill_result_t\r
+INTEGER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,\r
+ const asn_encoding_constraints_t *constraints,\r
+ size_t max_length) {\r
+ const asn_INTEGER_specifics_t *specs =\r
+ (const asn_INTEGER_specifics_t *)td->specifics;\r
+ asn_random_fill_result_t result_ok = {ARFILL_OK, 1};\r
+ asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};\r
+ asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};\r
+ INTEGER_t *st = *sptr;\r
+ const asn_INTEGER_enum_map_t *emap;\r
+ size_t emap_len;\r
+ intmax_t value;\r
+ int find_inside_map;\r
+\r
+ if(max_length == 0) return result_skipped;\r
+\r
+ if(st == NULL) {\r
+ st = (INTEGER_t *)CALLOC(1, sizeof(*st));\r
+ if(st == NULL) {\r
+ return result_failed;\r
+ }\r
+ }\r
+\r
+ if(specs) {\r
+ emap = specs->value2enum;\r
+ emap_len = specs->map_count;\r
+ if(specs->strict_enumeration) {\r
+ find_inside_map = emap_len > 0;\r
+ } else {\r
+ find_inside_map = emap_len ? asn_random_between(0, 1) : 0;\r
+ }\r
+ } else {\r
+ emap = 0;\r
+ emap_len = 0;\r
+ find_inside_map = 0;\r
+ }\r
+\r
+ if(find_inside_map) {\r
+ assert(emap_len > 0);\r
+ value = emap[asn_random_between(0, emap_len - 1)].nat_value;\r
+ } else {\r
+ const asn_per_constraints_t *ct;\r
+\r
+ static const long variants[] = {\r
+ -65536, -65535, -65534, -32769, -32768, -32767, -16385, -16384,\r
+ -16383, -257, -256, -255, -254, -129, -128, -127,\r
+ -126, -1, 0, 1, 126, 127, 128, 129,\r
+ 254, 255, 256, 257, 16383, 16384, 16385, 32767,\r
+ 32768, 32769, 65534, 65535, 65536, 65537};\r
+ if(specs && specs->field_unsigned) {\r
+ assert(variants[18] == 0);\r
+ value = variants[asn_random_between(\r
+ 18, sizeof(variants) / sizeof(variants[0]) - 1)];\r
+ } else {\r
+ value = variants[asn_random_between(\r
+ 0, sizeof(variants) / sizeof(variants[0]) - 1)];\r
+ }\r
+\r
+ if(!constraints) constraints = &td->encoding_constraints;\r
+ ct = constraints ? constraints->per_constraints : 0;\r
+ if(ct && (ct->value.flags & APC_CONSTRAINED)) {\r
+ if(value < ct->value.lower_bound || value > ct->value.upper_bound) {\r
+ value = asn_random_between(ct->value.lower_bound,\r
+ ct->value.upper_bound);\r
+ }\r
+ }\r
+ }\r
+\r
+ if(asn_imax2INTEGER(st, value)) {\r
+ if(st == *sptr) {\r
+ ASN_STRUCT_RESET(*td, st);\r
+ } else {\r
+ ASN_STRUCT_FREE(*td, st);\r
+ }\r
+ return result_failed;\r
+ } else {\r
+ *sptr = st;\r
+ result_ok.length = st->size;\r
+ return result_ok;\r
+ }\r
+}\r