/* * Copyright (c) 2017 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include asn_dec_rval_t INTEGER_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, const asn_TYPE_descriptor_t *td, const asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { const asn_INTEGER_specifics_t *specs = (const asn_INTEGER_specifics_t *)td->specifics; asn_dec_rval_t rval = { RC_OK, 0 }; INTEGER_t *st = (INTEGER_t *)*sptr; const asn_per_constraint_t *ct; int repeat; (void)opt_codec_ctx; if(!st) { st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); if(!st) ASN__DECODE_FAILED; } if(!constraints) constraints = td->encoding_constraints.per_constraints; ct = constraints ? &constraints->value : 0; if(ct && ct->flags & APC_EXTENSIBLE) { int inext = per_get_few_bits(pd, 1); if(inext < 0) ASN__DECODE_STARVED; if(inext) ct = 0; } FREEMEM(st->buf); st->buf = 0; st->size = 0; if(ct) { if(ct->flags & APC_SEMI_CONSTRAINED) { st->buf = (uint8_t *)CALLOC(1, 2); if(!st->buf) ASN__DECODE_FAILED; st->size = 1; } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) { size_t size = (ct->range_bits + 7) >> 3; st->buf = (uint8_t *)MALLOC(1 + size + 1); if(!st->buf) ASN__DECODE_FAILED; st->size = size; } } /* X.691-2008/11, #13.2.2, constrained whole number */ if(ct && ct->flags != APC_UNCONSTRAINED) { /* #11.5.6 */ ASN_DEBUG("Integer with range %d bits", ct->range_bits); if(ct->range_bits >= 0) { if((size_t)ct->range_bits > 8 * sizeof(uintmax_t)) ASN__DECODE_FAILED; if(specs && specs->field_unsigned) { uintmax_t uvalue = 0; if(uper_get_constrained_whole_number(pd, &uvalue, ct->range_bits)) ASN__DECODE_STARVED; ASN_DEBUG("Got value %lu + low %ld", uvalue, ct->lower_bound); uvalue += ct->lower_bound; if(asn_umax2INTEGER(st, uvalue)) ASN__DECODE_FAILED; } else { uintmax_t uvalue = 0; intmax_t svalue; if(uper_get_constrained_whole_number(pd, &uvalue, ct->range_bits)) ASN__DECODE_STARVED; ASN_DEBUG("Got value %lu + low %ld", uvalue, ct->lower_bound); if(per_imax_range_unrebase(uvalue, ct->lower_bound, ct->upper_bound, &svalue) || asn_imax2INTEGER(st, svalue)) { ASN__DECODE_FAILED; } } return rval; } } else { ASN_DEBUG("Decoding unconstrained integer %s", td->name); } /* X.691, #12.2.3, #12.2.4 */ do { ssize_t len = 0; void *p = NULL; int ret = 0; /* Get the PER length */ len = uper_get_length(pd, -1, 0, &repeat); if(len < 0) ASN__DECODE_STARVED; p = REALLOC(st->buf, st->size + len + 1); if(!p) ASN__DECODE_FAILED; st->buf = (uint8_t *)p; ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len); if(ret < 0) ASN__DECODE_STARVED; st->size += len; } while(repeat); st->buf[st->size] = 0; /* JIC */ /* #12.2.3 */ if(ct && ct->lower_bound) { /* * TODO: replace by in-place arithmetic. */ long value = 0; if(asn_INTEGER2long(st, &value)) ASN__DECODE_FAILED; if(asn_imax2INTEGER(st, value + ct->lower_bound)) ASN__DECODE_FAILED; } return rval; } asn_enc_rval_t INTEGER_encode_uper(const asn_TYPE_descriptor_t *td, const asn_per_constraints_t *constraints, const void *sptr, asn_per_outp_t *po) { const asn_INTEGER_specifics_t *specs = (const asn_INTEGER_specifics_t *)td->specifics; asn_enc_rval_t er = {0,0,0}; const INTEGER_t *st = (const INTEGER_t *)sptr; const uint8_t *buf; const uint8_t *end; const asn_per_constraint_t *ct; union { intmax_t s; uintmax_t u; } value; if(!st || st->size == 0) ASN__ENCODE_FAILED; if(!constraints) constraints = td->encoding_constraints.per_constraints; ct = constraints ? &constraints->value : 0; er.encoded = 0; if(ct) { int inext = 0; if(specs && specs->field_unsigned) { if(asn_INTEGER2umax(st, &value.u)) ASN__ENCODE_FAILED; /* Check proper range */ if(ct->flags & APC_SEMI_CONSTRAINED) { if(value.u < (uintmax_t)ct->lower_bound) inext = 1; } else if(ct->range_bits >= 0) { if(value.u < (uintmax_t)ct->lower_bound || value.u > (uintmax_t)ct->upper_bound) inext = 1; } ASN_DEBUG("Value %lu (%02x/%" ASN_PRI_SIZE ") lb %lu ub %lu %s", value.u, st->buf[0], st->size, ct->lower_bound, ct->upper_bound, inext ? "ext" : "fix"); } else { if(asn_INTEGER2imax(st, &value.s)) ASN__ENCODE_FAILED; /* Check proper range */ if(ct->flags & APC_SEMI_CONSTRAINED) { if(value.s < ct->lower_bound) inext = 1; } else if(ct->range_bits >= 0) { if(value.s < ct->lower_bound || value.s > ct->upper_bound) inext = 1; } ASN_DEBUG("Value %ld (%02x/%" ASN_PRI_SIZE ") lb %ld ub %ld %s", value.s, st->buf[0], st->size, ct->lower_bound, ct->upper_bound, inext ? "ext" : "fix"); } if(ct->flags & APC_EXTENSIBLE) { if(per_put_few_bits(po, inext, 1)) ASN__ENCODE_FAILED; if(inext) ct = 0; } else if(inext) { ASN__ENCODE_FAILED; } } /* X.691-11/2008, #13.2.2, test if constrained whole number */ if(ct && ct->range_bits >= 0) { uintmax_t v; /* #11.5.6 -> #11.3 */ if(specs && specs->field_unsigned) { if(((uintmax_t)ct->lower_bound > (uintmax_t)(ct->upper_bound) || (value.u < (uintmax_t)ct->lower_bound)) || (value.u > (uintmax_t)ct->upper_bound)) { ASN_DEBUG("Value %lu to-be-encoded is outside the bounds [%lu, %lu]!", value.u, ct->lower_bound, ct->upper_bound); ASN__ENCODE_FAILED; } v = value.u - (uintmax_t)ct->lower_bound; } else { if(per_imax_range_rebase(value.s, ct->lower_bound, ct->upper_bound, &v)) { ASN__ENCODE_FAILED; } } ASN_DEBUG("Encoding integer %lu with range %d bits", v, ct->range_bits); if(uper_put_constrained_whole_number_u(po, v, ct->range_bits)) ASN__ENCODE_FAILED; ASN__ENCODED_OK(er); } if(ct && ct->lower_bound) { ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); /* TODO: adjust lower bound */ ASN__ENCODE_FAILED; } for(buf = st->buf, end = st->buf + st->size; buf < end;) { int need_eom = 0; ssize_t mayEncode = uper_put_length(po, end - buf, &need_eom); if(mayEncode < 0) ASN__ENCODE_FAILED; if(per_put_many_bits(po, buf, 8 * mayEncode)) ASN__ENCODE_FAILED; buf += mayEncode; if(need_eom && uper_put_length(po, 0, 0)) ASN__ENCODE_FAILED; } ASN__ENCODED_OK(er); }