blob: 97e0d394d223df84119fb765321335386b797696 [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;
36 void *chunk_buf;
37 int callback_not_invoked;
38};
39
40static int
41xer__token_cb(pxml_chunk_type_e type, void *_chunk_data, size_t _chunk_size, void *key) {
42 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
54xer_next_token(int *stateContext, void *buffer, size_t size,
55 pxer_chunk_type_e *ch_type) {
56 struct xer__cb_arg arg;
57 ssize_t ret;
vlm390a9022005-02-14 17:21:22 +000058 int new_stateContext = *stateContext;
vlm9de248e2004-10-20 15:50:55 +000059
60 arg.callback_not_invoked = 1;
vlm390a9022005-02-14 17:21:22 +000061 ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg);
vlm9de248e2004-10-20 15:50:55 +000062 if(ret < 0) return -1;
63 if(arg.callback_not_invoked) {
64 assert(ret == 0); /* No data was consumed */
65 return 0; /* Try again with more data */
66 } else {
67 assert(arg.chunk_size);
68 assert(arg.chunk_buf == buffer);
69 }
70
71 /*
72 * Translate the XML chunk types into more convenient ones.
73 */
74 switch(arg.chunk_type) {
75 case PXML_TEXT:
76 *ch_type = PXER_TEXT;
77 break;
78 case PXML_TAG: return 0; /* Want more */
79 case PXML_TAG_END:
80 *ch_type = PXER_TAG;
81 break;
82 case PXML_COMMENT:
83 case PXML_COMMENT_END:
84 *ch_type = PXER_COMMENT;
85 break;
86 }
87
vlm390a9022005-02-14 17:21:22 +000088 *stateContext = new_stateContext; /* Update the context */
vlm9de248e2004-10-20 15:50:55 +000089 return arg.chunk_size;
90}
91
92#define CSLASH 0x2f /* '/' */
93#define LANGLE 0x3c /* '<' */
94#define RANGLE 0x3e /* '>' */
95
96xer_check_tag_e
97xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
98 const char *buf = (const char *)buf_ptr;
99 const char *end;
100 xer_check_tag_e ct = XCT_OPENING;
101
102 if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
vlm390a9022005-02-14 17:21:22 +0000103 if(size >= 2)
104 ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]);
vlm9de248e2004-10-20 15:50:55 +0000105 return XCT_BROKEN;
106 }
107
108 /*
109 * Determine the tag class.
110 */
111 if(buf[1] == CSLASH) {
112 buf += 2; /* advance past "</" */
113 size -= 3; /* strip "</" and ">" */
114 ct = XCT_CLOSING;
115 if(size > 0 && buf[size-1] == CSLASH)
116 return XCT_BROKEN; /* </abc/> */
117 } else {
118 buf++; /* advance past "<" */
119 size -= 2; /* strip "<" and ">" */
120 if(size > 0 && buf[size-1] == CSLASH) {
121 ct = XCT_BOTH;
122 size--; /* One more, for "/" */
123 }
124 }
125
126 /*
127 * Determine the tag name.
128 */
129 for(end = buf + size; buf < end; buf++, need_tag++) {
130 int b = *buf, n = *need_tag;
131 if(b != n) {
132 if(n == 0) {
133 switch(b) {
134 case 0x09: case 0x0a: case 0x0c: case 0x0d:
135 case 0x20:
136 /* "<abc def/>": whitespace is normal */
137 return ct;
138 }
139 }
140 return XCT_UNEXPECTED;
141 }
142 if(b == 0)
143 return XCT_BROKEN; /* Embedded 0 in buf?! */
144 }
145 if(*need_tag) return XCT_UNEXPECTED;
146
147 return ct;
148}
149
150
151#undef ADVANCE
152#define ADVANCE(num_bytes) do { \
153 size_t num = (num_bytes); \
154 buf_ptr = ((char *)buf_ptr) + num; \
155 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); \
vlm88c50282005-02-18 12:26:20 +0000171 if(converted_size == 0 && size == chunk_size) { \
172 ctx->step = xer_state; \
173 RETURN(RC_WMORE); \
174 } \
vlm9de248e2004-10-20 15:50:55 +0000175 chunk_size = converted_size; \
176 } while(0)
177#define XER_GOT_EMPTY() do { \
vlm88c50282005-02-18 12:26:20 +0000178 if(body_receiver(struct_key, 0, 0, size > 0) == -1) \
179 RETURN(RC_FAIL); \
vlm9de248e2004-10-20 15:50:55 +0000180 } while(0)
181
182/*
183 * Generalized function for decoding the primitive values.
184 */
185asn_dec_rval_t
186xer_decode_general(asn_codec_ctx_t *opt_codec_ctx,
187 asn_struct_ctx_t *ctx, /* Type decoder context */
vlm3b6e1122004-10-21 11:22:12 +0000188 void *struct_key,
vlm9de248e2004-10-20 15:50:55 +0000189 const char *xml_tag, /* Expected XML tag */
190 void *buf_ptr, size_t size,
191 int (*opt_unexpected_tag_decoder)
vlm3b6e1122004-10-21 11:22:12 +0000192 (void *struct_key, void *chunk_buf, size_t chunk_size),
vlm9de248e2004-10-20 15:50:55 +0000193 ssize_t (*body_receiver)
vlm3b6e1122004-10-21 11:22:12 +0000194 (void *struct_key, void *chunk_buf, size_t chunk_size,
vlm9de248e2004-10-20 15:50:55 +0000195 int have_more)
196 ) {
197
198 asn_dec_rval_t rval;
199 ssize_t consumed_myself = 0;
vlm9de248e2004-10-20 15:50:55 +0000200 int xer_state; /* XER low level parsing context */
201
202 (void)opt_codec_ctx;
203
204 /*
205 * Phases of XER/XML processing:
206 * Phase 0: Check that the opening tag matches our expectations.
207 * Phase 1: Processing body and reacting on closing tag.
208 */
209 if(ctx->phase > 1) RETURN(RC_FAIL);
210 for(xer_state = ctx->step;;) {
vlmb8404852004-10-23 13:27:03 +0000211 pxer_chunk_type_e ch_type; /* XER chunk type */
212 ssize_t ch_size; /* Chunk size */
213 xer_check_tag_e tcv; /* Tag check value */
vlm9de248e2004-10-20 15:50:55 +0000214
215 /*
216 * Get the next part of the XML stream.
217 */
218 ch_size = xer_next_token(&xer_state, buf_ptr, size, &ch_type);
219 switch(ch_size) {
220 case -1: RETURN(RC_FAIL);
221 case 0:
222 ctx->step = xer_state;
223 RETURN(RC_WMORE);
224 default:
225 switch(ch_type) {
226 case PXER_COMMENT: /* Got XML comment */
227 ADVANCE(ch_size); /* Skip silently */
228 continue;
229 case PXER_TEXT:
230 if(ctx->phase == 0) {
vlm7958f112004-10-21 05:44:11 +0000231 /*
232 * We have to ignore whitespace here,
233 * but in order to be forward compatible
234 * with EXTENDED-XER (EMBED-VALUES, #25)
235 * any text is just ignored here.
236 */
237 } else {
vlm88c50282005-02-18 12:26:20 +0000238 XER_GOT_BODY(buf_ptr, ch_size, size);
vlm9de248e2004-10-20 15:50:55 +0000239 }
vlm9de248e2004-10-20 15:50:55 +0000240 ADVANCE(ch_size);
241 continue;
242 case PXER_TAG:
243 break; /* Check the rest down there */
244 }
245 }
246
247 assert(ch_type == PXER_TAG && size);
248
249 tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
vlmb8404852004-10-23 13:27:03 +0000250 /*
251 * Phase 0:
252 * Expecting the opening tag
253 * for the type being processed.
254 * Phase 1:
255 * Waiting for the closing XML tag.
256 */
257 switch(tcv) {
258 case XCT_BOTH:
259 if(ctx->phase) break;
260 /* Finished decoding of an empty element */
261 XER_GOT_EMPTY();
262 ADVANCE(ch_size);
263 ctx->phase = 2; /* Phase out */
264 RETURN(RC_OK);
265 case XCT_OPENING:
266 if(ctx->phase) break;
267 ADVANCE(ch_size);
268 ctx->phase = 1; /* Processing body phase */
269 continue;
270 case XCT_CLOSING:
271 if(!ctx->phase) break;
272 ADVANCE(ch_size);
273 ctx->phase = 2; /* Phase out */
274 RETURN(RC_OK);
275 case XCT_UNEXPECTED:
276 if(!ctx->phase) break;
vlm9de248e2004-10-20 15:50:55 +0000277 /*
vlmb8404852004-10-23 13:27:03 +0000278 * Certain tags in the body may be expected.
vlm9de248e2004-10-20 15:50:55 +0000279 */
vlmb8404852004-10-23 13:27:03 +0000280 if(opt_unexpected_tag_decoder
281 && opt_unexpected_tag_decoder(struct_key,
282 buf_ptr, ch_size) == 0) {
283 /* Tag's processed fine */
vlm9de248e2004-10-20 15:50:55 +0000284 ADVANCE(ch_size);
vlm9de248e2004-10-20 15:50:55 +0000285 continue;
vlm9de248e2004-10-20 15:50:55 +0000286 }
vlmb8404852004-10-23 13:27:03 +0000287 /* Fall through */
288 default:
289 break; /* Unexpected tag */
vlm9de248e2004-10-20 15:50:55 +0000290 }
vlmb8404852004-10-23 13:27:03 +0000291
292 ASN_DEBUG("Unexpected XML tag");
vlm9de248e2004-10-20 15:50:55 +0000293 break; /* Dark and mysterious things have just happened */
294 }
295
296 RETURN(RC_FAIL);
297}
298
vlm2a4245f2004-10-22 08:17:16 +0000299
300int
301xer_is_whitespace(void *chunk_buf, size_t chunk_size) {
302 char *p = (char *)chunk_buf;
303 char *pend = p + chunk_size;
304
305 for(; p < pend; p++) {
306 switch(*p) {
307 /* X.693, #8.1.4
308 * HORISONTAL TAB (9)
309 * LINE FEED (10)
310 * CARRIAGE RETURN (13)
311 * SPACE (32)
312 */
313 case 0x09: case 0x0a: case 0x0d: case 0x20:
314 break;
315 default:
316 return 0;
317 }
318 }
319 return 1; /* All whitespace */
320}
321