--- /dev/null
+/*
+ * 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 */