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