add OER SEQUENCE decoder
diff --git a/skeletons/Makefile.am b/skeletons/Makefile.am
index df3d3da..9b5b700 100644
--- a/skeletons/Makefile.am
+++ b/skeletons/Makefile.am
@@ -63,6 +63,7 @@
ber_tlv_tag.c ber_tlv_tag.h \
constr_CHOICE.c constr_CHOICE.h \
constr_SEQUENCE.c constr_SEQUENCE.h \
+ constr_SEQUENCE_oer.c constr_SEQUENCE_oer.h \
constr_SEQUENCE_OF.c constr_SEQUENCE_OF.h \
constr_SET.c constr_SET.h \
constr_SET_OF.c constr_SET_OF.h \
diff --git a/skeletons/constr_SEQUENCE.h b/skeletons/constr_SEQUENCE.h
index c2aeb66..f20381a 100644
--- a/skeletons/constr_SEQUENCE.h
+++ b/skeletons/constr_SEQUENCE.h
@@ -6,6 +6,7 @@
#define _CONSTR_SEQUENCE_H_
#include <asn_application.h>
+#include <constr_SEQUENCE_oer.h>
#ifdef __cplusplus
extern "C" {
diff --git a/skeletons/constr_SEQUENCE_oer.c b/skeletons/constr_SEQUENCE_oer.c
new file mode 100644
index 0000000..18fefdf
--- /dev/null
+++ b/skeletons/constr_SEQUENCE_oer.c
@@ -0,0 +1,374 @@
+/*
+ * 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 <constr_SEQUENCE.h>
+#include <errno.h>
+
+/*
+ * This macro "eats" the part of the buffer which is definitely "consumed",
+ * i.e. was correctly converted into local representation or rightfully skipped.
+ */
+#undef ADVANCE
+#define ADVANCE(num_bytes) \
+ do { \
+ size_t num = num_bytes; \
+ ptr = ((const char *)ptr) + num; \
+ size -= num; \
+ consumed_myself += num; \
+ } while(0)
+
+/*
+ * Switch to the next phase of parsing.
+ */
+#undef NEXT_PHASE
+#undef PHASE_OUT
+#define NEXT_PHASE(ctx) \
+ do { \
+ ctx->phase++; \
+ ctx->step = 0; \
+ } while(0)
+
+/*
+ * Check whether we are inside the extensions group.
+ */
+#define IN_EXTENSION_GROUP(specs, memb_idx) \
+ ( ((memb_idx) > (specs)->ext_after) \
+ &&((memb_idx) < (specs)->ext_before))
+
+/*
+ * Return a standardized complex structure.
+ */
+#undef RETURN
+#define RETURN(_code) do { \
+ rval.code = _code; \
+ rval.consumed = consumed_myself;\
+ return rval; \
+ } while(0)
+
+asn_dec_rval_t
+SEQUENCE_decode_oer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+ asn_oer_constraints_t *constraints, void **struct_ptr,
+ const void *ptr, size_t size) {
+ asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics;
+ asn_dec_rval_t rval = {RC_OK, 0};
+ void *st = *struct_ptr; /* Target structure */
+ asn_struct_ctx_t *ctx; /* Decoder context */
+ size_t consumed_myself = 0; /* Consumed bytes from ptr. */
+
+
+ (void)opt_codec_ctx;
+ (void)specs;
+
+ /*
+ * Create the target structure if it is not present already.
+ */
+ if(st == 0) {
+ st = *struct_ptr = CALLOC(1, specs->struct_size);
+ if(st == 0) {
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * Restore parsing context.
+ */
+ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
+ if(ctx->ptr == 0) {
+ ctx->ptr = CALLOC(1, sizeof(asn_per_data_t));
+ if(!ctx->ptr) {
+ RETURN(RC_FAIL);
+ }
+ }
+
+ /*
+ * Start to parse where left previously.
+ */
+ switch(ctx->phase) {
+ case 0: {
+ /*
+ * Fetch preamble.
+ */
+ asn_per_data_t *preamble = ctx->ptr;
+ int has_extensions = (specs->ext_before >= 0);
+ size_t preamble_bits = (has_extensions + specs->roms_count);
+ size_t preamble_bytes = (preamble_bits >> 3);
+ uint8_t *pbytes;
+
+ if(size < preamble_bytes) {
+ ASN__DECODE_STARVED;
+ }
+
+ pbytes = MALLOC(preamble_bytes + 1);
+ if(!pbytes) {
+ RETURN(RC_FAIL);
+ }
+ preamble->buffer = (const void *)pbytes;
+ memcpy(pbytes, ptr, preamble_bytes);
+ pbytes[preamble_bytes] = '\0'; /* Just in case */
+ preamble->nboff = has_extensions;
+ preamble->nbits = preamble_bits;
+ ADVANCE(preamble_bytes);
+ }
+ NEXT_PHASE(ctx);
+ /* FALL THROUGH */
+ case 1: {
+ /* Decode components of the extension root */
+ asn_per_data_t *preamble = ctx->ptr;
+ size_t edx;
+
+ for(edx = (ctx->step >> 1); edx < td->elements_count;
+ edx++, ctx->step = (ctx->step & ~1) + 2) {
+ asn_TYPE_member_t *elm = &td->elements[edx];
+ void **memb_ptr2; /* Pointer to a pointer to a memmber */
+
+ if(ctx->step & 1) {
+ goto microphase2_decode_continues;
+ }
+
+
+ if(IN_EXTENSION_GROUP(specs, edx)) {
+ /* Ignore non-root components in PHASE 1 */
+ continue;
+ }
+
+ if(elm->optional) {
+ int32_t present = per_get_few_bits(preamble, 1);
+ if(present < 0) {
+ RETURN(RC_FAIL);
+ } else if(present == 0) {
+ if(elm->default_value) {
+ if(elm->flags & ATF_POINTER) {
+ /* Member is a pointer to another structure */
+ memb_ptr2 =
+ (void **)((char *)st + elm->memb_offset);
+ } else {
+ void *memb_ptr = (char *)st + elm->memb_offset;
+ memb_ptr2 = &memb_ptr;
+ }
+ /* Fill-in DEFAULT */
+ if(elm->default_value(1, memb_ptr2)) {
+ RETURN(RC_FAIL);
+ }
+ }
+ /* The member is not present. */
+ continue;
+ }
+ /* Present OPTIONAL or DEFAULT component. */
+ }
+
+ /*
+ * MICROPHASE 2: Invoke the member-specific decoder.
+ */
+ ctx->step |= 1; /* Confirm entering next microphase */
+ microphase2_decode_continues:
+ if(elm->flags & ATF_POINTER) {
+ /* Member is a pointer to another structure */
+ memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+ } else {
+ void *memb_ptr = (char *)st + elm->memb_offset;
+ memb_ptr2 = &memb_ptr;
+ }
+
+ rval = elm->type->oer_decoder(opt_codec_ctx, elm->type,
+ elm->oer_constraints, memb_ptr2, ptr,
+ size);
+ switch(rval.code) {
+ case RC_OK:
+ ADVANCE(rval.consumed);
+ break;
+ case RC_WMORE:
+ ADVANCE(rval.consumed);
+ RETURN(RC_WMORE);
+ case RC_FAIL:
+ RETURN(RC_FAIL);
+ }
+ } /* for(all root members) */
+
+ }
+ NEXT_PHASE(ctx);
+ /* FALL THROUGH */
+ case 2: {
+ /* Cleanup preamble. */
+ asn_per_data_t *preamble = ctx->ptr;
+ asn_per_data_t *extadds;
+ int has_extensions = (specs->ext_before >= 0);
+ int extensions_present =
+ has_extensions && (((const uint8_t *)preamble->buffer)[0] & 0x80);
+ uint8_t unused_bits;
+ size_t len = 0;
+ ssize_t len_len;
+ uint8_t *ebytes;
+
+ union {
+ const uint8_t *cptr;
+ uint8_t *uptr;
+ } unconst;
+ unconst.cptr = preamble->buffer;
+ FREEMEM(unconst.uptr);
+ preamble->buffer = 0;
+
+ if(!extensions_present) {
+ ctx->phase = 10;
+ RETURN(RC_OK);
+ }
+
+ /*
+ * X.696 (08/2015) #16.1 (c), #16.4
+ * Read in the extension addition presence bitmap.
+ */
+
+ len_len = oer_fetch_length(ptr, size, &len);
+ if(len_len > 0) {
+ ADVANCE(len_len);
+ } if(len_len < 0) {
+ RETURN(RC_FAIL);
+ } else {
+ RETURN(RC_WMORE);
+ }
+
+ if(len == 0) {
+ /* 16.4.1-2 */
+ RETURN(RC_FAIL);
+ } else if(len > size) {
+ RETURN(RC_WMORE);
+ }
+
+ /* Account for unused bits */
+ unused_bits = 0x7 & *(const uint8_t *)ptr;
+ ADVANCE(1);
+ len--;
+ if(unused_bits && len == 0) {
+ RETURN(RC_FAIL);
+ }
+
+ /* Get the extensions map */
+ ebytes = MALLOC(len + 1);
+ if(!ebytes) {
+ RETURN(RC_FAIL);
+ }
+ memcpy(ebytes, ptr, len);
+ ebytes[len] = '\0';
+
+ extadds = preamble;
+ memset(extadds, 0, sizeof(*extadds));
+ extadds->buffer = ebytes;
+ extadds->nboff = 0;
+ extadds->nbits = 8 * len - unused_bits;
+
+ ADVANCE(len);
+ }
+ NEXT_PHASE(ctx);
+ ctx->step = (specs->ext_after + 1);
+ /* Fall through */
+ case 3:
+ for(; ctx->step < specs->ext_before; ctx->step++) {
+ asn_per_data_t *extadds = ctx->ptr;
+ size_t edx = ctx->step;
+ asn_TYPE_member_t *elm = &td->elements[edx];
+ void **memb_ptr2;
+
+ if(elm->flags & ATF_POINTER) {
+ /* Member is a pointer to another structure */
+ memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+ } else {
+ void *memb_ptr = (char *)st + elm->memb_offset;
+ memb_ptr2 = &memb_ptr;
+ assert(elm->flags & ATF_POINTER); /* Extensions are indirect */
+ }
+
+ switch(per_get_few_bits(extadds, 1)) {
+ case -1:
+ /*
+ * Not every one of our extensions is known to the remote side.
+ * Continue filling in their defaults though.
+ */
+ /* Fall through */
+ case 0:
+ /* Fill-in DEFAULT */
+ if(elm->default_value && elm->default_value(1, memb_ptr2)) {
+ RETURN(RC_FAIL);
+ }
+ continue;
+ case 1: {
+ /* Read OER open type */
+ ssize_t ot_size = oer_open_type_get(opt_codec_ctx, elm->type,
+ elm->oer_constraints,
+ memb_ptr2, ptr, size);
+ if(ot_size > 0) {
+ ADVANCE(ot_size);
+ } else if(ot_size < 0) {
+ RETURN(RC_FAIL);
+ } else {
+ /* Roll back open type parsing */
+ per_get_undo(extadds, 1);
+ ASN_STRUCT_FREE(*elm->type, *memb_ptr2);
+ *memb_ptr2 = NULL;
+ RETURN(RC_WMORE);
+ }
+ break;
+ }
+ default:
+ RETURN(RC_FAIL);
+ }
+ }
+
+ NEXT_PHASE(ctx);
+ /* Fall through */
+ case 4:
+ /* Read in the rest of Open Types while ignoring them */
+ for(;;) {
+ asn_per_data_t *extadds = ctx->ptr;
+ switch(per_get_few_bits(extadds, 1)) {
+ case 0:
+ continue;
+ case 1: {
+ ssize_t slurped = oer_open_type_slurp(ptr, size);
+ if(slurped > 0) {
+ ADVANCE(slurped);
+ } else if(slurped < 0) {
+ RETURN(RC_FAIL);
+ } else {
+ per_get_undo(extadds, 1);
+ RETURN(RC_WMORE);
+ }
+ continue;
+ }
+ case -1:
+ /* No more Open Type encoded components */
+ break;
+ default:
+ RETURN(RC_FAIL);
+ }
+ break;
+ }
+ }
+
+ return rval;
+}
+
+/*
+ * Encode as Canonical OER.
+ */
+asn_enc_rval_t
+SEQUENCE_encode_oer(asn_TYPE_descriptor_t *td,
+ asn_oer_constraints_t *constraints, void *sptr,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ asn_enc_rval_t er;
+ const uint8_t *buf;
+ const uint8_t *end;
+ size_t useful_bytes;
+ size_t req_bytes = 0;
+ int encode_as_unsigned;
+ int sign = 0;
+
+ er.encoded = -1;
+
+ return er;
+}
+
+#endif /* ASN_DISABLE_OER_SUPPORT */
diff --git a/skeletons/constr_SEQUENCE_oer.h b/skeletons/constr_SEQUENCE_oer.h
new file mode 100644
index 0000000..dce71be
--- /dev/null
+++ b/skeletons/constr_SEQUENCE_oer.h
@@ -0,0 +1,20 @@
+/*-
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef CONSTR_SEQUENCE_OER_H
+#define CONSTR_SEQUENCE_OER_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <asn_application.h>
+#include <asn_codecs.h>
+
+oer_type_decoder_f SEQUENCE_decode_oer;
+oer_type_encoder_f SEQUENCE_encode_oer;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* CONSTR_SEQUENCE_OER_H */
diff --git a/skeletons/oer_decoder.h b/skeletons/oer_decoder.h
index c2dc560..33acb87 100644
--- a/skeletons/oer_decoder.h
+++ b/skeletons/oer_decoder.h
@@ -2,8 +2,8 @@
* Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
-#ifndef _OER_DECODER_H_
-#define _OER_DECODER_H_
+#ifndef OER_DECODER_H
+#define OER_DECODER_H
#include <asn_application.h>
#include <oer_support.h>
@@ -37,8 +37,30 @@
const void *buf_ptr,
size_t size);
+/*
+ * Swallow the Open Type (X.696 (08/2015), #30) into /dev/null.
+ * RETURN VALUES:
+ * 0: More data expected than bufptr contains.
+ * -1: Fatal error deciphering length.
+ * >0: Number of bytes used from bufptr.
+ */
+ssize_t oer_open_type_slurp(const void *bufptr, size_t size);
+
+/*
+ * Read the Open Type (X.696 (08/2015), #30).
+ * RETURN VALUES:
+ * 0: More data expected than bufptr contains.
+ * -1: Fatal error deciphering length.
+ * >0: Number of bytes used from bufptr.
+ */
+ssize_t oer_open_type_get(asn_codec_ctx_t *opt_codec_ctx,
+ struct asn_TYPE_descriptor_s *td,
+ asn_oer_constraints_t *constraints, void **struct_ptr,
+ const void *bufptr, size_t size);
+
+
#ifdef __cplusplus
}
#endif
-#endif /* _OER_DECODER_H_ */
+#endif /* OER_DECODER_H */
diff --git a/skeletons/oer_encoder.h b/skeletons/oer_encoder.h
index 08d0d4c..6d33f1c 100644
--- a/skeletons/oer_encoder.h
+++ b/skeletons/oer_encoder.h
@@ -2,8 +2,8 @@
* Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
-#ifndef _OER_ENCODER_H_
-#define _OER_ENCODER_H_
+#ifndef OER_ENCODER_H
+#define OER_ENCODER_H
#include <asn_application.h>
@@ -48,4 +48,4 @@
}
#endif
-#endif /* _OER_ENCODER_H_ */
+#endif /* OER_ENCODER_H */
diff --git a/skeletons/oer_support.h b/skeletons/oer_support.h
index 727d7db..2a7fcb9 100644
--- a/skeletons/oer_support.h
+++ b/skeletons/oer_support.h
@@ -3,8 +3,8 @@
* All rights reserved.
* Redistribution and modifications are oermitted subject to BSD license.
*/
-#ifndef _OER_SUPPORT_H_
-#define _OER_SUPPORT_H_
+#ifndef OER_SUPPORT_H
+#define OER_SUPPORT_H
#include <asn_system.h> /* Platform-specific types */
@@ -30,7 +30,7 @@
/*
- * Fetch the length determinant (X.696 08/2015, #8.6) into *len_r.
+ * Fetch the length determinant (X.696 (08/2015), #8.6) into *len_r.
* RETURN VALUES:
* 0: More data expected than bufptr contains.
* -1: Fatal error deciphering length.
@@ -49,4 +49,4 @@
}
#endif
-#endif /* _OER_SUPPORT_H_ */
+#endif /* OER_SUPPORT_H */