Change version after creation of r2 branch
[ric-plt/resource-status-manager.git] / RSM / asn1codec / e2ap_engine / xer_decoder.c
1
2 /*
3  * Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
4  * Redistribution and modifications are permitted subject to BSD license.
5  */
6 #include <asn_application.h>
7 #include <asn_internal.h>
8 #include <xer_support.h>                /* XER/XML parsing support */
9
10
11 /*
12  * Decode the XER encoding of a given type.
13  */
14 asn_dec_rval_t
15 xer_decode(const asn_codec_ctx_t *opt_codec_ctx,
16            const asn_TYPE_descriptor_t *td, void **struct_ptr,
17            const void *buffer, size_t size) {
18     asn_codec_ctx_t s_codec_ctx;
19
20         /*
21          * Stack checker requires that the codec context
22          * must be allocated on the stack.
23          */
24         if(opt_codec_ctx) {
25                 if(opt_codec_ctx->max_stack_size) {
26                         s_codec_ctx = *opt_codec_ctx;
27                         opt_codec_ctx = &s_codec_ctx;
28                 }
29         } else {
30                 /* If context is not given, be security-conscious anyway */
31                 memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
32                 s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX;
33                 opt_codec_ctx = &s_codec_ctx;
34         }
35
36         /*
37          * Invoke type-specific decoder.
38          */
39         return td->op->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size);
40 }
41
42
43
44 struct xer__cb_arg {
45         pxml_chunk_type_e       chunk_type;
46         size_t                  chunk_size;
47         const void              *chunk_buf;
48         int callback_not_invoked;
49 };
50
51 static int
52 xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) {
53         struct xer__cb_arg *arg = (struct xer__cb_arg *)key;
54         arg->chunk_type = type;
55         arg->chunk_size = _chunk_size;
56         arg->chunk_buf = _chunk_data;
57         arg->callback_not_invoked = 0;
58         return -1;      /* Terminate the XML parsing */
59 }
60
61 /*
62  * Fetch the next token from the XER/XML stream.
63  */
64 ssize_t
65 xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) {
66         struct xer__cb_arg arg;
67         int new_stateContext = *stateContext;
68         ssize_t ret;
69
70         arg.callback_not_invoked = 1;
71         ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg);
72         if(ret < 0) return -1;
73         if(arg.callback_not_invoked) {
74                 assert(ret == 0);       /* No data was consumed */
75         *ch_type = PXER_WMORE;
76                 return 0;               /* Try again with more data */
77         } else {
78                 assert(arg.chunk_size);
79                 assert(arg.chunk_buf == buffer);
80         }
81
82         /*
83          * Translate the XML chunk types into more convenient ones.
84          */
85         switch(arg.chunk_type) {
86         case PXML_TEXT:
87                 *ch_type = PXER_TEXT;
88                 break;
89         case PXML_TAG:
90                 *ch_type = PXER_WMORE;
91                 return 0;       /* Want more */
92         case PXML_TAG_END:
93                 *ch_type = PXER_TAG;
94                 break;
95         case PXML_COMMENT:
96         case PXML_COMMENT_END:
97                 *ch_type = PXER_COMMENT;
98                 break;
99         }
100
101         *stateContext = new_stateContext;
102         return arg.chunk_size;
103 }
104
105 #define CSLASH  0x2f    /* '/' */
106 #define LANGLE  0x3c    /* '<' */
107 #define RANGLE  0x3e    /* '>' */
108
109 xer_check_tag_e
110 xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
111         const char *buf = (const char *)buf_ptr;
112         const char *end;
113         xer_check_tag_e ct = XCT_OPENING;
114
115         if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
116                 if(size >= 2)
117                         ASN_DEBUG("Broken XML tag: \"%c...%c\"",
118                         buf[0], buf[size - 1]);
119                 return XCT_BROKEN;
120         }
121
122         /*
123          * Determine the tag class.
124          */
125         if(buf[1] == CSLASH) {
126                 buf += 2;       /* advance past "</" */
127                 size -= 3;      /* strip "</" and ">" */
128                 ct = XCT_CLOSING;
129                 if(size > 0 && buf[size-1] == CSLASH)
130                         return XCT_BROKEN;      /* </abc/> */
131         } else {
132                 buf++;          /* advance past "<" */
133                 size -= 2;      /* strip "<" and ">" */
134                 if(size > 0 && buf[size-1] == CSLASH) {
135                         ct = XCT_BOTH;
136                         size--; /* One more, for "/" */
137                 }
138         }
139
140         /* Sometimes we don't care about the tag */
141         if(!need_tag || !*need_tag)
142                 return (xer_check_tag_e)(XCT__UNK__MASK | ct);
143
144         /*
145          * Determine the tag name.
146          */
147         for(end = buf + size; buf < end; buf++, need_tag++) {
148                 int b = *buf, n = *need_tag;
149                 if(b != n) {
150                         if(n == 0) {
151                                 switch(b) {
152                                 case 0x09: case 0x0a: case 0x0c: case 0x0d:
153                                 case 0x20:
154                                         /* "<abc def/>": whitespace is normal */
155                                         return ct;
156                                 }
157                         }
158                         return (xer_check_tag_e)(XCT__UNK__MASK | ct);
159                 }
160                 if(b == 0)
161                         return XCT_BROKEN;      /* Embedded 0 in buf?! */
162         }
163         if(*need_tag)
164                 return (xer_check_tag_e)(XCT__UNK__MASK | ct);
165
166         return ct;
167 }
168
169
170 #undef  ADVANCE
171 #define ADVANCE(num_bytes)      do {                            \
172                 size_t num = (num_bytes);                       \
173                 buf_ptr = ((const char *)buf_ptr) + num;        \
174                 size -= num;                                    \
175                 consumed_myself += num;                         \
176         } while(0)
177
178 #undef  RETURN
179 #define RETURN(_code)   do {                                    \
180                 rval.code = _code;                              \
181                 rval.consumed = consumed_myself;                \
182                 if(rval.code != RC_OK)                          \
183                         ASN_DEBUG("Failed with %d", rval.code); \
184                 return rval;                                    \
185         } while(0)
186
187 #define XER_GOT_BODY(chunk_buf, chunk_size, size)       do {    \
188                 ssize_t converted_size = body_receiver          \
189                         (struct_key, chunk_buf, chunk_size,     \
190                                 (size_t)chunk_size < size);     \
191                 if(converted_size == -1) RETURN(RC_FAIL);       \
192                 if(converted_size == 0                          \
193                         && size == (size_t)chunk_size)          \
194                         RETURN(RC_WMORE);                       \
195                 chunk_size = converted_size;                    \
196         } while(0)
197 #define XER_GOT_EMPTY() do {                                    \
198         if(body_receiver(struct_key, 0, 0, size > 0) == -1)     \
199                         RETURN(RC_FAIL);                        \
200         } while(0)
201
202 /*
203  * Generalized function for decoding the primitive values.
204  */
205 asn_dec_rval_t
206 xer_decode_general(const asn_codec_ctx_t *opt_codec_ctx,
207         asn_struct_ctx_t *ctx,  /* Type decoder context */
208         void *struct_key,
209         const char *xml_tag,    /* Expected XML tag */
210         const void *buf_ptr, size_t size,
211         int (*opt_unexpected_tag_decoder)
212                 (void *struct_key, const void *chunk_buf, size_t chunk_size),
213         ssize_t (*body_receiver)
214                 (void *struct_key, const void *chunk_buf, size_t chunk_size,
215                         int have_more)
216         ) {
217
218         asn_dec_rval_t rval;
219         ssize_t consumed_myself = 0;
220
221         (void)opt_codec_ctx;
222
223         /*
224          * Phases of XER/XML processing:
225          * Phase 0: Check that the opening tag matches our expectations.
226          * Phase 1: Processing body and reacting on closing tag.
227          */
228         if(ctx->phase > 1) RETURN(RC_FAIL);
229         for(;;) {
230                 pxer_chunk_type_e ch_type;      /* XER chunk type */
231                 ssize_t ch_size;                /* Chunk size */
232                 xer_check_tag_e tcv;            /* Tag check value */
233
234                 /*
235                  * Get the next part of the XML stream.
236                  */
237                 ch_size = xer_next_token(&ctx->context, buf_ptr, size,
238                         &ch_type);
239                 if(ch_size == -1) {
240             RETURN(RC_FAIL);
241         } else {
242                         switch(ch_type) {
243                         case PXER_WMORE:
244                 RETURN(RC_WMORE);
245                         case PXER_COMMENT:              /* Got XML comment */
246                                 ADVANCE(ch_size);       /* Skip silently */
247                                 continue;
248                         case PXER_TEXT:
249                                 if(ctx->phase == 0) {
250                                         /*
251                                          * We have to ignore whitespace here,
252                                          * but in order to be forward compatible
253                                          * with EXTENDED-XER (EMBED-VALUES, #25)
254                                          * any text is just ignored here.
255                                          */
256                                 } else {
257                                         XER_GOT_BODY(buf_ptr, ch_size, size);
258                                 }
259                                 ADVANCE(ch_size);
260                                 continue;
261                         case PXER_TAG:
262                                 break;  /* Check the rest down there */
263                         }
264                 }
265
266                 assert(ch_type == PXER_TAG && size);
267
268                 tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
269                 /*
270                  * Phase 0:
271                  *      Expecting the opening tag
272                  *      for the type being processed.
273                  * Phase 1:
274                  *      Waiting for the closing XML tag.
275                  */
276                 switch(tcv) {
277                 case XCT_BOTH:
278                         if(ctx->phase) break;
279                         /* Finished decoding of an empty element */
280                         XER_GOT_EMPTY();
281                         ADVANCE(ch_size);
282                         ctx->phase = 2; /* Phase out */
283                         RETURN(RC_OK);
284                 case XCT_OPENING:
285                         if(ctx->phase) break;
286                         ADVANCE(ch_size);
287                         ctx->phase = 1; /* Processing body phase */
288                         continue;
289                 case XCT_CLOSING:
290                         if(!ctx->phase) break;
291                         ADVANCE(ch_size);
292                         ctx->phase = 2; /* Phase out */
293                         RETURN(RC_OK);
294                 case XCT_UNKNOWN_BO:
295                         /*
296                          * Certain tags in the body may be expected.
297                          */
298                         if(opt_unexpected_tag_decoder
299                         && opt_unexpected_tag_decoder(struct_key,
300                                         buf_ptr, ch_size) >= 0) {
301                                 /* Tag's processed fine */
302                                 ADVANCE(ch_size);
303                                 if(!ctx->phase) {
304                                         /* We are not expecting
305                                          * the closing tag anymore. */
306                                         ctx->phase = 2; /* Phase out */
307                                         RETURN(RC_OK);
308                                 }
309                                 continue;
310                         }
311                         /* Fall through */
312                 default:
313                         break;          /* Unexpected tag */
314                 }
315
316                 ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag);
317                 break;  /* Dark and mysterious things have just happened */
318         }
319
320         RETURN(RC_FAIL);
321 }
322
323
324 size_t
325 xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {
326         const char *p = (const char *)chunk_buf;
327         const char *pend = p + chunk_size;
328
329         for(; p < pend; p++) {
330                 switch(*p) {
331                 /* X.693, #8.1.4
332                  * HORISONTAL TAB (9)
333                  * LINE FEED (10) 
334                  * CARRIAGE RETURN (13) 
335                  * SPACE (32)
336                  */
337                 case 0x09: case 0x0a: case 0x0d: case 0x20:
338                         continue;
339                 default:
340                         break;
341                 }
342                 break;
343         }
344         return (p - (const char *)chunk_buf);
345 }
346
347 /*
348  * This is a vastly simplified, non-validating XML tree skipper.
349  */
350 int
351 xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) {
352         assert(*depth > 0);
353         switch(tcv) {
354         case XCT_BOTH:
355         case XCT_UNKNOWN_BO:
356                 /* These negate each other. */
357                 return 0;
358         case XCT_OPENING:
359         case XCT_UNKNOWN_OP:
360                 ++(*depth);
361                 return 0;
362         case XCT_CLOSING:
363         case XCT_UNKNOWN_CL:
364                 if(--(*depth) == 0)
365                         return (tcv == XCT_CLOSING) ? 2 : 1;
366                 return 0;
367         default:
368                 return -1;
369         }
370 }