| /* |
| * 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_SET_OF.h> |
| #include <asn_SET_OF.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 |
| #define NEXT_PHASE(ctx) \ |
| do { \ |
| ctx->phase++; \ |
| ctx->step = 0; \ |
| } while(0) |
| #undef SET_PHASE |
| #define SET_PHASE(ctx, value) \ |
| do { \ |
| ctx->phase = value; \ |
| ctx->step = 0; \ |
| } while(0) |
| |
| /* |
| * Return a standardized complex structure. |
| */ |
| #undef RETURN |
| #define RETURN(_code) \ |
| do { \ |
| asn_dec_rval_t rval; \ |
| rval.code = _code; \ |
| rval.consumed = consumed_myself; \ |
| return rval; \ |
| } while(0) |
| |
| /* |
| * The SEQUENCE OF and SET OF values utilize a "quantity field". |
| * It is is a pointless combination of #8.6 (length determinant, capable |
| * of encoding tiny and huge numbers in the shortest possible number of octets) |
| * and the variable sized integer. What could have been encoded by #8.6 alone |
| * is required to be encoded by #8.6 followed by that number of unsigned octets. |
| * This doesn't make too much sense. It seems that the original version of OER |
| * standard have been using the unconstrained unsigned integer as a quantity |
| * field, and this legacy have gone through ISO/ITU-T standardization process. |
| */ |
| static ssize_t |
| oer_fetch_quantity(const void *ptr, size_t size, size_t *qty_r) { |
| size_t len = 0; |
| size_t qty; |
| |
| ssize_t len_len = oer_fetch_length(ptr, size, &len); |
| if(len_len <= 0) { |
| *qty_r = 0; |
| return len_len; |
| } |
| |
| if((len_len + len) > size) { |
| *qty_r = 0; |
| return 0; |
| } |
| |
| const uint8_t *b = (const uint8_t *)ptr + len_len; |
| const uint8_t *bend = b + len_len; |
| |
| |
| /* Skip the leading 0-bytes */ |
| for(; b < bend && *b == 0; b++) { |
| } |
| |
| |
| if((bend - b) > (ssize_t)sizeof(size_t)) { |
| /* Length is not representable by the native size_t type */ |
| *qty_r = 0; |
| return -1; |
| } |
| |
| for(qty = 0; b < bend; b++) { |
| qty = (qty << 8) + *b; |
| } |
| |
| if(qty > RSIZE_MAX) { /* A bit of C11 validation */ |
| *qty_r = 0; |
| return -1; |
| } |
| |
| *qty_r = qty; |
| assert((size_t)len_len + len == (size_t)(bend - (const uint8_t *)ptr)); |
| return len_len + len; |
| } |
| |
| asn_dec_rval_t |
| SET_OF_decode_oer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, |
| const asn_oer_constraints_t *constraints, void **struct_ptr, |
| const void *ptr, size_t size) { |
| asn_SET_OF_specifics_t *specs = (asn_SET_OF_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)constraints; |
| |
| /* |
| * 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); |
| |
| /* |
| * Start to parse where left previously. |
| */ |
| switch(ctx->phase) { |
| case 0: { |
| /* |
| * Fetch number of elements to decode. |
| */ |
| size_t length = 0; |
| size_t len_size = oer_fetch_quantity(ptr, size, &length); |
| switch(len_size) { |
| case 0: |
| RETURN(RC_WMORE); |
| case -1: |
| RETURN(RC_FAIL); |
| default: |
| ASN_DEBUG("ptr[] = %02x, advancing %zu, length=%zu", *(const uint8_t *)ptr, len_size, length); |
| ADVANCE(len_size); |
| ctx->left = length; |
| } |
| } |
| NEXT_PHASE(ctx); |
| /* FALL THROUGH */ |
| case 1: { |
| /* Decode components of the extension root */ |
| asn_TYPE_member_t *elm = td->elements; |
| asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); |
| |
| assert(td->elements_count == 1); |
| |
| ASN_DEBUG("OER SET OF %s Decoding PHASE 1", td->name); |
| |
| for(; ctx->left > 0; ctx->left--) { |
| asn_dec_rval_t rv = elm->type->op->oer_decoder( |
| opt_codec_ctx, elm->type, elm->oer_constraints, &ctx->ptr, ptr, |
| size); |
| ADVANCE(rv.consumed); |
| switch(rv.code) { |
| case RC_OK: |
| if(ASN_SET_ADD(list, ctx->ptr) != 0) { |
| RETURN(RC_FAIL); |
| } else { |
| ctx->ptr = 0; |
| break; |
| } |
| case RC_WMORE: |
| RETURN(RC_WMORE); |
| case RC_FAIL: |
| ASN_STRUCT_FREE(*elm->type, ctx->ptr); |
| ctx->ptr = 0; |
| SET_PHASE(ctx, 3); |
| RETURN(RC_FAIL); |
| } |
| } |
| /* Decoded decently. */ |
| NEXT_PHASE(ctx); |
| } |
| /* Fall through */ |
| case 2: |
| /* Ignore fully decoded */ |
| assert(ctx->left == 0); |
| RETURN(RC_OK); |
| case 3: |
| /* Failed to decode. */ |
| RETURN(RC_FAIL); |
| } |
| |
| return rval; |
| } |
| |
| /* |
| * Encode as Canonical OER. |
| */ |
| asn_enc_rval_t |
| SET_OF_encode_oer(asn_TYPE_descriptor_t *td, |
| const asn_oer_constraints_t *constraints, void *sptr, |
| asn_app_consume_bytes_f *cb, void *app_key) { |
| size_t computed_size = 0; |
| |
| (void)constraints; |
| (void)cb; |
| (void)app_key; |
| |
| { |
| asn_enc_rval_t er = {computed_size, td, sptr}; |
| ASN__ENCODED_OK(er); |
| } |
| } |
| |
| #endif /* ASN_DISABLE_OER_SUPPORT */ |