| /* |
| * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. |
| * All rights reserved. |
| * Redistribution and modifications are permitted subject to BSD license. |
| */ |
| #ifndef ASN_DISABLE_OER_SUPPORT |
| |
| #include <asn_internal.h> |
| #include <NativeEnumerated.h> |
| #include <errno.h> |
| |
| static long |
| asn__nativeenumerated_convert(const uint8_t *b, const uint8_t *end) { |
| unsigned long value; |
| |
| /* Perform the sign initialization */ |
| /* Actually value = -(*b >> 7); gains nothing, yet unreadable! */ |
| if((*b >> 7)) { |
| value = (unsigned long)(-1); |
| } else { |
| value = 0; |
| } |
| |
| /* Conversion engine */ |
| for(; b < end; b++) { |
| value = (value << 8) | *b; |
| } |
| |
| return value; |
| } |
| |
| asn_dec_rval_t |
| NativeEnumerated_decode_oer(const asn_codec_ctx_t *opt_codec_ctx, |
| const asn_TYPE_descriptor_t *td, |
| const asn_oer_constraints_t *constraints, |
| void **nint_ptr, const void *ptr, size_t size) { |
| asn_dec_rval_t rval = {RC_OK, 0}; |
| long *native = (long *)*nint_ptr; |
| const uint8_t *b = ptr; |
| |
| (void)opt_codec_ctx; |
| (void)constraints; |
| |
| if(size < 1) { |
| ASN__DECODE_STARVED; |
| } |
| |
| if((*b & 0x80) == 0) { |
| /* |
| * X.696 (08/2015) #11.2 Short form for Enumerated. |
| */ |
| if(!native) { |
| native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native))); |
| if(!native) ASN__DECODE_FAILED; |
| } |
| |
| *native = *b; |
| rval.consumed = 1; |
| } else { |
| /* |
| * X.696 (08/2015) #11.4 Long form for Enumerated. |
| */ |
| size_t length = *b & 0x7f; |
| const uint8_t *bend; |
| long value; |
| |
| if(length < 1 || length > sizeof(*native)) { |
| ASN__DECODE_FAILED; |
| } |
| if((1 + length) > size) { |
| ASN__DECODE_STARVED; |
| } |
| b++; |
| bend = b + length; |
| |
| value = asn__nativeenumerated_convert(b, bend); |
| if(value < 0) { |
| const asn_INTEGER_specifics_t *specs = |
| (const asn_INTEGER_specifics_t *)td->specifics; |
| if(specs && specs->field_unsigned) { |
| ASN__DECODE_FAILED; |
| } |
| } |
| |
| if(!native) { |
| native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native))); |
| if(!native) ASN__DECODE_FAILED; |
| } |
| |
| *native = value; |
| |
| rval.consumed = (1 + length); |
| } |
| |
| return rval; |
| } |
| |
| /* |
| * Encode as Canonical OER. |
| */ |
| asn_enc_rval_t |
| NativeEnumerated_encode_oer(const asn_TYPE_descriptor_t *td, |
| const asn_oer_constraints_t *constraints, |
| const void *sptr, asn_app_consume_bytes_f *cb, |
| void *app_key) { |
| asn_enc_rval_t er = {0,0,0}; |
| long native; |
| |
| (void)constraints; |
| |
| if(!sptr) ASN__ENCODE_FAILED; |
| |
| native = *(const long *)sptr; |
| |
| if(native >= 0 && native <= 127) { |
| /* #11.2 Short form */ |
| uint8_t b = native; |
| er.encoded = 1; |
| if(cb(&b, er.encoded, app_key) < 0) { |
| ASN__ENCODE_FAILED; |
| } |
| ASN__ENCODED_OK(er); |
| } else { |
| /* #11.2 Long form */ |
| uint8_t buf[1 + sizeof(native)]; |
| uint8_t *b = &buf[sizeof(native)]; /* Last addressable */ |
| long final_pattern = -1 * (native < 0); |
| |
| for(;;) { |
| *b-- = native; |
| native >>= 8; |
| if(native == final_pattern) { |
| if(final_pattern) { |
| if((b[1] & 0x80)) break; |
| } else { |
| if(!(b[1] & 0x80)) break; |
| } |
| } |
| } |
| *b = 0x80 | (&buf[sizeof(native)] - b); |
| er.encoded = 1 + (&buf[sizeof(native)] - b); |
| if(cb(b, er.encoded, app_key) < 0) { |
| ASN__ENCODE_FAILED; |
| } |
| ASN__ENCODED_OK(er); |
| } |
| } |
| |
| #endif /* ASN_DISABLE_OER_SUPPORT */ |