2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
4 * Redistribution and modifications are permitted subject to BSD license.
6 #ifndef ASN_DISABLE_OER_SUPPORT
8 #include <asn_internal.h>
9 #include <constr_SET_OF.h>
10 #include <asn_SET_OF.h>
14 * This macro "eats" the part of the buffer which is definitely "consumed",
15 * i.e. was correctly converted into local representation or rightfully skipped.
18 #define ADVANCE(num_bytes) \
20 size_t num = num_bytes; \
21 ptr = ((const char *)ptr) + num; \
23 consumed_myself += num; \
27 * Switch to the next phase of parsing.
30 #define NEXT_PHASE(ctx) \
36 #define SET_PHASE(ctx, value) \
43 * Return a standardized complex structure.
46 #define RETURN(_code) \
48 asn_dec_rval_t rval; \
50 rval.consumed = consumed_myself; \
55 * The SEQUENCE OF and SET OF values utilize a "quantity field".
56 * It is is a pointless combination of #8.6 (length determinant, capable
57 * of encoding tiny and huge numbers in the shortest possible number of octets)
58 * and the variable sized integer. What could have been encoded by #8.6 alone
59 * is required to be encoded by #8.6 followed by that number of unsigned octets.
60 * This doesn't make too much sense. It seems that the original version of OER
61 * standard have been using the unconstrained unsigned integer as a quantity
62 * field, and this legacy have gone through ISO/ITU-T standardization process.
65 oer_fetch_quantity(const void *ptr, size_t size, size_t *qty_r) {
71 ssize_t len_len = oer_fetch_length(ptr, size, &len);
77 if((len_len + len) > size) {
82 b = (const uint8_t *)ptr + len_len;
85 /* Skip the leading 0-bytes */
86 for(; b < bend && *b == 0; b++) {
89 if((bend - b) > (ssize_t)sizeof(size_t)) {
90 /* Length is not representable by the native size_t type */
95 for(qty = 0; b < bend; b++) {
96 qty = (qty << 8) + *b;
99 if(qty > RSIZE_MAX) { /* A bit of C11 validation */
105 assert((size_t)len_len + len == (size_t)(bend - (const uint8_t *)ptr));
106 return len_len + len;
110 SET_OF_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
111 const asn_TYPE_descriptor_t *td,
112 const asn_oer_constraints_t *constraints, void **struct_ptr,
113 const void *ptr, size_t size) {
114 const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics;
115 asn_dec_rval_t rval = {RC_OK, 0};
116 void *st = *struct_ptr; /* Target structure */
117 asn_struct_ctx_t *ctx; /* Decoder context */
118 size_t consumed_myself = 0; /* Consumed bytes from ptr. */
122 if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
126 * Create the target structure if it is not present already.
129 st = *struct_ptr = CALLOC(1, specs->struct_size);
136 * Restore parsing context.
138 ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
141 * Start to parse where left previously.
146 * Fetch number of elements to decode.
149 size_t len_size = oer_fetch_quantity(ptr, size, &length);
163 /* Decode components of the extension root */
164 asn_TYPE_member_t *elm = td->elements;
165 asn_anonymous_set_ *list = _A_SET_FROM_VOID(st);
166 const void *base_ptr = ptr;
167 ber_tlv_len_t base_ctx_left = ctx->left;
169 assert(td->elements_count == 1);
171 ASN_DEBUG("OER SET OF %s Decoding PHASE 1", td->name);
173 for(; ctx->left > 0; ctx->left--) {
174 asn_dec_rval_t rv = elm->type->op->oer_decoder(
175 opt_codec_ctx, elm->type,
176 elm->encoding_constraints.oer_constraints, &ctx->ptr, ptr,
178 ADVANCE(rv.consumed);
181 if(ASN_SET_ADD(list, ctx->ptr) != 0) {
186 * This check is to avoid compression bomb with
187 * specs like SEQUENCE/SET OF NULL which don't
188 * consume data at all.
190 if(rv.consumed == 0 && base_ptr == ptr
191 && (base_ctx_left - ctx->left) > 200) {
199 ASN_STRUCT_FREE(*elm->type, ctx->ptr);
205 /* Decoded decently. */
210 /* Ignore fully decoded */
211 assert(ctx->left == 0);
214 /* Failed to decode. */
222 oer_put_quantity(size_t qty, asn_app_consume_bytes_f *cb, void *app_key) {
223 uint8_t buf[1 + sizeof(size_t)];
224 uint8_t *b = &buf[sizeof(size_t)]; /* Last addressable */
232 *b = sizeof(buf) - (b-buf) - 1;
233 encoded = sizeof(buf) - (b-buf);
234 if(cb(b, encoded, app_key) < 0)
240 * Encode as Canonical OER.
243 SET_OF_encode_oer(const asn_TYPE_descriptor_t *td,
244 const asn_oer_constraints_t *constraints, const void *sptr,
245 asn_app_consume_bytes_f *cb, void *app_key) {
246 const asn_TYPE_member_t *elm;
247 const asn_anonymous_set_ *list;
248 size_t computed_size = 0;
254 if(!sptr) ASN__ENCODE_FAILED;
257 list = _A_CSET_FROM_VOID(sptr);
259 qty_len = oer_put_quantity(list->count, cb, app_key);
263 computed_size += qty_len;
265 for(n = 0; n < list->count; n++) {
266 void *memb_ptr = list->array[n];
268 er = elm->type->op->oer_encoder(
269 elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb,
274 computed_size += er.encoded;
279 asn_enc_rval_t erval;
280 erval.encoded = computed_size;
281 ASN__ENCODED_OK(erval);
285 #endif /* ASN_DISABLE_OER_SUPPORT */