ITS
xer_decoder.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
3  * Redistribution and modifications are permitted subject to BSD license.
4  */
5 #include <asn_application.h>
6 #include <asn_internal.h>
7 #include <xer_support.h> /* XER/XML parsing support */
8 
9 
10 /*
11  * Decode the XER encoding of a given type.
12  */
15  void **struct_ptr, const void *buffer, size_t size) {
16  asn_codec_ctx_t s_codec_ctx;
17 
18  /*
19  * Stack checker requires that the codec context
20  * must be allocated on the stack.
21  */
22  if(opt_codec_ctx) {
23  if(opt_codec_ctx->max_stack_size) {
24  s_codec_ctx = *opt_codec_ctx;
25  opt_codec_ctx = &s_codec_ctx;
26  }
27  } else {
28  /* If context is not given, be security-conscious anyway */
29  memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
31  opt_codec_ctx = &s_codec_ctx;
32  }
33 
34  /*
35  * Invoke type-specific decoder.
36  */
37  return td->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size);
38 }
39 
40 
41 
42 struct xer__cb_arg {
44  size_t chunk_size;
45  const void *chunk_buf;
47 };
48 
49 static int
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 */
57 }
58 
59 /*
60  * Fetch the next token from the XER/XML stream.
61  */
62 ssize_t
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;
66  ssize_t ret;
67 
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 */
74  } else {
75  assert(arg.chunk_size);
76  assert(arg.chunk_buf == buffer);
77  }
78 
79  /*
80  * Translate the XML chunk types into more convenient ones.
81  */
82  switch(arg.chunk_type) {
83  case PXML_TEXT:
84  *ch_type = PXER_TEXT;
85  break;
86  case PXML_TAG: return 0; /* Want more */
87  case PXML_TAG_END:
88  *ch_type = PXER_TAG;
89  break;
90  case PXML_COMMENT:
91  case PXML_COMMENT_END:
92  *ch_type = PXER_COMMENT;
93  break;
94  }
95 
96  *stateContext = new_stateContext;
97  return arg.chunk_size;
98 }
99 
100 #define CSLASH 0x2f /* '/' */
101 #define LANGLE 0x3c /* '<' */
102 #define RANGLE 0x3e /* '>' */
103 
105 xer_check_tag(const void *buf_ptr, int size, const char *need_tag) {
106  const char *buf = (const char *)buf_ptr;
107  const char *end;
109 
110  if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
111  if(size >= 2)
112  ASN_DEBUG("Broken XML tag: \"%c...%c\"",
113  buf[0], buf[size - 1]);
114  return XCT_BROKEN;
115  }
116 
117  /*
118  * Determine the tag class.
119  */
120  if(buf[1] == CSLASH) {
121  buf += 2; /* advance past "</" */
122  size -= 3; /* strip "</" and ">" */
123  ct = XCT_CLOSING;
124  if(size > 0 && buf[size-1] == CSLASH)
125  return XCT_BROKEN; /* </abc/> */
126  } else {
127  buf++; /* advance past "<" */
128  size -= 2; /* strip "<" and ">" */
129  if(size > 0 && buf[size-1] == CSLASH) {
130  ct = XCT_BOTH;
131  size--; /* One more, for "/" */
132  }
133  }
134 
135  /* Sometimes we don't care about the tag */
136  if(!need_tag || !*need_tag)
137  return (xer_check_tag_e)(XCT__UNK__MASK | ct);
138 
139  /*
140  * Determine the tag name.
141  */
142  for(end = buf + size; buf < end; buf++, need_tag++) {
143  int b = *buf, n = *need_tag;
144  if(b != n) {
145  if(n == 0) {
146  switch(b) {
147  case 0x09: case 0x0a: case 0x0c: case 0x0d:
148  case 0x20:
149  /* "<abc def/>": whitespace is normal */
150  return ct;
151  }
152  }
153  return (xer_check_tag_e)(XCT__UNK__MASK | ct);
154  }
155  if(b == 0)
156  return XCT_BROKEN; /* Embedded 0 in buf?! */
157  }
158  if(*need_tag)
159  return (xer_check_tag_e)(XCT__UNK__MASK | ct);
160 
161  return ct;
162 }
163 
164 
165 #undef ADVANCE
166 #define ADVANCE(num_bytes) do { \
167  size_t num = (num_bytes); \
168  buf_ptr = ((const char *)buf_ptr) + num; \
169  size -= num; \
170  consumed_myself += num; \
171  } while(0)
172 
173 #undef RETURN
174 #define RETURN(_code) do { \
175  rval.code = _code; \
176  rval.consumed = consumed_myself; \
177  if(rval.code != RC_OK) \
178  ASN_DEBUG("Failed with %d", rval.code); \
179  return rval; \
180  } while(0)
181 
182 #define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \
183  ssize_t converted_size = body_receiver \
184  (struct_key, chunk_buf, chunk_size, \
185  (size_t)chunk_size < size); \
186  if(converted_size == -1) RETURN(RC_FAIL); \
187  if(converted_size == 0 \
188  && size == (size_t)chunk_size) \
189  RETURN(RC_WMORE); \
190  chunk_size = converted_size; \
191  } while(0)
192 #define XER_GOT_EMPTY() do { \
193  if(body_receiver(struct_key, 0, 0, size > 0) == -1) \
194  RETURN(RC_FAIL); \
195  } while(0)
196 
197 /*
198  * Generalized function for decoding the primitive values.
199  */
202  asn_struct_ctx_t *ctx, /* Type decoder context */
203  void *struct_key,
204  const char *xml_tag, /* Expected XML tag */
205  const void *buf_ptr, size_t size,
206  int (*opt_unexpected_tag_decoder)
207  (void *struct_key, const void *chunk_buf, size_t chunk_size),
208  ssize_t (*body_receiver)
209  (void *struct_key, const void *chunk_buf, size_t chunk_size,
210  int have_more)
211  ) {
212 
213  asn_dec_rval_t rval;
214  ssize_t consumed_myself = 0;
215 
216  (void)opt_codec_ctx;
217 
218  /*
219  * Phases of XER/XML processing:
220  * Phase 0: Check that the opening tag matches our expectations.
221  * Phase 1: Processing body and reacting on closing tag.
222  */
223  if(ctx->phase > 1) RETURN(RC_FAIL);
224  for(;;) {
225  pxer_chunk_type_e ch_type; /* XER chunk type */
226  ssize_t ch_size; /* Chunk size */
227  xer_check_tag_e tcv; /* Tag check value */
228 
229  /*
230  * Get the next part of the XML stream.
231  */
232  ch_size = xer_next_token(&ctx->context, buf_ptr, size,
233  &ch_type);
234  switch(ch_size) {
235  case -1: RETURN(RC_FAIL);
236  case 0:
237  RETURN(RC_WMORE);
238  default:
239  switch(ch_type) {
240  case PXER_COMMENT: /* Got XML comment */
241  ADVANCE(ch_size); /* Skip silently */
242  continue;
243  case PXER_TEXT:
244  if(ctx->phase == 0) {
245  /*
246  * We have to ignore whitespace here,
247  * but in order to be forward compatible
248  * with EXTENDED-XER (EMBED-VALUES, #25)
249  * any text is just ignored here.
250  */
251  } else {
252  XER_GOT_BODY(buf_ptr, ch_size, size);
253  }
254  ADVANCE(ch_size);
255  continue;
256  case PXER_TAG:
257  break; /* Check the rest down there */
258  }
259  }
260 
261  assert(ch_type == PXER_TAG && size);
262 
263  tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
264  /*
265  * Phase 0:
266  * Expecting the opening tag
267  * for the type being processed.
268  * Phase 1:
269  * Waiting for the closing XML tag.
270  */
271  switch(tcv) {
272  case XCT_BOTH:
273  if(ctx->phase) break;
274  /* Finished decoding of an empty element */
275  XER_GOT_EMPTY();
276  ADVANCE(ch_size);
277  ctx->phase = 2; /* Phase out */
278  RETURN(RC_OK);
279  case XCT_OPENING:
280  if(ctx->phase) break;
281  ADVANCE(ch_size);
282  ctx->phase = 1; /* Processing body phase */
283  continue;
284  case XCT_CLOSING:
285  if(!ctx->phase) break;
286  ADVANCE(ch_size);
287  ctx->phase = 2; /* Phase out */
288  RETURN(RC_OK);
289  case XCT_UNKNOWN_BO:
290  /*
291  * Certain tags in the body may be expected.
292  */
293  if(opt_unexpected_tag_decoder
294  && opt_unexpected_tag_decoder(struct_key,
295  buf_ptr, ch_size) >= 0) {
296  /* Tag's processed fine */
297  ADVANCE(ch_size);
298  if(!ctx->phase) {
299  /* We are not expecting
300  * the closing tag anymore. */
301  ctx->phase = 2; /* Phase out */
302  RETURN(RC_OK);
303  }
304  continue;
305  }
306  /* Fall through */
307  default:
308  break; /* Unexpected tag */
309  }
310 
311  ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag);
312  break; /* Dark and mysterious things have just happened */
313  }
314 
315  RETURN(RC_FAIL);
316 }
317 
318 
319 size_t
321  const char *p = (const char *)chunk_buf;
322  const char *pend = p + chunk_size;
323 
324  for(; p < pend; p++) {
325  switch(*p) {
326  /* X.693, #8.1.4
327  * HORISONTAL TAB (9)
328  * LINE FEED (10)
329  * CARRIAGE RETURN (13)
330  * SPACE (32)
331  */
332  case 0x09: case 0x0a: case 0x0d: case 0x20:
333  continue;
334  default:
335  break;
336  }
337  break;
338  }
339  return (p - (const char *)chunk_buf);
340 }
341 
342 /*
343  * This is a vastly simplified, non-validating XML tree skipper.
344  */
345 int
347  assert(*depth > 0);
348  switch(tcv) {
349  case XCT_BOTH:
350  case XCT_UNKNOWN_BO:
351  /* These negate each other. */
352  return 0;
353  case XCT_OPENING:
354  case XCT_UNKNOWN_OP:
355  ++(*depth);
356  return 0;
357  case XCT_CLOSING:
358  case XCT_UNKNOWN_CL:
359  if(--(*depth) == 0)
360  return (tcv == XCT_CLOSING) ? 2 : 1;
361  return 0;
362  default:
363  return -1;
364  }
365 }
#define _ASN_DEFAULT_STACK_MAX
Definition: asn_internal.h:103
size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size)
Definition: xer_decoder.c:320
const void * chunk_buf
Definition: xer_decoder.c:45
#define LANGLE
Definition: xer_decoder.c:101
xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, const char *need_tag)
Definition: xer_decoder.c:105
static int xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key)
Definition: xer_decoder.c:50
#define RANGLE
Definition: xer_decoder.c:102
#define CSLASH
Definition: xer_decoder.c:100
ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, pxml_callback_f *cb, void *_key)
Definition: xer_support.c:88
ssize_t ber_tlv_len_t
pxml_chunk_type_e chunk_type
Definition: xer_decoder.c:43
int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth)
Definition: xer_decoder.c:346
pxml_chunk_type_e
Definition: xer_support.h:18
ssize_t xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type)
Definition: xer_decoder.c:63
size_t chunk_size
Definition: xer_decoder.c:44
enum xer_check_tag xer_check_tag_e
#define XER_GOT_EMPTY()
Definition: xer_decoder.c:192
asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, asn_struct_ctx_t *ctx, void *struct_key, const char *xml_tag, const void *buf_ptr, size_t size, int(*opt_unexpected_tag_decoder)(void *struct_key, const void *chunk_buf, size_t chunk_size), ssize_t(*body_receiver)(void *struct_key, const void *chunk_buf, size_t chunk_size, int have_more))
Definition: xer_decoder.c:201
xer_type_decoder_f * xer_decoder
Definition: constr_TYPE.h:98
size_t max_stack_size
Definition: asn_codecs.h:36
static void ASN_DEBUG(const char *fmt,...)
Definition: asn_internal.h:62
#define XER_GOT_BODY(chunk_buf, chunk_size, size)
Definition: xer_decoder.c:182
asn_dec_rval_t xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **struct_ptr, const void *buffer, size_t size)
Definition: xer_decoder.c:14
int callback_not_invoked
Definition: xer_decoder.c:46
#define RETURN(_code)
Definition: xer_decoder.c:174
#define ADVANCE(num_bytes)
Definition: xer_decoder.c:166
enum pxer_chunk_type pxer_chunk_type_e