SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / constr_SET_OF_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_SET_OF.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 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 SET_OF_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_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics;
40     const asn_TYPE_member_t *element = td->elements;
41     const char *elm_tag;
42     const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
43
44     /*
45      * ... and parts of the structure being constructed.
46      */
47     void *st = *struct_ptr;  /* Target structure. */
48     asn_struct_ctx_t *ctx;   /* Decoder context */
49
50     asn_dec_rval_t rval = {RC_OK, 0};  /* Return value from a decoder */
51     ssize_t consumed_myself = 0;       /* Consumed bytes from ptr */
52
53     /*
54      * Create the target structure if it is not present already.
55      */
56     if(st == 0) {
57         st = *struct_ptr = CALLOC(1, specs->struct_size);
58         if(st == 0) RETURN(RC_FAIL);
59     }
60
61     /* Which tag is expected for the downstream */
62     if(specs->as_XMLValueList) {
63         elm_tag = (specs->as_XMLValueList == 1) ? 0 : "";
64     } else {
65         elm_tag = (*element->name)
66                 ? element->name : element->type->xml_tag;
67     }
68
69     /*
70      * Restore parsing context.
71      */
72     ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
73
74     /*
75      * Phases of XER/XML processing:
76      * Phase 0: Check that the opening tag matches our expectations.
77      * Phase 1: Processing body and reacting on closing tag.
78      * Phase 2: Processing inner type.
79      */
80     for(; ctx->phase <= 2;) {
81         pxer_chunk_type_e ch_type;  /* XER chunk type */
82         ssize_t ch_size;            /* Chunk size */
83         xer_check_tag_e tcv;        /* Tag check value */
84
85         /*
86          * Go inside the inner member of a set.
87          */
88         if(ctx->phase == 2) {
89             asn_dec_rval_t tmprval = {RC_OK, 0};
90
91             /* Invoke the inner type decoder, m.b. multiple times */
92             ASN_DEBUG("XER/SET OF element [%s]", elm_tag);
93             tmprval = element->type->op->xer_decoder(opt_codec_ctx,
94                                                      element->type,
95                                                      &ctx->ptr, elm_tag,
96                                                      buf_ptr, size);
97             if(tmprval.code == RC_OK) {
98                 asn_anonymous_set_ *list = _A_SET_FROM_VOID(st);
99                 if(ASN_SET_ADD(list, ctx->ptr) != 0)
100                     RETURN(RC_FAIL);
101                 ctx->ptr = 0;
102                 XER_ADVANCE(tmprval.consumed);
103             } else {
104                 XER_ADVANCE(tmprval.consumed);
105                 RETURN(tmprval.code);
106             }
107             ctx->phase = 1;  /* Back to body processing */
108             ASN_DEBUG("XER/SET OF phase => %d", ctx->phase);
109             /* Fall through */
110         }
111
112         /*
113          * Get the next part of the XML stream.
114          */
115         ch_size = xer_next_token(&ctx->context,
116                                  buf_ptr, size, &ch_type);
117         if(ch_size == -1) {
118             RETURN(RC_FAIL);
119         } else {
120             switch(ch_type) {
121             case PXER_WMORE:
122                 RETURN(RC_WMORE);
123             case PXER_COMMENT:  /* Got XML comment */
124             case PXER_TEXT:  /* Ignore free-standing text */
125                 XER_ADVANCE(ch_size);  /* Skip silently */
126                 continue;
127             case PXER_TAG:
128                 break;  /* Check the rest down there */
129             }
130         }
131
132         tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
133         ASN_DEBUG("XER/SET OF: tcv = %d, ph=%d t=%s",
134                   tcv, ctx->phase, xml_tag);
135         switch(tcv) {
136         case XCT_CLOSING:
137             if(ctx->phase == 0) break;
138             ctx->phase = 0;
139             /* Fall through */
140         case XCT_BOTH:
141             if(ctx->phase == 0) {
142                 /* No more things to decode */
143                 XER_ADVANCE(ch_size);
144                 ctx->phase = 3;  /* Phase out */
145                 RETURN(RC_OK);
146             }
147             /* Fall through */
148         case XCT_OPENING:
149             if(ctx->phase == 0) {
150                 XER_ADVANCE(ch_size);
151                 ctx->phase = 1;  /* Processing body phase */
152                 continue;
153             }
154             /* Fall through */
155         case XCT_UNKNOWN_OP:
156         case XCT_UNKNOWN_BO:
157
158             ASN_DEBUG("XER/SET OF: tcv=%d, ph=%d", tcv, ctx->phase);
159             if(ctx->phase == 1) {
160                 /*
161                  * Process a single possible member.
162                  */
163                 ctx->phase = 2;
164                 continue;
165             }
166             /* Fall through */
167         default:
168             break;
169         }
170
171         ASN_DEBUG("Unexpected XML tag in SET OF");
172         break;
173     }
174
175     ctx->phase = 3;  /* "Phase out" on hard failure */
176     RETURN(RC_FAIL);
177 }
178
179 typedef struct xer_tmp_enc_s {
180     void *buffer;
181     size_t offset;
182     size_t size;
183 } xer_tmp_enc_t;
184
185 static int
186 SET_OF_encode_xer_callback(const void *buffer, size_t size, void *key) {
187     xer_tmp_enc_t *t = (xer_tmp_enc_t *)key;
188     if(t->offset + size >= t->size) {
189         size_t newsize = (t->size << 2) + size;
190         void *p = REALLOC(t->buffer, newsize);
191         if(!p) return -1;
192         t->buffer = p;
193         t->size = newsize;
194     }
195     memcpy((char *)t->buffer + t->offset, buffer, size);
196     t->offset += size;
197     return 0;
198 }
199
200 static int
201 SET_OF_xer_order(const void *aptr, const void *bptr) {
202     const xer_tmp_enc_t *a = (const xer_tmp_enc_t *)aptr;
203     const xer_tmp_enc_t *b = (const xer_tmp_enc_t *)bptr;
204     size_t minlen = a->offset;
205     int ret;
206     if(b->offset < minlen) minlen = b->offset;
207     /* Well-formed UTF-8 has this nice lexicographical property... */
208     ret = memcmp(a->buffer, b->buffer, minlen);
209     if(ret != 0) return ret;
210     if(a->offset == b->offset)
211         return 0;
212     if(a->offset == minlen)
213         return -1;
214     return 1;
215 }
216
217 asn_enc_rval_t
218 SET_OF_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
219                   enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb,
220                   void *app_key) {
221     asn_enc_rval_t er = {0,0,0};
222     const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics;
223     const asn_TYPE_member_t *elm = td->elements;
224     const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr);
225     const char *mname = specs->as_XMLValueList
226         ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag);
227     size_t mlen = mname ? strlen(mname) : 0;
228     int xcan = (flags & XER_F_CANONICAL);
229     xer_tmp_enc_t *encs = 0;
230     size_t encs_count = 0;
231     void *original_app_key = app_key;
232     asn_app_consume_bytes_f *original_cb = cb;
233     int i;
234
235     if(!sptr) ASN__ENCODE_FAILED;
236
237     if(xcan) {
238         encs = (xer_tmp_enc_t *)MALLOC(list->count * sizeof(encs[0]));
239         if(!encs) ASN__ENCODE_FAILED;
240         cb = SET_OF_encode_xer_callback;
241     }
242
243     er.encoded = 0;
244
245     for(i = 0; i < list->count; i++) {
246         asn_enc_rval_t tmper = {0,0,0};
247
248         void *memb_ptr = list->array[i];
249         if(!memb_ptr) continue;
250
251         if(encs) {
252             memset(&encs[encs_count], 0, sizeof(encs[0]));
253             app_key = &encs[encs_count];
254             encs_count++;
255         }
256
257         if(mname) {
258             if(!xcan) ASN__TEXT_INDENT(1, ilevel);
259             ASN__CALLBACK3("<", 1, mname, mlen, ">", 1);
260         }
261
262         if(!xcan && specs->as_XMLValueList == 1)
263             ASN__TEXT_INDENT(1, ilevel + 1);
264         tmper = elm->type->op->xer_encoder(elm->type, memb_ptr,
265                                            ilevel + (specs->as_XMLValueList != 2),
266                                            flags, cb, app_key);
267         if(tmper.encoded == -1) return tmper;
268         er.encoded += tmper.encoded;
269         if(tmper.encoded == 0 && specs->as_XMLValueList) {
270             const char *name = elm->type->xml_tag;
271             size_t len = strlen(name);
272             ASN__CALLBACK3("<", 1, name, len, "/>", 2);
273         }
274
275         if(mname) {
276             ASN__CALLBACK3("</", 2, mname, mlen, ">", 1);
277         }
278
279     }
280
281     if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1);
282
283     if(encs) {
284         xer_tmp_enc_t *enc = encs;
285         xer_tmp_enc_t *end = encs + encs_count;
286         ssize_t control_size = 0;
287
288         er.encoded = 0;
289         cb = original_cb;
290         app_key = original_app_key;
291         qsort(encs, encs_count, sizeof(encs[0]), SET_OF_xer_order);
292
293         for(; enc < end; enc++) {
294             ASN__CALLBACK(enc->buffer, enc->offset);
295             FREEMEM(enc->buffer);
296             enc->buffer = 0;
297             control_size += enc->offset;
298         }
299         assert(control_size == er.encoded);
300     }
301
302     goto cleanup;
303 cb_failed:
304     ASN__ENCODE_FAILED;
305 cleanup:
306     if(encs) {
307         size_t n;
308         for(n = 0; n < encs_count; n++) {
309             FREEMEM(encs[n].buffer);
310         }
311         FREEMEM(encs);
312     }
313     ASN__ENCODED_OK(er);
314 }