blob: 0ddf9d28780359000ec6344a8cd7b48c5b47c3d5 [file] [log] [blame]
Lev Walkin9a1736d2017-08-27 23:46:34 -07001/*
2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3 * All rights reserved.
4 * Redistribution and modifications are permitted subject to BSD license.
5 */
6#ifndef ASN_DISABLE_OER_SUPPORT
7
8#include <asn_internal.h>
9#include <constr_CHOICE.h>
10#include <errno.h>
11
12/*
13 * Return a standardized complex structure.
14 */
15#undef RETURN
16#define RETURN(_code) \
17 do { \
18 rval.code = _code; \
19 rval.consumed = consumed_myself; \
20 return rval; \
21 } while(0)
22
23#undef ADVANCE
24#define ADVANCE(num_bytes) \
25 do { \
26 size_t num = num_bytes; \
27 ptr = ((const char *)ptr) + num; \
28 size -= num; \
29 consumed_myself += num; \
30 } while(0)
31
32/*
33 * Switch to the next phase of parsing.
34 */
35#undef NEXT_PHASE
36#define NEXT_PHASE(ctx) \
37 do { \
38 ctx->phase++; \
39 ctx->step = 0; \
40 } while(0)
41
42
43/*
44 * Tags are canonically sorted in the tag to member table.
45 */
46static int
47_search4tag(const void *ap, const void *bp) {
48 const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap;
49 const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp;
50
51 int a_class = BER_TAG_CLASS(a->el_tag);
52 int b_class = BER_TAG_CLASS(b->el_tag);
53
54 if(a_class == b_class) {
55 ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
56 ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
57
58 if(a_value == b_value)
59 return 0;
60 else if(a_value < b_value)
61 return -1;
62 else
63 return 1;
64 } else if(a_class < b_class) {
65 return -1;
66 } else {
67 return 1;
68 }
69}
70
71/*
72 * X.696 (08/2015) #8.7 Encoding of tags
73 */
74static ssize_t
75oer_fetch_tag(const void *ptr, size_t size, ber_tlv_tag_t *tag_r) {
76 ber_tlv_tag_t val;
77 ber_tlv_tag_t tclass;
78 size_t skipped;
79
80 if(size == 0)
81 return 0;
82
83 val = *(const uint8_t *)ptr;
84 tclass = (val >> 6);
85 if((val & 0x3F) != 0x3F) {
86 /* #8.7.1 */
87 *tag_r = ((val & 0x3F) << 2) | tclass;
88 fprintf(stderr, "byte %02x, tag_r = %d, %s", *(const uint8_t *)ptr,
89 *tag_r, ber_tlv_tag_string(*tag_r));
90 return 1;
91 }
92
93 /*
94 * Each octet contains 7 bits of useful information.
95 * The MSB is 0 if it is the last octet of the tag.
96 */
97 for(val = 0, ptr = ((const char *)ptr) + 1, skipped = 2; skipped <= size;
98 ptr = ((const char *)ptr) + 1, skipped++) {
99 unsigned int oct = *(const uint8_t *)ptr;
100 if(oct & 0x80) {
101 val = (val << 7) | (oct & 0x7F);
102 /*
103 * Make sure there are at least 9 bits spare
104 * at the MS side of a value.
105 */
106 if(val >> ((8 * sizeof(val)) - 9)) {
107 /*
108 * We would not be able to accomodate
109 * any more tag bits.
110 */
111 return -1;
112 }
113 } else {
114 val = (val << 7) | oct;
115 *tag_r = (val << 2) | tclass;
116 return skipped;
117 }
118 }
119
120
121 return 0; /* Want more */
122}
123
124
125asn_dec_rval_t
126CHOICE_decode_oer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
127 const asn_oer_constraints_t *constraints, void **struct_ptr,
128 const void *ptr, size_t size) {
129 /*
130 * Bring closer parts of structure description.
131 */
132 asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
133 asn_TYPE_member_t *elements = td->elements;
134
135 /*
136 * Parts of the structure being constructed.
137 */
138 void *st = *struct_ptr; /* Target structure. */
139 asn_struct_ctx_t *ctx; /* Decoder context */
140
141 asn_dec_rval_t rval; /* Return code from subparsers */
142
143 ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
144
145 (void)constraints;
146
147 ASN_DEBUG("Decoding %s as CHOICE", td->name);
148
149 /*
150 * Create the target structure if it is not present already.
151 */
152 if(st == 0) {
153 st = *struct_ptr = CALLOC(1, specs->struct_size);
154 if(st == 0) {
155 RETURN(RC_FAIL);
156 }
157 }
158
159 /*
160 * Restore parsing context.
161 */
162 ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
163 switch(ctx->phase) {
164 case 0: {
165 /*
166 * Discover the tag.
167 */
168 ber_tlv_tag_t tlv_tag; /* T from TLV */
169 ssize_t tag_len; /* Length of TLV's T */
170
171 tag_len = oer_fetch_tag(ptr, size, &tlv_tag);
172 switch(tag_len) {
173 case 0:
174 ASN__DECODE_STARVED;
175 case -1:
176 ASN__DECODE_FAILED;
177 }
178
179 do {
180 const asn_TYPE_tag2member_t *t2m;
181 asn_TYPE_tag2member_t key = {tlv_tag, 0, 0, 0};
182
183 t2m = (const asn_TYPE_tag2member_t *)bsearch(
184 &key, specs->tag2el, specs->tag2el_count,
185 sizeof(specs->tag2el[0]), _search4tag);
186 if(t2m) {
187 /*
188 * Found the element corresponding to the tag.
189 */
190 NEXT_PHASE(ctx);
191 ctx->step = t2m->el_no;
192 break;
193 } else if(specs->ext_start == -1) {
194 ASN_DEBUG(
195 "Unexpected tag %s "
196 "in non-extensible CHOICE %s",
197 ber_tlv_tag_string(tlv_tag), td->name);
198 RETURN(RC_FAIL);
199 } else {
200 /* Skip open type extension */
201 RETURN(RC_FAIL);
202 }
203 } while(0);
204
205
206 ADVANCE(tag_len);
207 }
208 case 1: {
209 asn_TYPE_member_t *elm = &elements[ctx->step]; /* CHOICE's element */
210 void *memb_ptr; /* Pointer to the member */
211 void **memb_ptr2; /* Pointer to that pointer */
212
213 /*
214 * Compute the position of the member inside a structure,
215 * and also a type of containment (it may be contained
216 * as pointer or using inline inclusion).
217 */
218 if(elm->flags & ATF_POINTER) {
219 /* Member is a pointer to another structure */
220 memb_ptr2 = (void **)((char *)st + elm->memb_offset);
221 } else {
222 /*
223 * A pointer to a pointer
224 * holding the start of the structure
225 */
226 memb_ptr = (char *)st + elm->memb_offset;
227 memb_ptr2 = &memb_ptr;
228 }
229
230 /* Set presence to be able to free it properly at any time */
231 (void)CHOICE_variant_set_presence(td, st, ctx->step + 1);
232
233 if(specs->ext_start <= ctx->step) {
234 /* We're in the extensions group. #20.2 requires Open Type */
235 RETURN(RC_FAIL);
236 }
237
238 rval = elm->type->op->oer_decoder(opt_codec_ctx, elm->type,
239 elm->oer_constraints, memb_ptr2, ptr,
240 size);
241 rval.consumed += consumed_myself;
242 return rval;
243 }
244 }
245
246 RETURN(RC_FAIL);
247}
248
249/*
250 * Encode as Canonical OER.
251 */
252asn_enc_rval_t
253CHOICE_encode_oer(asn_TYPE_descriptor_t *td,
254 const asn_oer_constraints_t *constraints, void *sptr,
255 asn_app_consume_bytes_f *cb, void *app_key) {
256
257 (void)constraints;
258 (void)cb;
259 (void)app_key;
260
261 ASN__ENCODE_FAILED;
262}
263
264#endif /* ASN_DISABLE_OER_SUPPORT */