blob: db27a4971398aa25a2f07aa0701bbe8de1fc7027 [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;
58
59 arg.callback_not_invoked = 1;
60 ret = pxml_parse(stateContext, buffer, size, xer__token_cb, &arg);
61 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
87 return arg.chunk_size;
88}
89
90#define CSLASH 0x2f /* '/' */
91#define LANGLE 0x3c /* '<' */
92#define RANGLE 0x3e /* '>' */
93
94xer_check_tag_e
95xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
96 const char *buf = (const char *)buf_ptr;
97 const char *end;
98 xer_check_tag_e ct = XCT_OPENING;
99
100 if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
101 return XCT_BROKEN;
102 }
103
104 /*
105 * Determine the tag class.
106 */
107 if(buf[1] == CSLASH) {
108 buf += 2; /* advance past "</" */
109 size -= 3; /* strip "</" and ">" */
110 ct = XCT_CLOSING;
111 if(size > 0 && buf[size-1] == CSLASH)
112 return XCT_BROKEN; /* </abc/> */
113 } else {
114 buf++; /* advance past "<" */
115 size -= 2; /* strip "<" and ">" */
116 if(size > 0 && buf[size-1] == CSLASH) {
117 ct = XCT_BOTH;
118 size--; /* One more, for "/" */
119 }
120 }
121
122 /*
123 * Determine the tag name.
124 */
125 for(end = buf + size; buf < end; buf++, need_tag++) {
126 int b = *buf, n = *need_tag;
127 if(b != n) {
128 if(n == 0) {
129 switch(b) {
130 case 0x09: case 0x0a: case 0x0c: case 0x0d:
131 case 0x20:
132 /* "<abc def/>": whitespace is normal */
133 return ct;
134 }
135 }
136 return XCT_UNEXPECTED;
137 }
138 if(b == 0)
139 return XCT_BROKEN; /* Embedded 0 in buf?! */
140 }
141 if(*need_tag) return XCT_UNEXPECTED;
142
143 return ct;
144}
145
146
147#undef ADVANCE
148#define ADVANCE(num_bytes) do { \
149 size_t num = (num_bytes); \
150 buf_ptr = ((char *)buf_ptr) + num; \
151 size -= num; \
152 consumed_myself += num; \
153 } while(0)
154
155#undef RETURN
156#define RETURN(_code) do { \
157 rval.code = _code; \
158 rval.consumed = consumed_myself; \
159 return rval; \
160 } while(0)
161
162#define XER_GOT_BODY(chunk_buf, chunk_size) do { \
163 ssize_t converted_size = body_receiver \
vlm3b6e1122004-10-21 11:22:12 +0000164 (struct_key, chunk_buf, chunk_size, \
vlm9de248e2004-10-20 15:50:55 +0000165 (size_t)chunk_size < size); \
166 if(converted_size == -1) RETURN(RC_FAIL); \
167 chunk_size = converted_size; \
168 } while(0)
169#define XER_GOT_EMPTY() do { \
170 ssize_t chunk_size = 0; \
171 XER_GOT_BODY(0, chunk_size); \
172 } while(0)
173
174/*
175 * Generalized function for decoding the primitive values.
176 */
177asn_dec_rval_t
178xer_decode_general(asn_codec_ctx_t *opt_codec_ctx,
179 asn_struct_ctx_t *ctx, /* Type decoder context */
vlm3b6e1122004-10-21 11:22:12 +0000180 void *struct_key,
vlm9de248e2004-10-20 15:50:55 +0000181 const char *xml_tag, /* Expected XML tag */
182 void *buf_ptr, size_t size,
183 int (*opt_unexpected_tag_decoder)
vlm3b6e1122004-10-21 11:22:12 +0000184 (void *struct_key, void *chunk_buf, size_t chunk_size),
vlm9de248e2004-10-20 15:50:55 +0000185 ssize_t (*body_receiver)
vlm3b6e1122004-10-21 11:22:12 +0000186 (void *struct_key, void *chunk_buf, size_t chunk_size,
vlm9de248e2004-10-20 15:50:55 +0000187 int have_more)
188 ) {
189
190 asn_dec_rval_t rval;
191 ssize_t consumed_myself = 0;
vlm9de248e2004-10-20 15:50:55 +0000192 int xer_state; /* XER low level parsing context */
193
194 (void)opt_codec_ctx;
195
196 /*
197 * Phases of XER/XML processing:
198 * Phase 0: Check that the opening tag matches our expectations.
199 * Phase 1: Processing body and reacting on closing tag.
200 */
201 if(ctx->phase > 1) RETURN(RC_FAIL);
202 for(xer_state = ctx->step;;) {
vlmb8404852004-10-23 13:27:03 +0000203 pxer_chunk_type_e ch_type; /* XER chunk type */
204 ssize_t ch_size; /* Chunk size */
205 xer_check_tag_e tcv; /* Tag check value */
vlm9de248e2004-10-20 15:50:55 +0000206
207 /*
208 * Get the next part of the XML stream.
209 */
210 ch_size = xer_next_token(&xer_state, buf_ptr, size, &ch_type);
211 switch(ch_size) {
212 case -1: RETURN(RC_FAIL);
213 case 0:
214 ctx->step = xer_state;
215 RETURN(RC_WMORE);
216 default:
217 switch(ch_type) {
218 case PXER_COMMENT: /* Got XML comment */
219 ADVANCE(ch_size); /* Skip silently */
220 continue;
221 case PXER_TEXT:
222 if(ctx->phase == 0) {
vlm7958f112004-10-21 05:44:11 +0000223 /*
224 * We have to ignore whitespace here,
225 * but in order to be forward compatible
226 * with EXTENDED-XER (EMBED-VALUES, #25)
227 * any text is just ignored here.
228 */
229 } else {
230 XER_GOT_BODY(buf_ptr, ch_size);
vlm9de248e2004-10-20 15:50:55 +0000231 }
vlm9de248e2004-10-20 15:50:55 +0000232 ADVANCE(ch_size);
233 continue;
234 case PXER_TAG:
235 break; /* Check the rest down there */
236 }
237 }
238
239 assert(ch_type == PXER_TAG && size);
240
241 tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
vlmb8404852004-10-23 13:27:03 +0000242 /*
243 * Phase 0:
244 * Expecting the opening tag
245 * for the type being processed.
246 * Phase 1:
247 * Waiting for the closing XML tag.
248 */
249 switch(tcv) {
250 case XCT_BOTH:
251 if(ctx->phase) break;
252 /* Finished decoding of an empty element */
253 XER_GOT_EMPTY();
254 ADVANCE(ch_size);
255 ctx->phase = 2; /* Phase out */
256 RETURN(RC_OK);
257 case XCT_OPENING:
258 if(ctx->phase) break;
259 ADVANCE(ch_size);
260 ctx->phase = 1; /* Processing body phase */
261 continue;
262 case XCT_CLOSING:
263 if(!ctx->phase) break;
264 ADVANCE(ch_size);
265 ctx->phase = 2; /* Phase out */
266 RETURN(RC_OK);
267 case XCT_UNEXPECTED:
268 if(!ctx->phase) break;
vlm9de248e2004-10-20 15:50:55 +0000269 /*
vlmb8404852004-10-23 13:27:03 +0000270 * Certain tags in the body may be expected.
vlm9de248e2004-10-20 15:50:55 +0000271 */
vlmb8404852004-10-23 13:27:03 +0000272 if(opt_unexpected_tag_decoder
273 && opt_unexpected_tag_decoder(struct_key,
274 buf_ptr, ch_size) == 0) {
275 /* Tag's processed fine */
vlm9de248e2004-10-20 15:50:55 +0000276 ADVANCE(ch_size);
vlm9de248e2004-10-20 15:50:55 +0000277 continue;
vlm9de248e2004-10-20 15:50:55 +0000278 }
vlmb8404852004-10-23 13:27:03 +0000279 /* Fall through */
280 default:
281 break; /* Unexpected tag */
vlm9de248e2004-10-20 15:50:55 +0000282 }
vlmb8404852004-10-23 13:27:03 +0000283
284 ASN_DEBUG("Unexpected XML tag");
vlm9de248e2004-10-20 15:50:55 +0000285 break; /* Dark and mysterious things have just happened */
286 }
287
288 RETURN(RC_FAIL);
289}
290
vlm2a4245f2004-10-22 08:17:16 +0000291
292int
293xer_is_whitespace(void *chunk_buf, size_t chunk_size) {
294 char *p = (char *)chunk_buf;
295 char *pend = p + chunk_size;
296
297 for(; p < pend; p++) {
298 switch(*p) {
299 /* X.693, #8.1.4
300 * HORISONTAL TAB (9)
301 * LINE FEED (10)
302 * CARRIAGE RETURN (13)
303 * SPACE (32)
304 */
305 case 0x09: case 0x0a: case 0x0d: case 0x20:
306 break;
307 default:
308 return 0;
309 }
310 }
311 return 1; /* All whitespace */
312}
313