SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / constr_CHOICE_ber.c
1 /*
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 #include <asn_internal.h>
7 #include <constr_CHOICE.h>
8
9 /*
10  * Number of bytes left for this structure.
11  * (ctx->left) indicates the number of bytes _transferred_ for the structure.
12  * (size) contains the number of bytes in the buffer passed.
13  */
14 #define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left)
15
16 /*
17  * If the subprocessor function returns with an indication that it wants
18  * more data, it may well be a fatal decoding problem, because the
19  * size is constrained by the <TLV>'s L, even if the buffer size allows
20  * reading more data.
21  * For example, consider the buffer containing the following TLVs:
22  * <T:5><L:1><V> <T:6>...
23  * The TLV length clearly indicates that one byte is expected in V, but
24  * if the V processor returns with "want more data" even if the buffer
25  * contains way more data than the V processor have seen.
26  */
27 #define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size)
28
29 /*
30  * This macro "eats" the part of the buffer which is definitely "consumed",
31  * i.e. was correctly converted into local representation or rightfully skipped.
32  */
33 #undef ADVANCE
34 #define ADVANCE(num_bytes)                \
35     do {                                  \
36         size_t num = num_bytes;           \
37         ptr = ((const char *)ptr) + num;  \
38         size -= num;                      \
39         if(ctx->left >= 0)                \
40             ctx->left -= num;             \
41         consumed_myself += num;           \
42     } while(0)
43
44 /*
45  * Switch to the next phase of parsing.
46  */
47 #undef NEXT_PHASE
48 #define NEXT_PHASE(ctx)  \
49     do {                 \
50         ctx->phase++;    \
51         ctx->step = 0;   \
52     } while(0)
53
54 /*
55  * Return a standardized complex structure.
56  */
57 #undef RETURN
58 #define RETURN(_code)                     \
59     do {                                  \
60         rval.code = _code;                \
61         rval.consumed = consumed_myself;  \
62         return rval;                      \
63     } while(0)
64
65 /*
66  * Tags are canonically sorted in the tag to member table.
67  */
68 static int
69 _search4tag(const void *ap, const void *bp) {
70     const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap;
71     const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp;
72
73     int a_class = BER_TAG_CLASS(a->el_tag);
74     int b_class = BER_TAG_CLASS(b->el_tag);
75
76     if(a_class == b_class) {
77         ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
78         ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
79
80         if(a_value == b_value)
81             return 0;
82         else if(a_value < b_value)
83             return -1;
84         else
85             return 1;
86     } else if(a_class < b_class) {
87         return -1;
88     } else {
89         return 1;
90     }
91 }
92
93 /*
94  * The decoder of the CHOICE type.
95  */
96 asn_dec_rval_t
97 CHOICE_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
98                   const asn_TYPE_descriptor_t *td, void **struct_ptr,
99                   const void *ptr, size_t size, int tag_mode) {
100     /*
101      * Bring closer parts of structure description.
102      */
103     const asn_CHOICE_specifics_t *specs =
104         (const asn_CHOICE_specifics_t *)td->specifics;
105     asn_TYPE_member_t *elements = td->elements;
106
107     /*
108      * Parts of the structure being constructed.
109      */
110     void *st = *struct_ptr;  /* Target structure. */
111     asn_struct_ctx_t *ctx;   /* Decoder context */
112
113     ber_tlv_tag_t tlv_tag;  /* T from TLV */
114     ssize_t tag_len;        /* Length of TLV's T */
115     asn_dec_rval_t rval;    /* Return code from subparsers */
116
117     ssize_t consumed_myself = 0;  /* Consumed bytes from ptr */
118
119     ASN_DEBUG("Decoding %s as CHOICE", td->name);
120
121     /*
122      * Create the target structure if it is not present already.
123      */
124     if(st == 0) {
125         st = *struct_ptr = CALLOC(1, specs->struct_size);
126         if(st == 0) {
127             RETURN(RC_FAIL);
128         }
129     }
130
131     /*
132      * Restore parsing context.
133      */
134     ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
135
136     /*
137      * Start to parse where left previously
138      */
139     switch(ctx->phase) {
140     case 0:
141         /*
142          * PHASE 0.
143          * Check that the set of tags associated with given structure
144          * perfectly fits our expectations.
145          */
146
147         if(tag_mode || td->tags_count) {
148             rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size,
149                                   tag_mode, -1, &ctx->left, 0);
150             if(rval.code != RC_OK) {
151                 ASN_DEBUG("%s tagging check failed: %d",
152                           td->name, rval.code);
153                 return rval;
154             }
155
156             if(ctx->left >= 0) {
157                 /* ?Subtracted below! */
158                 ctx->left += rval.consumed;
159             }
160             ADVANCE(rval.consumed);
161         } else {
162             ctx->left = -1;
163         }
164
165         NEXT_PHASE(ctx);
166
167         ASN_DEBUG("Structure consumes %ld bytes, buffer %ld",
168                   (long)ctx->left, (long)size);
169
170         /* Fall through */
171     case 1:
172         /*
173          * Fetch the T from TLV.
174          */
175         tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
176         ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len);
177         switch(tag_len) {
178         case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
179             /* Fall through */
180         case -1: RETURN(RC_FAIL);
181         }
182
183         do {
184             const asn_TYPE_tag2member_t *t2m;
185             asn_TYPE_tag2member_t key;
186
187             key.el_tag = tlv_tag;
188             t2m = (const asn_TYPE_tag2member_t *)bsearch(&key,
189                     specs->tag2el, specs->tag2el_count,
190                     sizeof(specs->tag2el[0]), _search4tag);
191             if(t2m) {
192                 /*
193                  * Found the element corresponding to the tag.
194                  */
195                 NEXT_PHASE(ctx);
196                 ctx->step = t2m->el_no;
197                 break;
198             } else if(specs->ext_start == -1) {
199                 ASN_DEBUG("Unexpected tag %s "
200                           "in non-extensible CHOICE %s",
201                           ber_tlv_tag_string(tlv_tag), td->name);
202                 RETURN(RC_FAIL);
203             } else {
204                 /* Skip this tag */
205                 ssize_t skip;
206
207                 ASN_DEBUG("Skipping unknown tag %s",
208                           ber_tlv_tag_string(tlv_tag));
209
210                 skip = ber_skip_length(opt_codec_ctx,
211                                        BER_TLV_CONSTRUCTED(ptr),
212                                        (const char *)ptr + tag_len,
213                                        LEFT - tag_len);
214
215                 switch(skip) {
216                 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
217                     /* Fall through */
218                 case -1: RETURN(RC_FAIL);
219                 }
220
221                 ADVANCE(skip + tag_len);
222                 RETURN(RC_OK);
223             }
224         } while(0);
225
226     case 2:
227         /*
228          * PHASE 2.
229          * Read in the element.
230          */
231         do {
232             asn_TYPE_member_t *elm;/* CHOICE's element */
233             void *memb_ptr;    /* Pointer to the member */
234             void **memb_ptr2;  /* Pointer to that pointer */
235
236             elm = &elements[ctx->step];
237
238             /*
239              * Compute the position of the member inside a structure,
240              * and also a type of containment (it may be contained
241              * as pointer or using inline inclusion).
242              */
243             if(elm->flags & ATF_POINTER) {
244                 /* Member is a pointer to another structure */
245                 memb_ptr2 = (void **)((char *)st + elm->memb_offset);
246             } else {
247                 /*
248                  * A pointer to a pointer
249                  * holding the start of the structure
250                  */
251                 memb_ptr = (char *)st + elm->memb_offset;
252                 memb_ptr2 = &memb_ptr;
253             }
254             /* Set presence to be able to free it properly at any time */
255             _set_present_idx(st, specs->pres_offset,
256                              specs->pres_size, ctx->step + 1);
257             /*
258              * Invoke the member fetch routine according to member's type
259              */
260             rval = elm->type->op->ber_decoder(opt_codec_ctx, elm->type,
261                                               memb_ptr2, ptr, LEFT,
262                                               elm->tag_mode);
263             switch(rval.code) {
264             case RC_OK:
265                 break;
266             case RC_WMORE: /* More data expected */
267                 if(!SIZE_VIOLATION) {
268                     ADVANCE(rval.consumed);
269                     RETURN(RC_WMORE);
270                 }
271                 RETURN(RC_FAIL);
272             case RC_FAIL: /* Fatal error */
273                 RETURN(rval.code);
274             } /* switch(rval) */
275
276             ADVANCE(rval.consumed);
277         } while(0);
278
279         NEXT_PHASE(ctx);
280
281         /* Fall through */
282     case 3:
283         ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d",
284                   td->name, (long)ctx->left, (long)size,
285                   tag_mode, td->tags_count);
286
287         if(ctx->left > 0) {
288             /*
289              * The type must be fully decoded
290              * by the CHOICE member-specific decoder.
291              */
292             RETURN(RC_FAIL);
293         }
294
295         if(ctx->left == -1
296         && !(tag_mode || td->tags_count)) {
297             /*
298              * This is an untagged CHOICE.
299              * It doesn't contain nothing
300              * except for the member itself, including all its tags.
301              * The decoding is completed.
302              */
303             NEXT_PHASE(ctx);
304             break;
305         }
306
307         /*
308          * Read in the "end of data chunks"'s.
309          */
310         while(ctx->left < 0) {
311             ssize_t tl;
312
313             tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
314             switch(tl) {
315             case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
316                 /* Fall through */
317             case -1: RETURN(RC_FAIL);
318             }
319
320             /*
321              * Expected <0><0>...
322              */
323             if(((const uint8_t *)ptr)[0] == 0) {
324                 if(LEFT < 2) {
325                     if(SIZE_VIOLATION)
326                         RETURN(RC_FAIL);
327                     else
328                         RETURN(RC_WMORE);
329                 } else if(((const uint8_t *)ptr)[1] == 0) {
330                     /*
331                      * Correctly finished with <0><0>.
332                      */
333                     ADVANCE(2);
334                     ctx->left++;
335                     continue;
336                 }
337             } else {
338                 ASN_DEBUG("Unexpected continuation in %s",
339                           td->name);
340                 RETURN(RC_FAIL);
341             }
342
343             /* UNREACHABLE */
344         }
345
346         NEXT_PHASE(ctx);
347     case 4:
348         /* No meaningful work here */
349         break;
350     }
351
352     RETURN(RC_OK);
353 }
354
355 asn_enc_rval_t
356 CHOICE_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr,
357                   int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb,
358                   void *app_key) {
359     const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
360     asn_TYPE_member_t *elm;  /* CHOICE element */
361     asn_enc_rval_t erval = {0,0,0};
362     const void *memb_ptr;
363     size_t computed_size = 0;
364     unsigned present;
365
366     if(!sptr) ASN__ENCODE_FAILED;
367
368     ASN_DEBUG("%s %s as CHOICE",
369               cb ? "Encoding" : "Estimating", td->name);
370
371     present = _fetch_present_idx(sptr,
372         specs->pres_offset, specs->pres_size);
373
374     /*
375      * If the structure was not initialized, it cannot be encoded:
376      * can't deduce what to encode in the choice type.
377      */
378     if(present == 0 || present > td->elements_count) {
379         if(present == 0 && td->elements_count == 0) {
380             /* The CHOICE is empty?! */
381             erval.encoded = 0;
382             ASN__ENCODED_OK(erval);
383         }
384         ASN__ENCODE_FAILED;
385     }
386
387     /*
388      * Seek over the present member of the structure.
389      */
390     elm = &td->elements[present-1];
391     if(elm->flags & ATF_POINTER) {
392         memb_ptr =
393             *(const void *const *)((const char *)sptr + elm->memb_offset);
394         if(memb_ptr == 0) {
395             if(elm->optional) {
396                 erval.encoded = 0;
397                 ASN__ENCODED_OK(erval);
398             }
399             /* Mandatory element absent */
400             ASN__ENCODE_FAILED;
401         }
402     } else {
403         memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
404     }
405
406     /*
407      * If the CHOICE itself is tagged EXPLICIT:
408      * T ::= [2] EXPLICIT CHOICE { ... }
409      * Then emit the appropriate tags.
410      */
411     if(tag_mode == 1 || td->tags_count) {
412         /*
413          * For this, we need to pre-compute the member.
414          */
415         ssize_t ret;
416
417         /* Encode member with its tag */
418         erval = elm->type->op->der_encoder(elm->type, memb_ptr,
419                                            elm->tag_mode,
420                                            elm->tag, 0, 0);
421         if(erval.encoded == -1)
422             return erval;
423
424         /* Encode CHOICE with parent or my own tag */
425         ret = der_write_tags(td, erval.encoded, tag_mode, 1, tag,
426                              cb, app_key);
427         if(ret == -1)
428             ASN__ENCODE_FAILED;
429         computed_size += ret;
430     }
431
432     /*
433      * Encode the single underlying member.
434      */
435     erval = elm->type->op->der_encoder(elm->type, memb_ptr,
436                                        elm->tag_mode, elm->tag,
437                                        cb, app_key);
438     if(erval.encoded == -1)
439         return erval;
440
441     ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)",
442               (long)erval.encoded, (long)computed_size);
443
444     erval.encoded += computed_size;
445
446     return erval;
447 }