~ubuntu-branches/ubuntu/raring/freerdp/raring

« back to all changes in this revision

Viewing changes to asn1/xer_decoder.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2010-06-23 21:39:09 UTC
  • Revision ID: james.westby@ubuntu.com-20100623213909-bb9pvvv03913tdv6
Tags: upstream-0.7.1
ImportĀ upstreamĀ versionĀ 0.7.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
13
asn_dec_rval_t
 
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;
 
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));
 
30
                s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX;
 
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 {
 
43
        pxml_chunk_type_e       chunk_type;
 
44
        size_t                  chunk_size;
 
45
        const void              *chunk_buf;
 
46
        int callback_not_invoked;
 
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
 
 
104
xer_check_tag_e
 
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;
 
108
        xer_check_tag_e ct = XCT_OPENING;
 
109
 
 
110
        if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) {
 
111
                if(size >= 2)
 
112
                ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]);
 
113
                return XCT_BROKEN;
 
114
        }
 
115
 
 
116
        /*
 
117
         * Determine the tag class.
 
118
         */
 
119
        if(buf[1] == CSLASH) {
 
120
                buf += 2;       /* advance past "</" */
 
121
                size -= 3;      /* strip "</" and ">" */
 
122
                ct = XCT_CLOSING;
 
123
                if(size > 0 && buf[size-1] == CSLASH)
 
124
                        return XCT_BROKEN;      /* </abc/> */
 
125
        } else {
 
126
                buf++;          /* advance past "<" */
 
127
                size -= 2;      /* strip "<" and ">" */
 
128
                if(size > 0 && buf[size-1] == CSLASH) {
 
129
                        ct = XCT_BOTH;
 
130
                        size--; /* One more, for "/" */
 
131
                }
 
132
        }
 
133
 
 
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);
 
137
 
 
138
        /*
 
139
         * Determine the tag name.
 
140
         */
 
141
        for(end = buf + size; buf < end; buf++, need_tag++) {
 
142
                int b = *buf, n = *need_tag;
 
143
                if(b != n) {
 
144
                        if(n == 0) {
 
145
                                switch(b) {
 
146
                                case 0x09: case 0x0a: case 0x0c: case 0x0d:
 
147
                                case 0x20:
 
148
                                        /* "<abc def/>": whitespace is normal */
 
149
                                        return ct;
 
150
                                }
 
151
                        }
 
152
                        return (xer_check_tag_e)(XCT__UNK__MASK | ct);
 
153
                }
 
154
                if(b == 0)
 
155
                        return XCT_BROKEN;      /* Embedded 0 in buf?! */
 
156
        }
 
157
        if(*need_tag)
 
158
                return (xer_check_tag_e)(XCT__UNK__MASK | ct);
 
159
 
 
160
        return ct;
 
161
}
 
162
 
 
163
 
 
164
#undef  ADVANCE
 
165
#define ADVANCE(num_bytes)      do {                            \
 
166
                size_t num = (num_bytes);                       \
 
167
                buf_ptr = ((const char *)buf_ptr) + num;        \
 
168
                size -= num;                                    \
 
169
                consumed_myself += num;                         \
 
170
        } while(0)
 
171
 
 
172
#undef  RETURN
 
173
#define RETURN(_code)   do {                                    \
 
174
                rval.code = _code;                              \
 
175
                rval.consumed = consumed_myself;                \
 
176
                if(rval.code != RC_OK)                          \
 
177
                        ASN_DEBUG("Failed with %d", rval.code); \
 
178
                return rval;                                    \
 
179
        } while(0)
 
180
 
 
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)          \
 
188
                        RETURN(RC_WMORE);                       \
 
189
                chunk_size = converted_size;                    \
 
190
        } while(0)
 
191
#define XER_GOT_EMPTY() do {                                    \
 
192
        if(body_receiver(struct_key, 0, 0, size > 0) == -1)     \
 
193
                        RETURN(RC_FAIL);                        \
 
194
        } while(0)
 
195
 
 
196
/*
 
197
 * Generalized function for decoding the primitive values.
 
198
 */
 
199
asn_dec_rval_t
 
200
xer_decode_general(asn_codec_ctx_t *opt_codec_ctx,
 
201
        asn_struct_ctx_t *ctx,  /* Type decoder context */
 
202
        void *struct_key,
 
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,
 
209
                        int have_more)
 
