1 /*****************************************************************************
3 # Copyright 2019 AT&T Intellectual Property *
5 # Licensed under the Apache License, Version 2.0 (the "License"); *
6 # you may not use this file except in compliance with the License. *
7 # You may obtain a copy of the License at *
9 # http://www.apache.org/licenses/LICENSE-2.0 *
11 # Unless required by applicable law or agreed to in writing, software *
12 # distributed under the License is distributed on an "AS IS" BASIS, *
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
14 # See the License for the specific language governing permissions and *
15 # limitations under the License. *
17 ******************************************************************************/
20 * Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
21 * Redistribution and modifications are permitted subject to BSD license.
23 #include <asn_application.h>
24 #include <asn_internal.h>
25 #include <xer_support.h> /* XER/XML parsing support */
29 * Decode the XER encoding of a given type.
32 xer_decode(const asn_codec_ctx_t *opt_codec_ctx,
33 const asn_TYPE_descriptor_t *td, void **struct_ptr,
34 const void *buffer, size_t size) {
35 asn_codec_ctx_t s_codec_ctx;
38 * Stack checker requires that the codec context
39 * must be allocated on the stack.
42 if(opt_codec_ctx->max_stack_size) {
43 s_codec_ctx = *opt_codec_ctx;
44 opt_codec_ctx = &s_codec_ctx;
47 /* If context is not given, be security-conscious anyway */
48 memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
49 s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX;
50 opt_codec_ctx = &s_codec_ctx;
54 * Invoke type-specific decoder.
56 return td->op->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size);
62 pxml_chunk_type_e chunk_type;
64 const void *chunk_buf;
65 int callback_not_invoked;
69 xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) {
70 struct xer__cb_arg *arg = (struct xer__cb_arg *)key;
71 arg->chunk_type = type;
72 arg->chunk_size = _chunk_size;
73 arg->chunk_buf = _chunk_data;
74 arg->callback_not_invoked = 0;
75 return -1; /* Terminate the XML parsing */
79 * Fetch the next token from the XER/XML stream.
82 xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) {
83 struct xer__cb_arg arg;
84 int new_stateContext = *stateContext;
87 arg.callback_not_invoked = 1;
88 ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg);
89 if(ret < 0) return -1;
90 if(arg.callback_not_invoked) {
91 assert(ret == 0); /* No data was consumed */
92 *ch_type = PXER_WMORE;
93 return 0; /* Try again with more data */
95 assert(arg.chunk_size);
96 assert(arg.chunk_buf == buffer);
100 * Translate the XML chunk types into more convenient ones.
102 switch(arg.chunk_type) {
104 *ch_type = PXER_TEXT;
107 *ch_type = PXER_WMORE;
108 return 0; /* Want more */
113 case PXML_COMMENT_END:
114 *ch_type = PXER_COMMENT;
118 *stateContext = new_stateContext;
119 return arg.chunk_size;
122 #define CSLASH 0x2f /* '/' */
123 #define LANGLE 0x3c /* '<' */
124 #define RANGLE 0x3e /* '>' */
127 xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
128 const char *buf = (const char *)buf_ptr;
130 xer_check_tag_e ct = XCT_OPENING;
132 if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
134 ASN_DEBUG("Broken XML tag: \"%c...%c\"",
135 buf[0], buf[size - 1]);
140 * Determine the tag class.
142 if(buf[1] == CSLASH) {
143 buf += 2; /* advance past "</" */
144 size -= 3; /* strip "</" and ">" */
146 if(size > 0 && buf[size-1] == CSLASH)
147 return XCT_BROKEN; /* </abc/> */
149 buf++; /* advance past "<" */
150 size -= 2; /* strip "<" and ">" */
151 if(size > 0 && buf[size-1] == CSLASH) {
153 size--; /* One more, for "/" */
157 /* Sometimes we don't care about the tag */
158 if(!need_tag || !*need_tag)
159 return (xer_check_tag_e)(XCT__UNK__MASK | ct);
162 * Determine the tag name.
164 for(end = buf + size; buf < end; buf++, need_tag++) {
165 int b = *buf, n = *need_tag;
169 case 0x09: case 0x0a: case 0x0c: case 0x0d:
171 /* "<abc def/>": whitespace is normal */
175 return (xer_check_tag_e)(XCT__UNK__MASK | ct);
178 return XCT_BROKEN; /* Embedded 0 in buf?! */
181 return (xer_check_tag_e)(XCT__UNK__MASK | ct);
188 #define ADVANCE(num_bytes) do { \
189 size_t num = (num_bytes); \
190 buf_ptr = ((const char *)buf_ptr) + num; \
192 consumed_myself += num; \
196 #define RETURN(_code) do { \
198 rval.consumed = consumed_myself; \
199 if(rval.code != RC_OK) \
200 ASN_DEBUG("Failed with %d", rval.code); \
204 #define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \
205 ssize_t converted_size = body_receiver \
206 (struct_key, chunk_buf, chunk_size, \
207 (size_t)chunk_size < size); \
208 if(converted_size == -1) RETURN(RC_FAIL); \
209 if(converted_size == 0 \
210 && size == (size_t)chunk_size) \
212 chunk_size = converted_size; \
214 #define XER_GOT_EMPTY() do { \
215 if(body_receiver(struct_key, 0, 0, size > 0) == -1) \
220 * Generalized function for decoding the primitive values.
223 xer_decode_general(const asn_codec_ctx_t *opt_codec_ctx,
224 asn_struct_ctx_t *ctx, /* Type decoder context */
226 const char *xml_tag, /* Expected XML tag */
227 const void *buf_ptr, size_t size,
228 int (*opt_unexpected_tag_decoder)
229 (void *struct_key, const void *chunk_buf, size_t chunk_size),
230 ssize_t (*body_receiver)
231 (void *struct_key, const void *chunk_buf, size_t chunk_size,
236 ssize_t consumed_myself = 0;
241 * Phases of XER/XML processing:
242 * Phase 0: Check that the opening tag matches our expectations.
243 * Phase 1: Processing body and reacting on closing tag.
245 if(ctx->phase > 1) RETURN(RC_FAIL);
247 pxer_chunk_type_e ch_type; /* XER chunk type */
248 ssize_t ch_size; /* Chunk size */
249 xer_check_tag_e tcv; /* Tag check value */
252 * Get the next part of the XML stream.
254 ch_size = xer_next_token(&ctx->context, buf_ptr, size,
262 case PXER_COMMENT: /* Got XML comment */
263 ADVANCE(ch_size); /* Skip silently */
266 if(ctx->phase == 0) {
268 * We have to ignore whitespace here,
269 * but in order to be forward compatible
270 * with EXTENDED-XER (EMBED-VALUES, #25)
271 * any text is just ignored here.
274 XER_GOT_BODY(buf_ptr, ch_size, size);
279 break; /* Check the rest down there */
283 assert(ch_type == PXER_TAG && size);
285 tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
288 * Expecting the opening tag
289 * for the type being processed.
291 * Waiting for the closing XML tag.
295 if(ctx->phase) break;
296 /* Finished decoding of an empty element */
299 ctx->phase = 2; /* Phase out */
302 if(ctx->phase) break;
304 ctx->phase = 1; /* Processing body phase */
307 if(!ctx->phase) break;
309 ctx->phase = 2; /* Phase out */
313 * Certain tags in the body may be expected.
315 if(opt_unexpected_tag_decoder
316 && opt_unexpected_tag_decoder(struct_key,
317 buf_ptr, ch_size) >= 0) {
318 /* Tag's processed fine */
321 /* We are not expecting
322 * the closing tag anymore. */
323 ctx->phase = 2; /* Phase out */
330 break; /* Unexpected tag */
333 ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag);
334 break; /* Dark and mysterious things have just happened */
342 xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {
343 const char *p = (const char *)chunk_buf;
344 const char *pend = p + chunk_size;
346 for(; p < pend; p++) {
351 * CARRIAGE RETURN (13)
354 case 0x09: case 0x0a: case 0x0d: case 0x20:
361 return (p - (const char *)chunk_buf);
365 * This is a vastly simplified, non-validating XML tree skipper.
368 xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) {
373 /* These negate each other. */
382 return (tcv == XCT_CLOSING) ? 2 : 1;