blob: 64566668fb0c18884c8dabca7659b26f4c5f57de [file] [log] [blame]
vlm9de248e2004-10-20 15:50:55 +00001
2#include <asn_application.h>
3#include <asn_internal.h>
4#include <xer_support.h> /* XER/XML parsing support */
5#include <assert.h>
6
7
8/*
9 * Decode the XER encoding of a given type.
10 */
11asn_dec_rval_t
12xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
13 void **struct_ptr, void *buffer, size_t size) {
14 asn_codec_ctx_t s_codec_ctx;
15
16 /*
17 * Satisfy the requirement that the codec context
18 * must be allocated on the stack.
19 */
20 if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
21 s_codec_ctx = *opt_codec_ctx;
22 opt_codec_ctx = &s_codec_ctx;
23 }
24
25 /*
26 * Invoke type-specific decoder.
27 */
28 return td->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size);
29}
30
31
32
33struct xer__cb_arg {
34 pxml_chunk_type_e chunk_type;
35 size_t chunk_size;
vlm4df9cc12005-03-09 22:19:25 +000036 const void *chunk_buf;
vlm9de248e2004-10-20 15:50:55 +000037 int callback_not_invoked;
38};
39
40static int
vlm4df9cc12005-03-09 22:19:25 +000041xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) {
vlm9de248e2004-10-20 15:50:55 +000042 struct xer__cb_arg *arg = (struct xer__cb_arg *)key;
43 arg->chunk_type = type;
44 arg->chunk_size = _chunk_size;
45 arg->chunk_buf = _chunk_data;
46 arg->callback_not_invoked = 0;
47 return -1; /* Terminate the XML parsing */
48}
49
50/*
51 * Fetch the next token from the XER/XML stream.
52 */
53ssize_t
vlm4df9cc12005-03-09 22:19:25 +000054xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) {
vlm9de248e2004-10-20 15:50:55 +000055 struct xer__cb_arg arg;
vlmc70f8f32005-02-18 18:06:36 +000056 int new_stateContext = *stateContext;
vlm9de248e2004-10-20 15:50:55 +000057 ssize_t ret;
58
59 arg.callback_not_invoked = 1;
vlmc70f8f32005-02-18 18:06:36 +000060 ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg);
vlm9de248e2004-10-20 15:50:55 +000061 if(ret < 0) return -1;
62 if(arg.callback_not_invoked) {
63 assert(ret == 0); /* No data was consumed */
64 return 0; /* Try again with more data */
65 } else {
66 assert(arg.chunk_size);
67 assert(arg.chunk_buf == buffer);
68 }
69
70 /*
71 * Translate the XML chunk types into more convenient ones.
72 */
73 switch(arg.chunk_type) {
74 case PXML_TEXT:
75 *ch_type = PXER_TEXT;
76 break;
77 case PXML_TAG: return 0; /* Want more */
78 case PXML_TAG_END:
79 *ch_type = PXER_TAG;
80 break;
81 case PXML_COMMENT:
82 case PXML_COMMENT_END:
83 *ch_type = PXER_COMMENT;
84 break;
85 }
86
vlmc70f8f32005-02-18 18:06:36 +000087 *stateContext = new_stateContext;
vlm9de248e2004-10-20 15:50:55 +000088 return arg.chunk_size;
89}
90
91#define CSLASH 0x2f /* '/' */
92#define LANGLE 0x3c /* '<' */
93#define RANGLE 0x3e /* '>' */
94
95xer_check_tag_e
96xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
97 const char *buf = (const char *)buf_ptr;
98 const char *end;
99 xer_check_tag_e ct = XCT_OPENING;
100
101 if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
vlm390a9022005-02-14 17:21:22 +0000102 if(size >= 2)
103 ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]);
vlm9de248e2004-10-20 15:50:55 +0000104 return XCT_BROKEN;
105 }
106
107 /*
108 * Determine the tag class.
109 */
110 if(buf[1] == CSLASH) {
111 buf += 2; /* advance past "</" */
112 size -= 3; /* strip "</" and ">" */
113 ct = XCT_CLOSING;
114 if(size > 0 && buf[size-1] == CSLASH)
115 return XCT_BROKEN; /* </abc/> */
116 } else {
117 buf++; /* advance past "<" */
118 size -= 2; /* strip "<" and ">" */
119 if(size > 0 && buf[size-1] == CSLASH) {
120 ct = XCT_BOTH;
121 size--; /* One more, for "/" */
122 }
123 }
124
125 /*
126 * Determine the tag name.
127 */
128 for(end = buf + size; buf < end; buf++, need_tag++) {
129 int b = *buf, n = *need_tag;
130 if(b != n) {
131 if(n == 0) {
132 switch(b) {
133 case 0x09: case 0x0a: case 0x0c: case 0x0d:
134 case 0x20:
135 /* "<abc def/>": whitespace is normal */
136 return ct;
137 }
138 }
vlmc70f8f32005-02-18 18:06:36 +0000139 return (xer_check_tag_e)(XCT__UNK__MASK | ct);
vlm9de248e2004-10-20 15:50:55 +0000140 }
141 if(b == 0)
142 return XCT_BROKEN; /* Embedded 0 in buf?! */
143 }
vlm957da5b2005-02-18 14:23:48 +0000144 if(*need_tag)
vlmc70f8f32005-02-18 18:06:36 +0000145 return (xer_check_tag_e)(XCT__UNK__MASK | ct);
vlm9de248e2004-10-20 15:50:55 +0000146
147 return ct;
148}
149
150
151#undef ADVANCE
152#define ADVANCE(num_bytes) do { \
153 size_t num = (num_bytes); \
vlm4df9cc12005-03-09 22:19:25 +0000154 buf_ptr = ((const char *)buf_ptr) + num; \
vlm9de248e2004-10-20 15:50:55 +0000155 size -= num; \
156 consumed_myself += num; \
157 } while(0)
158
159#undef RETURN
160#define RETURN(_code) do { \
161 rval.code = _code; \
162 rval.consumed = consumed_myself; \
163 return rval; \
164 } while(0)
165
vlm88c50282005-02-18 12:26:20 +0000166#define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \
vlm9de248e2004-10-20 15:50:55 +0000167 ssize_t converted_size = body_receiver \
vlm3b6e1122004-10-21 11:22:12 +0000168 (struct_key, chunk_buf, chunk_size, \
vlm9de248e2004-10-20 15:50:55 +0000169 (size_t)chunk_size < size); \
170 if(converted_size == -1) RETURN(RC_FAIL); \
vlmc70f8f32005-02-18 18:06:36 +0000171 if(converted_size == 0 \
172 && size == (size_t)chunk_size) \
vlm88c50282005-02-18 12:26:20 +0000173 RETURN(RC_WMORE); \
vlm9de248e2004-10-20 15:50:55 +0000174 chunk_size = converted_size; \
175 } while(0)
176#define XER_GOT_EMPTY() do { \
vlm88c50282005-02-18 12:26:20 +0000177 if(body_receiver(struct_key, 0, 0, size > 0) == -1) \
178 RETURN(RC_FAIL); \
vlm9de248e2004-10-20 15:50:55 +0000179 } while(0)
180
181/*
182 * Generalized function for decoding the primitive values.
183 */
184asn_dec_rval_t
185xer_decode_general(asn_codec_ctx_t *opt_codec_ctx,
186 asn_struct_ctx_t *ctx, /* Type decoder context */
vlm3b6e1122004-10-21 11:22:12 +0000187 void *struct_key,
vlm9de248e2004-10-20 15:50:55 +0000188 const char *xml_tag, /* Expected XML tag */
vlm4df9cc12005-03-09 22:19:25 +0000189 const void *buf_ptr, size_t size,
vlm9de248e2004-10-20 15:50:55 +0000190 int (*opt_unexpected_tag_decoder)
vlm4df9cc12005-03-09 22:19:25 +0000191 (void *struct_key, const void *chunk_buf, size_t chunk_size),
vlm9de248e2004-10-20 15:50:55 +0000192 ssize_t (*body_receiver)
vlm4df9cc12005-03-09 22:19:25 +0000193 (void *struct_key, const void *chunk_buf, size_t chunk_size,
vlm9de248e2004-10-20 15:50:55 +0000194 int have_more)
195 ) {
196
197 asn_dec_rval_t rval;
198 ssize_t consumed_myself = 0;
vlm9de248e2004-10-20 15:50:55 +0000199
200 (void)opt_codec_ctx;
201
202 /*
203 * Phases of XER/XML processing:
204 * Phase 0: Check that the opening tag matches our expectations.
205 * Phase 1: Processing body and reacting on closing tag.
206 */
207 if(ctx->phase > 1) RETURN(RC_FAIL);
vlmcb7222f2005-02-18 16:10:40 +0000208 for(;;) {
vlmb8404852004-10-23 13:27:03 +0000209 pxer_chunk_type_e ch_type; /* XER chunk type */
210 ssize_t ch_size; /* Chunk size */
211 xer_check_tag_e tcv; /* Tag check value */
vlm9de248e2004-10-20 15:50:55 +0000212
213 /*
214 * Get the next part of the XML stream.
215 */
vlmc70f8f32005-02-18 18:06:36 +0000216 ch_size = xer_next_token(&ctx->context, buf_ptr, size,
217 &ch_type);
vlm9de248e2004-10-20 15:50:55 +0000218 switch(ch_size) {
219 case -1: RETURN(RC_FAIL);
220 case 0:
vlm9de248e2004-10-20 15:50:55 +0000221 RETURN(RC_WMORE);
222 default:
223 switch(ch_type) {
224 case PXER_COMMENT: /* Got XML comment */
225 ADVANCE(ch_size); /* Skip silently */
226 continue;
227 case PXER_TEXT:
228 if(ctx->phase == 0) {
vlm7958f112004-10-21 05:44:11 +0000229 /*
230 * We have to ignore whitespace here,
231 * but in order to be forward compatible
232 * with EXTENDED-XER (EMBED-VALUES, #25)
233 * any text is just ignored here.
234 */
235 } else {
vlm88c50282005-02-18 12:26:20 +0000236 XER_GOT_BODY(buf_ptr, ch_size, size);
vlm9de248e2004-10-20 15:50:55 +0000237 }
vlm9de248e2004-10-20 15:50:55 +0000238 ADVANCE(ch_size);
239 continue;
240 case PXER_TAG:
241 break; /* Check the rest down there */
242 }
243 }
244
245 assert(ch_type == PXER_TAG && size);
246
247 tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
vlmb8404852004-10-23 13:27:03 +0000248 /*
249 * Phase 0:
250 * Expecting the opening tag
251 * for the type being processed.
252 * Phase 1:
253 * Waiting for the closing XML tag.
254 */
255 switch(tcv) {
256 case XCT_BOTH:
257 if(ctx->phase) break;
258 /* Finished decoding of an empty element */
259 XER_GOT_EMPTY();
260 ADVANCE(ch_size);
261 ctx->phase = 2; /* Phase out */
262 RETURN(RC_OK);
263 case XCT_OPENING:
264 if(ctx->phase) break;
265 ADVANCE(ch_size);
266 ctx->phase = 1; /* Processing body phase */
267 continue;
268 case XCT_CLOSING:
269 if(!ctx->phase) break;
270 ADVANCE(ch_size);
271 ctx->phase = 2; /* Phase out */
272 RETURN(RC_OK);
vlm957da5b2005-02-18 14:23:48 +0000273 case XCT_UNKNOWN_BO:
vlm9de248e2004-10-20 15:50:55 +0000274 /*
vlmb8404852004-10-23 13:27:03 +0000275 * Certain tags in the body may be expected.
vlm9de248e2004-10-20 15:50:55 +0000276 */
vlmb8404852004-10-23 13:27:03 +0000277 if(opt_unexpected_tag_decoder
278 && opt_unexpected_tag_decoder(struct_key,
vlm8a09e0f2005-02-25 14:20:30 +0000279 buf_ptr, ch_size) >= 0) {
vlmb8404852004-10-23 13:27:03 +0000280 /* Tag's processed fine */
vlm9de248e2004-10-20 15:50:55 +0000281 ADVANCE(ch_size);
vlm80a48592005-02-25 12:10:27 +0000282 if(!ctx->phase) {
283 /* We are not expecting
284 * the closing tag anymore. */
285 ctx->phase = 2; /* Phase out */
286 RETURN(RC_OK);
287 }
vlm9de248e2004-10-20 15:50:55 +0000288 continue;
vlm9de248e2004-10-20 15:50:55 +0000289 }
vlmb8404852004-10-23 13:27:03 +0000290 /* Fall through */
291 default:
292 break; /* Unexpected tag */
vlm9de248e2004-10-20 15:50:55 +0000293 }
vlmb8404852004-10-23 13:27:03 +0000294
vlmaa930cb2005-02-24 22:37:07 +0000295 ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag);
vlm9de248e2004-10-20 15:50:55 +0000296 break; /* Dark and mysterious things have just happened */
297 }
298
299 RETURN(RC_FAIL);
300}
301
vlm2a4245f2004-10-22 08:17:16 +0000302
303int
vlm4df9cc12005-03-09 22:19:25 +0000304xer_is_whitespace(const void *chunk_buf, size_t chunk_size) {
305 const char *p = (const char *)chunk_buf;
306 const char *pend = p + chunk_size;
vlm2a4245f2004-10-22 08:17:16 +0000307
308 for(; p < pend; p++) {
309 switch(*p) {
310 /* X.693, #8.1.4
311 * HORISONTAL TAB (9)
312 * LINE FEED (10)
313 * CARRIAGE RETURN (13)
314 * SPACE (32)
315 */
316 case 0x09: case 0x0a: case 0x0d: case 0x20:
317 break;
318 default:
319 return 0;
320 }
321 }
322 return 1; /* All whitespace */
323}
324
vlmcb7222f2005-02-18 16:10:40 +0000325/*
326 * This is a vastly simplified, non-validating XML tree skipper.
327 */
328int
329xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) {
330 assert(*depth > 0);
331 switch(tcv) {
332 case XCT_BOTH:
333 case XCT_UNKNOWN_BO:
334 /* These negate each other. */
335 return 0;
336 case XCT_OPENING:
337 case XCT_UNKNOWN_OP:
338 ++(*depth);
339 return 0;
340 case XCT_CLOSING:
341 case XCT_UNKNOWN_CL:
342 if(--(*depth) == 0)
343 return (tcv == XCT_CLOSING) ? 2 : 1;
344 return 0;
345 default:
346 return -1;
347 }
348}
349
350