210
        ) {
 
211
 
 
212
        asn_dec_rval_t rval;
 
213
        ssize_t consumed_myself = 0;
 
214
 
 
215
        (void)opt_codec_ctx;
 
216
 
 
217
        /*
 
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.
 
221
         */
 
222
        if(ctx->phase > 1) RETURN(RC_FAIL);
 
223
        for(;;) {
 
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 */
 
227
 
 
228
                /*
 
229
                 * Get the next part of the XML stream.
 
230
                 */
 
231
                ch_size = xer_next_token(&ctx->context, buf_ptr, size,
 
232
                        &ch_type);
 
233
                switch(ch_size) {
 
234
                case -1: RETURN(RC_FAIL);
 
235
                case 0:
 
236
                        RETURN(RC_WMORE);
 
237
                default:
 
238
                        switch(ch_type) {
 
239
                        case PXER_COMMENT:              /* Got XML comment */
 
240
                                ADVANCE(ch_size);       /* Skip silently */
 
241
                                continue;
 
242
                        case PXER_TEXT:
 
243
                                if(ctx->phase == 0) {
 
244
                                        /*
 
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.
 
249
                                         */
 
250
                                } else {
 
251
                                        XER_GOT_BODY(buf_ptr, ch_size, size);
 
252
                                }
 
253
                                ADVANCE(ch_size);
 
254
                                continue;
 
255
                        case PXER_TAG:
 
256
                                break;  /* Check the rest down there */
 
257
                        }
 
258
                }
 
259
 
 
260
                assert(ch_type == PXER_TAG && size);
 
261
 
 
262
                tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
 
263
                /*
 
264
                 * Phase 0:
 
265
                 *      Expecting the opening tag
 
266
                 *      for the type being processed.
 
267
                 * Phase 1:
 
268
                 *      Waiting for the closing XML tag.
 
269
                 */
 
270
                switch(tcv) {
 
271
                case XCT_BOTH:
 
272
                        if(ctx->phase) break;
 
273
                        /* Finished decoding of an empty element */
 
274
                        XER_GOT_EMPTY();
 
275
                        ADVANCE(ch_size);
 
276
                        ctx->phase = 2; /* Phase out */
 
277
                        RETURN(RC_OK);
 
278
                case XCT_OPENING:
 
279
                        if(ctx->phase) break;
 
280
                        ADVANCE(ch_size);
 
281
                        ctx->phase = 1; /* Processing body phase */
 
282
                        continue;
 
283
                case XCT_CLOSING:
 
284
                        if(!ctx->phase) break;
 
285
                        ADVANCE(ch_size);
 
286
                        ctx->phase = 2; /* Phase out */
 
287
                        RETURN(RC_OK);
 
288
                case XCT_UNKNOWN_BO:
 
289
                        /*
 
290
                         * Certain tags in the body may be expected.
 
291
                         */
 
292
                        if(opt_unexpected_tag_decoder
 
293
                        && opt_unexpected_tag_decoder(struct_key,
 
294
                                        buf_ptr, ch_size) >= 0) {
 
295
                                /* Tag's processed fine */
 
296
                                ADVANCE(ch_size);
 
297
                                if(!ctx->phase) {
 
298
                                        /* We are not expecting
 
299
                                         * the closing tag anymore. */
 
300
                                        ctx->phase = 2; /* Phase out */
 
301
                                        RETURN(RC_OK);
 
302
                                }
 
303
                                continue;
 
304
                        }
 
305
                        /* Fall through */
 
306
                default:
 
307
                        break;          /* Unexpected tag */
 
308
                }
 
309
 
 
310
                ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag);
 
311
                break;  /* Dark and mysterious things have just happened */
 
312
        }
 
313
 
 
314
        RETURN(RC_FAIL);
 
315
}
 
316
 
 
317
 
 
318
int
 
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;
 
322
 
 
323
        for(; p < pend; p++) {
 
324
                switch(*p) {
 
325
                /* X.693, #8.1.4
 
326
                 * HORISONTAL TAB (9)
 
327
                 * LINE FEED (10) 
 
328
                 * CARRIAGE RETURN (13) 
 
329
                 * SPACE (32)
 
330
                 */
 
331
                case 0x09: case 0x0a: case 0x0d: case 0x20:
 
332
                        break;
 
333
                default:
 
334
                        return 0;
 
335
                }
 
336
        }
 
337
        return 1;       /* All whitespace */
 
338
}
 
339
 
 
340
/*
 
341
 * This is a vastly simplified, non-validating XML tree skipper.
 
342
 */
 
343
int
 
344
xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) {
 
345
        assert(*depth > 0);
 
346
        switch(tcv) {
 
347
        case XCT_BOTH:
 
348
        case XCT_UNKNOWN_BO:
 
349
                /* These negate each other. */
 
350
                return 0;
 
351
        case XCT_OPENING:
 
352
        case XCT_UNKNOWN_OP:
 
353
                ++(*depth);
 
354
                return 0;
 
355
        case XCT_CLOSING:
 
356
        case XCT_UNKNOWN_CL:
 
357
                if(--(*depth) == 0)
 
358
                        return (tcv == XCT_CLOSING) ? 2 : 1;
 
359
                return 0;
 
360
        default:
 
361
                return -1;
 
362
        }
 
363
}