blob: 39e830d04fb2ac78dddfa1bdc28c1a17cbea218a [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 \
164 (struct_ptr, chunk_buf, chunk_size, \
165 (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 */
180 void *struct_ptr, /* The structure must be already allocated */
181 const char *xml_tag, /* Expected XML tag */
182 void *buf_ptr, size_t size,
183 int (*opt_unexpected_tag_decoder)
184 (void *struct_ptr, void *chunk_buf, size_t chunk_size),
185 ssize_t (*body_receiver)
186 (void *struct_ptr, void *chunk_buf, size_t chunk_size,
187 int have_more)
188 ) {
189
190 asn_dec_rval_t rval;
191 ssize_t consumed_myself = 0;
192 pxer_chunk_type_e ch_type; /* XER chunk type */
193 int xer_state; /* XER low level parsing context */
194
195 (void)opt_codec_ctx;
196
197 /*
198 * Phases of XER/XML processing:
199 * Phase 0: Check that the opening tag matches our expectations.
200 * Phase 1: Processing body and reacting on closing tag.
201 */
202 if(ctx->phase > 1) RETURN(RC_FAIL);
203 for(xer_state = ctx->step;;) {
204 ssize_t ch_size; /* Chunk size */
205 xer_check_tag_e tcv; /* Tag check value */
206
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) {
223 /* Unexpected data */
224 /* TODO: ignore whitespace? */
225 RETURN(RC_FAIL);
226 }
227 XER_GOT_BODY(buf_ptr, ch_size);
228 ADVANCE(ch_size);
229 continue;
230 case PXER_TAG:
231 break; /* Check the rest down there */
232 }
233 }
234
235 assert(ch_type == PXER_TAG && size);
236
237 tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
238 if(ctx->phase == 0) {
239 /*
240 * Expecting the opening tag
241 * for the type being processed.
242 */
243 switch(tcv) {
244 case XCT_BOTH:
245 /* Finished decoding of an empty element */
246 XER_GOT_EMPTY();
247 ADVANCE(ch_size);
248 ctx->phase = 2; /* Phase out */
249 RETURN(RC_OK);
250 case XCT_OPENING:
251 ADVANCE(ch_size);
252 ctx->phase = 1; /* Processing body phase */
253 continue;
254 default:
255 break; /* Unexpected tag */
256 }
257 } else {
258 /*
259 * Waiting for the closing XML tag.
260 */
261 switch(tcv) {
262 case XCT_CLOSING:
263 ADVANCE(ch_size);
264 ctx->phase = 2; /* Phase out */
265 RETURN(RC_OK);
266 case XCT_UNEXPECTED:
267 /*
268 * Certain tags in the body may be expected.
269 */
270 if(opt_unexpected_tag_decoder
271 && opt_unexpected_tag_decoder(struct_ptr,
272 buf_ptr, ch_size) == 0) {
273 /* Tag's processed fine */
274 ADVANCE(ch_size);
275 continue;
276 }
277 /* Fall through */
278 default:
279 break;
280 }
281 ASN_DEBUG("Unexpected XML tag");
282 }
283 break; /* Dark and mysterious things have just happened */
284 }
285
286 RETURN(RC_FAIL);
287}
288