SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / constr_CHOICE_xer.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  * Return a standardized complex structure.
11  */
12 #undef RETURN
13 #define RETURN(_code)                     \
14     do {                                  \
15         rval.code = _code;                \
16         rval.consumed = consumed_myself;  \
17         return rval;                      \
18     } while(0)
19
20 #undef XER_ADVANCE
21 #define XER_ADVANCE(num_bytes)                                    \
22     do {                                                          \
23         size_t num = num_bytes;                                   \
24         buf_ptr = (const void *)(((const char *)buf_ptr) + num);  \
25         size -= num;                                              \
26         consumed_myself += num;                                   \
27     } while(0)
28
29 /*
30  * Decode the XER (XML) data.
31  */
32 asn_dec_rval_t
33 CHOICE_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
34                   const asn_TYPE_descriptor_t *td, void **struct_ptr,
35                   const char *opt_mname, const void *buf_ptr, size_t size) {
36     /*
37      * Bring closer parts of structure description.
38      */
39     const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
40     const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
41
42     /*
43      * Parts of the structure being constructed.
44      */
45     void *st = *struct_ptr;  /* Target structure. */
46     asn_struct_ctx_t *ctx;   /* Decoder context */
47
48     asn_dec_rval_t rval;          /* Return value of a decoder */
49     ssize_t consumed_myself = 0;  /* Consumed bytes from ptr */
50     size_t edx;                   /* Element index */
51
52     /*
53      * Create the target structure if it is not present already.
54      */
55     if(st == 0) {
56         st = *struct_ptr = CALLOC(1, specs->struct_size);
57         if(st == 0) RETURN(RC_FAIL);
58     }
59
60     /*
61      * Restore parsing context.
62      */
63     ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
64     if(ctx->phase == 0 && !*xml_tag)
65         ctx->phase = 1;  /* Skip the outer tag checking phase */
66
67     /*
68      * Phases of XER/XML processing:
69      * Phase 0: Check that the opening tag matches our expectations.
70      * Phase 1: Processing body and reacting on closing tag.
71      * Phase 2: Processing inner type.
72      * Phase 3: Only waiting for closing tag.
73      * Phase 4: Skipping unknown extensions.
74      * Phase 5: PHASED OUT
75      */
76     for(edx = ctx->step; ctx->phase <= 4;) {
77         pxer_chunk_type_e ch_type;  /* XER chunk type */
78         ssize_t ch_size;            /* Chunk size */
79         xer_check_tag_e tcv;        /* Tag check value */
80         asn_TYPE_member_t *elm;
81
82         /*
83          * Go inside the member.
84          */
85         if(ctx->phase == 2) {
86             asn_dec_rval_t tmprval;
87             void *memb_ptr;    /* Pointer to the member */
88             void **memb_ptr2;  /* Pointer to that pointer */
89             unsigned old_present;
90
91             elm = &td->elements[edx];
92
93             if(elm->flags & ATF_POINTER) {
94                 /* Member is a pointer to another structure */
95                 memb_ptr2 = (void **)((char *)st
96                     + elm->memb_offset);
97             } else {
98                 memb_ptr = (char *)st + elm->memb_offset;
99                 memb_ptr2 = &memb_ptr;
100             }
101
102             /* Start/Continue decoding the inner member */
103             tmprval = elm->type->op->xer_decoder(opt_codec_ctx,
104                                                  elm->type, memb_ptr2,
105                                                  elm->name,
106                                                  buf_ptr, size);
107             XER_ADVANCE(tmprval.consumed);
108             ASN_DEBUG("XER/CHOICE: itdf: [%s] code=%d",
109                       elm->type->name, tmprval.code);
110             old_present = _fetch_present_idx(st,
111                                              specs->pres_offset,
112                                              specs->pres_size);
113             assert(old_present == 0 || old_present == edx + 1);
114             /* Record what we've got */
115             _set_present_idx(st,
116                              specs->pres_offset,
117                              specs->pres_size, edx + 1);
118             if(tmprval.code != RC_OK)
119                 RETURN(tmprval.code);
120             ctx->phase = 3;
121             /* Fall through */
122         }
123
124         /* No need to wait for closing tag; special mode. */
125         if(ctx->phase == 3 && !*xml_tag) {
126             ctx->phase = 5;  /* Phase out */
127             RETURN(RC_OK);
128         }
129
130         /*
131          * Get the next part of the XML stream.
132          */
133         ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type);
134         if(ch_size == -1) {
135             RETURN(RC_FAIL);
136         } else {
137             switch(ch_type) {
138             case PXER_WMORE:
139                 RETURN(RC_WMORE);
140             case PXER_COMMENT:  /* Got XML comment */
141             case PXER_TEXT:  /* Ignore free-standing text */
142                 XER_ADVANCE(ch_size);  /* Skip silently */
143                 continue;
144             case PXER_TAG:
145                 break;  /* Check the rest down there */
146             }
147         }
148
149         tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
150         ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d",
151                   ch_size>0?((const uint8_t *)buf_ptr)[0]:'?',
152                   ch_size>1?((const uint8_t *)buf_ptr)[1]:'?',
153                   ch_size>2?((const uint8_t *)buf_ptr)[2]:'?',
154                   ch_size>3?((const uint8_t *)buf_ptr)[3]:'?',
155                   xml_tag, tcv);
156
157         /* Skip the extensions section */
158         if(ctx->phase == 4) {
159             ASN_DEBUG("skip_unknown(%d, %ld)",
160                       tcv, (long)ctx->left);
161             switch(xer_skip_unknown(tcv, &ctx->left)) {
162             case -1:
163                 ctx->phase = 5;
164                 RETURN(RC_FAIL);
165             case 1:
166                 ctx->phase = 3;
167                 /* Fall through */
168             case 0:
169                 XER_ADVANCE(ch_size);
170                 continue;
171             case 2:
172                 ctx->phase = 3;
173                 break;
174             }
175         }
176
177         switch(tcv) {
178         case XCT_BOTH:
179             break;  /* No CHOICE? */
180         case XCT_CLOSING:
181             if(ctx->phase != 3)
182                 break;
183             XER_ADVANCE(ch_size);
184             ctx->phase = 5;  /* Phase out */
185             RETURN(RC_OK);
186         case XCT_OPENING:
187             if(ctx->phase == 0) {
188                 XER_ADVANCE(ch_size);
189                 ctx->phase = 1;  /* Processing body phase */
190                 continue;
191             }
192             /* Fall through */
193         case XCT_UNKNOWN_OP:
194         case XCT_UNKNOWN_BO:
195
196             if(ctx->phase != 1)
197                 break;  /* Really unexpected */
198
199             /*
200              * Search which inner member corresponds to this tag.
201              */
202             for(edx = 0; edx < td->elements_count; edx++) {
203                 elm = &td->elements[edx];
204                 tcv = xer_check_tag(buf_ptr,ch_size,elm->name);
205                 switch(tcv) {
206                 case XCT_BOTH:
207                 case XCT_OPENING:
208                     /*
209                      * Process this member.
210                      */
211                     ctx->step = edx;
212                     ctx->phase = 2;
213                     break;
214                 case XCT_UNKNOWN_OP:
215                 case XCT_UNKNOWN_BO:
216                     continue;
217                 default:
218                     edx = td->elements_count;
219                     break;  /* Phase out */
220                 }
221                 break;
222             }
223             if(edx != td->elements_count)
224                 continue;
225
226             /* It is expected extension */
227             if(specs->ext_start != -1) {
228                 ASN_DEBUG("Got anticipated extension");
229                 /*
230                  * Check for (XCT_BOTH or XCT_UNKNOWN_BO)
231                  * By using a mask. Only record a pure
232                  * <opening> tags.
233                  */
234                 if(tcv & XCT_CLOSING) {
235                     /* Found </extension> without body */
236                     ctx->phase = 3;  /* Terminating */
237                 } else {
238                     ctx->left = 1;
239                     ctx->phase = 4;  /* Skip ...'s */
240                 }
241                 XER_ADVANCE(ch_size);
242                 continue;
243             }
244
245             /* Fall through */
246         default:
247             break;
248         }
249
250         ASN_DEBUG("Unexpected XML tag [%c%c%c%c] in CHOICE [%s]"
251                   " (ph=%d, tag=%s)",
252                   ch_size>0?((const uint8_t *)buf_ptr)[0]:'?',
253                   ch_size>1?((const uint8_t *)buf_ptr)[1]:'?',
254                   ch_size>2?((const uint8_t *)buf_ptr)[2]:'?',
255                   ch_size>3?((const uint8_t *)buf_ptr)[3]:'?',
256                   td->name, ctx->phase, xml_tag);
257         break;
258     }
259
260     ctx->phase = 5;  /* Phase out, just in case */
261     RETURN(RC_FAIL);
262 }
263
264 asn_enc_rval_t
265 CHOICE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
266                   enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb,
267                   void *app_key) {
268     const asn_CHOICE_specifics_t *specs =
269         (const asn_CHOICE_specifics_t *)td->specifics;
270     asn_enc_rval_t er = {0,0,0};
271     unsigned present = 0;
272
273     if(!sptr)
274         ASN__ENCODE_FAILED;
275
276     /*
277      * Figure out which CHOICE element is encoded.
278      */
279     present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
280
281     if(present == 0 || present > td->elements_count) {
282         ASN__ENCODE_FAILED;
283     } else {
284         asn_enc_rval_t tmper = {0,0,0};
285         asn_TYPE_member_t *elm = &td->elements[present-1];
286         const void *memb_ptr = NULL;
287         const char *mname = elm->name;
288         unsigned int mlen = strlen(mname);
289
290         if(elm->flags & ATF_POINTER) {
291             memb_ptr =
292                 *(const void *const *)((const char *)sptr + elm->memb_offset);
293             if(!memb_ptr) ASN__ENCODE_FAILED;
294         } else {
295             memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
296         }
297
298         er.encoded = 0;
299
300         if(!(flags & XER_F_CANONICAL)) ASN__TEXT_INDENT(1, ilevel);
301         ASN__CALLBACK3("<", 1, mname, mlen, ">", 1);
302
303         tmper = elm->type->op->xer_encoder(elm->type, memb_ptr,
304                                            ilevel + 1, flags, cb, app_key);
305         if(tmper.encoded == -1) return tmper;
306         er.encoded += tmper.encoded;
307
308         ASN__CALLBACK3("</", 2, mname, mlen, ">", 1);
309     }
310
311     if(!(flags & XER_F_CANONICAL)) ASN__TEXT_INDENT(1, ilevel - 1);
312
313     ASN__ENCODED_OK(er);
314 cb_failed:
315     ASN__ENCODE_FAILED;
316 }