2
* Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
3
* Redistribution and modifications are permitted subject to BSD license.
5
#include <asn_application.h>
6
#include <asn_internal.h>
7
#include <xer_support.h> /* XER/XML parsing support */
11
* Decode the XER encoding of a given type.
14
xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
15
void **struct_ptr, const void *buffer, size_t size) {
16
asn_codec_ctx_t s_codec_ctx;
19
* Stack checker requires that the codec context
20
* must be allocated on the stack.
23
if(opt_codec_ctx->max_stack_size) {
24
s_codec_ctx = *opt_codec_ctx;
25
opt_codec_ctx = &s_codec_ctx;
28
/* If context is not given, be security-conscious anyway */
29
memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
30
s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX;
31
opt_codec_ctx = &s_codec_ctx;
35
* Invoke type-specific decoder.
37
return td->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size);
43
pxml_chunk_type_e chunk_type;
45
const void *chunk_buf;
46
int callback_not_invoked;
50
xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) {
51
struct xer__cb_arg *arg = (struct xer__cb_arg *)key;
52
arg->chunk_type = type;
53
arg->chunk_size = _chunk_size;
54
arg->chunk_buf = _chunk_data;
55
arg->callback_not_invoked = 0;
56
return -1; /* Terminate the XML parsing */
60
* Fetch the next token from the XER/XML stream.
63
xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) {
64
struct xer__cb_arg arg;
65
int new_stateContext = *stateContext;
68
arg.callback_not_invoked = 1;
69
ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg);
70
if(ret < 0) return -1;
71
if(arg.callback_not_invoked) {
72
assert(ret == 0); /* No data was consumed */
73
return 0; /* Try again with more data */
75
assert(arg.chunk_size);
76
assert(arg.chunk_buf == buffer);
80
* Translate the XML chunk types into more convenient ones.
82
switch(arg.chunk_type) {
86
case PXML_TAG: return 0; /* Want more */
91
case PXML_COMMENT_END:
92
*ch_type = PXER_COMMENT;
96
*stateContext = new_stateContext;
97
return arg.chunk_size;
100
#define CSLASH 0x2f /* '/' */
101
#define LANGLE 0x3c /* '<' */
102
#define RANGLE 0x3e /* '>' */
105
xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
106
const char *buf = (const char *)buf_ptr;
108
xer_check_tag_e ct = XCT_OPENING;
110
if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
112
ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]);
117
* Determine the tag class.
119
if(buf[1] == CSLASH) {
120
buf += 2; /* advance past "</" */
121
size -= 3; /* strip "</" and ">" */
123
if(size > 0 && buf[size-1] == CSLASH)
124
return XCT_BROKEN; /* </abc/> */
126
buf++; /* advance past "<" */
127
size -= 2; /* strip "<" and ">" */
128
if(size > 0 && buf[size-1] == CSLASH) {
130
size--; /* One more, for "/" */
134
/* Sometimes we don't care about the tag */
135
if(!need_tag || !*need_tag)
136
return (xer_check_tag_e)(XCT__UNK__MASK | ct);
139
* Determine the tag name.
141
for(end = buf + size; buf < end; buf++, need_tag++) {
142
int b = *buf, n = *need_tag;
146
case 0x09: case 0x0a: case 0x0c: case 0x0d:
148
/* "<abc def/>": whitespace is normal */
152
return (xer_check_tag_e)(XCT__UNK__MASK | ct);
155
return XCT_BROKEN; /* Embedded 0 in buf?! */
158
return (xer_check_tag_e)(XCT__UNK__MASK | ct);
165
#define ADVANCE(num_bytes) do { \
166
size_t num = (num_bytes); \
167
buf_ptr = ((const char *)buf_ptr) + num; \
169
consumed_myself += num; \
173
#define RETURN(_code) do { \
175
rval.consumed = consumed_myself; \
176
if(rval.code != RC_OK) \
177
ASN_DEBUG("Failed with %d", rval.code); \
181
#define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \
182
ssize_t converted_size = body_receiver \
183
(struct_key, chunk_buf, chunk_size, \
184
(size_t)chunk_size < size); \
185
if(converted_size == -1) RETURN(RC_FAIL); \
186
if(converted_size == 0 \
187
&& size == (size_t)chunk_size) \
189
chunk_size = converted_size; \
191
#define XER_GOT_EMPTY() do { \
192
if(body_receiver(struct_key, 0, 0, size > 0) == -1) \
197
* Generalized function for decoding the primitive values.
200
xer_decode_general(asn_codec_ctx_t *opt_codec_ctx,
201
asn_struct_ctx_t *ctx, /* Type decoder context */
203
const char *xml_tag, /* Expected XML tag */
204
const void *buf_ptr, size_t size,
205
int (*opt_unexpected_tag_decoder)
206
(void *struct_key, const void *chunk_buf, size_t chunk_size),
207
ssize_t (*body_receiver)
208
(void *struct_key, const void *chunk_buf, size_t chunk_size,
213
ssize_t consumed_myself = 0;
218
* Phases of XER/XML processing:
219
* Phase 0: Check that the opening tag matches our expectations.
220
* Phase 1: Processing body and reacting on closing tag.
222
if(ctx->phase > 1) RETURN(RC_FAIL);
224
pxer_chunk_type_e ch_type; /* XER chunk type */
225
ssize_t ch_size; /* Chunk size */
226
xer_check_tag_e tcv; /* Tag check value */
229
* Get the next part of the XML stream.
231
ch_size = xer_next_token(&ctx->context, buf_ptr, size,
234
case -1: RETURN(RC_FAIL);
239
case PXER_COMMENT: /* Got XML comment */
240
ADVANCE(ch_size); /* Skip silently */
243
if(ctx->phase == 0) {
245
* We have to ignore whitespace here,
246
* but in order to be forward compatible
247
* with EXTENDED-XER (EMBED-VALUES, #25)
248
* any text is just ignored here.
251
XER_GOT_BODY(buf_ptr, ch_size, size);
256
break; /* Check the rest down there */
260
assert(ch_type == PXER_TAG && size);
262
tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
265
* Expecting the opening tag
266
* for the type being processed.
268
* Waiting for the closing XML tag.
272
if(ctx->phase) break;
273
/* Finished decoding of an empty element */
276
ctx->phase = 2; /* Phase out */
279
if(ctx->phase) break;
281
ctx->phase = 1; /* Processing body phase */
284
if(!ctx->phase) break;
286
ctx->phase = 2; /* Phase out */
290
* Certain tags in the body may be expected.
292
if(opt_unexpected_tag_decoder
293
&& opt_unexpected_tag_decoder(struct_key,
294
buf_ptr, ch_size) >= 0) {
295
/* Tag's processed fine */
298
/* We are not expecting
299
* the closing tag anymore. */
300
ctx->phase = 2; /* Phase out */
307
break; /* Unexpected tag */
310
ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag);
311
break; /* Dark and mysterious things have just happened */
319
xer_is_whitespace(const void *chunk_buf, size_t chunk_size) {
320
const char *p = (const char *)chunk_buf;
321
const char *pend = p + chunk_size;
323
for(; p < pend; p++) {
328
* CARRIAGE RETURN (13)
331
case 0x09: case 0x0a: case 0x0d: case 0x20:
337
return 1; /* All whitespace */
341
* This is a vastly simplified, non-validating XML tree skipper.
344
xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) {
349
/* These negate each other. */
358
return (tcv == XCT_CLOSING) ? 2 : 1;