~ubuntu-branches/ubuntu/quantal/freerdp/quantal

« back to all changes in this revision

Viewing changes to asn1/constr_CHOICE.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) 2003, 2004, 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>.
 
3
 * All rights reserved.
 
4
 * Redistribution and modifications are permitted subject to BSD license.
 
5
 */
 
6
#include <asn_internal.h>
 
7
#include <constr_CHOICE.h>
 
8
#include <per_opentype.h>
 
9
 
 
10
/*
 
11
 * Number of bytes left for this structure.
 
12
 * (ctx->left) indicates the number of bytes _transferred_ for the structure.
 
13
 * (size) contains the number of bytes in the buffer passed.
 
14
 */
 
15
#define LEFT    ((size<(size_t)ctx->left)?size:(size_t)ctx->left)
 
16
 
 
17
/*
 
18
 * If the subprocessor function returns with an indication that it wants
 
19
 * more data, it may well be a fatal decoding problem, because the
 
20
 * size is constrained by the <TLV>'s L, even if the buffer size allows
 
21
 * reading more data.
 
22
 * For example, consider the buffer containing the following TLVs:
 
23
 * <T:5><L:1><V> <T:6>...
 
24
 * The TLV length clearly indicates that one byte is expected in V, but
 
25
 * if the V processor returns with "want more data" even if the buffer
 
26
 * contains way more data than the V processor have seen.
 
27
 */
 
28
#define SIZE_VIOLATION  (ctx->left >= 0 && (size_t)ctx->left <= size)
 
29
 
 
30
/*
 
31
 * This macro "eats" the part of the buffer which is definitely "consumed",
 
32
 * i.e. was correctly converted into local representation or rightfully skipped.
 
33
 */
 
34
#undef  ADVANCE
 
35
#define ADVANCE(num_bytes)      do {            \
 
36
                size_t num = num_bytes;         \
 
37
                ptr = ((const char *)ptr) + num;\
 
38
                size -= num;                    \
 
39
                if(ctx->left >= 0)              \
 
40
                        ctx->left -= num;       \
 
41
                consumed_myself += num;         \
 
42
        } while(0)
 
43
 
 
44
/*
 
45
 * Switch to the next phase of parsing.
 
46
 */
 
47
#undef  NEXT_PHASE
 
48
#define NEXT_PHASE(ctx) do {                    \
 
49
                ctx->phase++;                   \
 
50
                ctx->step = 0;                  \
 
51
        } while(0)
 
52
 
 
53
/*
 
54
 * Return a standardized complex structure.
 
55
 */
 
56
#undef  RETURN
 
57
#define RETURN(_code)   do {                    \
 
58
                rval.code = _code;              \
 
59
                rval.consumed = consumed_myself;\
 
60
                return rval;                    \
 
61
        } while(0)
 
62
 
 
63
/*
 
64
 * See the definitions.
 
65
 */
 
66
static int _fetch_present_idx(const void *struct_ptr, int off, int size);
 
67
static void _set_present_idx(void *sptr, int offset, int size, int pres);
 
68
 
 
69
/*
 
70
 * Tags are canonically sorted in the tag to member table.
 
71
 */
 
72
static int
 
73
_search4tag(const void *ap, const void *bp) {
 
74
        const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap;
 
75
        const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp;
 
76
 
 
77
        int a_class = BER_TAG_CLASS(a->el_tag);
 
78
        int b_class = BER_TAG_CLASS(b->el_tag);
 
79
 
 
80
        if(a_class == b_class) {
 
81
                ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
 
82
                ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
 
83
 
 
84
                if(a_value == b_value)
 
85
                        return 0;
 
86
                else if(a_value < b_value)
 
87
                        return -1;
 
88
                else
 
89
                        return 1;
 
90
        } else if(a_class < b_class) {
 
91
                return -1;
 
92
        } else {
 
93
                return 1;
 
94
        }
 
95
}
 
96
 
 
97
/*
 
98
 * The decoder of the CHOICE type.
 
99
 */
 
100
asn_dec_rval_t
 
101
CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 
102
        void **struct_ptr, const void *ptr, size_t size, int tag_mode) {
 
103
        /*
 
104
         * Bring closer parts of structure description.
 
105
         */
 
106
        asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 
107
        asn_TYPE_member_t *elements = td->elements;
 
108
 
 
109
        /*
 
110
         * Parts of the structure being constructed.
 
111
         */
 
112
        void *st = *struct_ptr; /* Target structure. */
 
113
        asn_struct_ctx_t *ctx;  /* Decoder context */
 
114
 
 
115
        ber_tlv_tag_t tlv_tag;  /* T from TLV */
 
116
        ssize_t tag_len;        /* Length of TLV's T */
 
117
        asn_dec_rval_t rval;    /* Return code from subparsers */
 
118
 
 
119
        ssize_t consumed_myself = 0;    /* Consumed bytes from ptr */
 
120
 
 
121
        ASN_DEBUG("Decoding %s as CHOICE", td->name);
 
122
 
 
123
        /*
 
124
         * Create the target structure if it is not present already.
 
125
         */
 
126
        if(st == 0) {
 
127
                st = *struct_ptr = CALLOC(1, specs->struct_size);
 
128
                if(st == 0) {
 
129
                        RETURN(RC_FAIL);
 
130
                }
 
131
        }
 
132
 
 
133
        /*
 
134
         * Restore parsing context.
 
135
         */
 
136
        ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
 
137
        
 
138
        /*
 
139
         * Start to parse where left previously
 
140
         */
 
141
        switch(ctx->phase) {
 
142
        case 0:
 
143
                /*
 
144
                 * PHASE 0.
 
145
                 * Check that the set of tags associated with given structure
 
146
                 * perfectly fits our expectations.
 
147
                 */
 
148
 
 
149
                if(tag_mode || td->tags_count) {
 
150
                        rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size,
 
151
                                tag_mode, -1, &ctx->left, 0);
 
152
                        if(rval.code != RC_OK) {
 
153
                                ASN_DEBUG("%s tagging check failed: %d",
 
154
                                        td->name, rval.code);
 
155
                                return rval;
 
156
                        }
 
157
 
 
158
                        if(ctx->left >= 0) {
 
159
                                /* ?Substracted below! */
 
160
                                ctx->left += rval.consumed;
 
161
                        }
 
162
                        ADVANCE(rval.consumed);
 
163
                } else {
 
164
                        ctx->left = -1;
 
165
                }
 
166
 
 
167
                NEXT_PHASE(ctx);
 
168
 
 
169
                ASN_DEBUG("Structure consumes %ld bytes, buffer %ld",
 
170
                        (long)ctx->left, (long)size);
 
171
 
 
172
                /* Fall through */
 
173
        case 1:
 
174
                /*
 
175
                 * Fetch the T from TLV.
 
176
                 */
 
177
                tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
 
178
                ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len);
 
179
                switch(tag_len) {
 
180
                case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
 
181
                        /* Fall through */
 
182
                case -1: RETURN(RC_FAIL);
 
183
                }
 
184
 
 
185
                do {
 
186
                        asn_TYPE_tag2member_t *t2m;
 
187
                        asn_TYPE_tag2member_t key;
 
188
 
 
189
                        key.el_tag = tlv_tag;
 
190
                        t2m = (asn_TYPE_tag2member_t *)bsearch(&key,
 
191
                                        specs->tag2el, specs->tag2el_count,
 
192
                                        sizeof(specs->tag2el[0]), _search4tag);
 
193
                        if(t2m) {
 
194
                                /*
 
195
                                 * Found the element corresponding to the tag.
 
196
                                 */
 
197
                                NEXT_PHASE(ctx);
 
198
                                ctx->step = t2m->el_no;
 
199
                                break;
 
200
                        } else if(specs->ext_start == -1) {
 
201
                                ASN_DEBUG("Unexpected tag %s "
 
202
                                        "in non-extensible CHOICE %s",
 
203
                                        ber_tlv_tag_string(tlv_tag), td->name);
 
204
                                RETURN(RC_FAIL);
 
205
                        } else {
 
206
                                /* Skip this tag */
 
207
                                ssize_t skip;
 
208
 
 
209
                                ASN_DEBUG("Skipping unknown tag %s",
 
210
                                        ber_tlv_tag_string(tlv_tag));
 
211
 
 
212
                                skip = ber_skip_length(opt_codec_ctx,
 
213
                                        BER_TLV_CONSTRUCTED(ptr),
 
214
                                        (const char *)ptr + tag_len,
 
215
                                        LEFT - tag_len);
 
216
 
 
217
                                switch(skip) {
 
218
                                case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
 
219
                                        /* Fall through */
 
220
                                case -1: RETURN(RC_FAIL);
 
221
                                }
 
222
 
 
223
                                ADVANCE(skip + tag_len);
 
224
                                RETURN(RC_OK);
 
225
                        }
 
226
                } while(0);
 
227
 
 
228
        case 2:
 
229
                /*
 
230
                 * PHASE 2.
 
231
                 * Read in the element.
 
232
                 */
 
233
            do {
 
234
                asn_TYPE_member_t *elm;/* CHOICE's element */
 
235
                void *memb_ptr;         /* Pointer to the member */
 
236
                void **memb_ptr2;       /* Pointer to that pointer */
 
237
 
 
238
                elm = &elements[ctx->step];
 
239
 
 
240
                /*
 
241
                 * Compute the position of the member inside a structure,
 
242
                 * and also a type of containment (it may be contained
 
243
                 * as pointer or using inline inclusion).
 
244
                 */
 
245
                if(elm->flags & ATF_POINTER) {
 
246
                        /* Member is a pointer to another structure */
 
247
                        memb_ptr2 = (void **)((char *)st + elm->memb_offset);
 
248
                } else {
 
249
                        /*
 
250
                         * A pointer to a pointer
 
251
                         * holding the start of the structure
 
252
                         */
 
253
                        memb_ptr = (char *)st + elm->memb_offset;
 
254
                        memb_ptr2 = &memb_ptr;
 
255
                }
 
256
                /* Set presence to be able to free it properly at any time */
 
257
                _set_present_idx(st, specs->pres_offset,
 
258
                                specs->pres_size, ctx->step + 1);
 
259
                /*
 
260
                 * Invoke the member fetch routine according to member's type
 
261
                 */
 
262
                rval = elm->type->ber_decoder(opt_codec_ctx, elm->type,
 
263
                                memb_ptr2, ptr, LEFT, elm->tag_mode);
 
264
                switch(rval.code) {
 
265
                case RC_OK:
 
266
                        break;
 
267
                case RC_WMORE: /* More data expected */
 
268
                        if(!SIZE_VIOLATION) {
 
269
                                ADVANCE(rval.consumed);
 
270
                                RETURN(RC_WMORE);
 
271
                        }
 
272
                        RETURN(RC_FAIL);
 
273
                case RC_FAIL: /* Fatal error */
 
274
                        RETURN(rval.code);
 
275
                } /* switch(rval) */
 
276
                
 
277
                ADVANCE(rval.consumed);
 
278
          } while(0);
 
279
 
 
280
                NEXT_PHASE(ctx);
 
281
 
 
282
                /* Fall through */
 
283
        case 3:
 
284
                ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d",
 
285
                        td->name, (long)ctx->left, (long)size,
 
286
                        tag_mode, td->tags_count);
 
287
 
 
288
                if(ctx->left > 0) {
 
289
                        /*
 
290
                         * The type must be fully decoded
 
291
                         * by the CHOICE member-specific decoder.
 
292
                         */
 
293
                        RETURN(RC_FAIL);
 
294
                }
 
295
 
 
296
                if(ctx->left == -1
 
297
                && !(tag_mode || td->tags_count)) {
 
298
                        /*
 
299
                         * This is an untagged CHOICE.
 
300
                         * It doesn't contain nothing
 
301
                         * except for the member itself, including all its tags.
 
302
                         * The decoding is completed.
 
303
                         */
 
304
                        NEXT_PHASE(ctx);
 
305
                        break;
 
306
                }
 
307
 
 
308
                /*
 
309
                 * Read in the "end of data chunks"'s.
 
310
                 */
 
311
                while(ctx->left < 0) {
 
312
                        ssize_t tl;
 
313
 
 
314
                        tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
 
315
                        switch(tl) {
 
316
                        case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
 
317
                                /* Fall through */
 
318
                        case -1: RETURN(RC_FAIL);
 
319
                        }
 
320
 
 
321
                        /*
 
322
                         * Expected <0><0>...
 
323
                         */
 
324
                        if(((const uint8_t *)ptr)[0] == 0) {
 
325
                                if(LEFT < 2) {
 
326
                                        if(SIZE_VIOLATION)
 
327
                                                RETURN(RC_FAIL);
 
328
                                        else
 
329
                                                RETURN(RC_WMORE);
 
330
                                } else if(((const uint8_t *)ptr)[1] == 0) {
 
331
                                        /*
 
332
                                         * Correctly finished with <0><0>.
 
333
                                         */
 
334
                                        ADVANCE(2);
 
335
                                        ctx->left++;
 
336
                                        continue;
 
337
                                }
 
338
                        } else {
 
339
                                ASN_DEBUG("Unexpected continuation in %s",
 
340
                                        td->name);
 
341
                                RETURN(RC_FAIL);
 
342
                        }
 
343
 
 
344
                        /* UNREACHABLE */
 
345
                }
 
346
 
 
347
                NEXT_PHASE(ctx);
 
348
        case 4:
 
349
                /* No meaningful work here */
 
350
                break;
 
351
        }
 
352
        
 
353
        RETURN(RC_OK);
 
354
}
 
355
 
 
356
asn_enc_rval_t
 
357
CHOICE_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
 
358
                int tag_mode, ber_tlv_tag_t tag,
 
359
                asn_app_consume_bytes_f *cb, void *app_key) {
 
360
        asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 
361
        asn_TYPE_member_t *elm; /* CHOICE element */
 
362
        asn_enc_rval_t erval;
 
363
        void *memb_ptr;
 
364
        size_t computed_size = 0;
 
365
        int present;
 
366
 
 
367
        if(!sptr) _ASN_ENCODE_FAILED;
 
368
 
 
369
        ASN_DEBUG("%s %s as CHOICE",
 
370
                cb?"Encoding":"Estimating", td->name);
 
371
 
 
372
        present = _fetch_present_idx(sptr,
 
373
                specs->pres_offset, specs->pres_size);
 
374
 
 
375
        /*
 
376
         * If the structure was not initialized, it cannot be encoded:
 
377
         * can't deduce what to encode in the choice type.
 
378
         */
 
379
        if(present <= 0 || present > td->elements_count) {
 
380
                if(present == 0 && td->elements_count == 0) {
 
381
                        /* The CHOICE is empty?! */
 
382
                        erval.encoded = 0;
 
383
                        _ASN_ENCODED_OK(erval);
 
384
                }
 
385
                _ASN_ENCODE_FAILED;
 
386
        }
 
387
 
 
388
        /*
 
389
         * Seek over the present member of the structure.
 
390
         */
 
391
        elm = &td->elements[present-1];
 
392
        if(elm->flags & ATF_POINTER) {
 
393
                memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
 
394
                if(memb_ptr == 0) {
 
395
                        if(elm->optional) {
 
396
                                erval.encoded = 0;
 
397
                                _ASN_ENCODED_OK(erval);
 
398
                        }
 
399
                        /* Mandatory element absent */
 
400
                        _ASN_ENCODE_FAILED;
 
401
                }
 
402
        } else {
 
403
                memb_ptr = (void *)((char *)sptr + elm->memb_offset);
 
404
        }
 
405
 
 
406
        /*
 
407
         * If the CHOICE itself is tagged EXPLICIT:
 
408
         * T ::= [2] EXPLICIT CHOICE { ... }
 
409
         * Then emit the appropriate tags.
 
410
         */
 
411
        if(tag_mode == 1 || td->tags_count) {
 
412
                /*
 
413
                 * For this, we need to pre-compute the member.
 
414
                 */
 
415
                ssize_t ret;
 
416
 
 
417
                /* Encode member with its tag */
 
418
                erval = elm->type->der_encoder(elm->type, memb_ptr,
 
419
                        elm->tag_mode, elm->tag, 0, 0);
 
420
                if(erval.encoded == -1)
 
421
                        return erval;
 
422
 
 
423
                /* Encode CHOICE with parent or my own tag */
 
424
                ret = der_write_tags(td, erval.encoded, tag_mode, 1, tag,
 
425
                        cb, app_key);
 
426
                if(ret == -1)
 
427
                        _ASN_ENCODE_FAILED;
 
428
                computed_size += ret;
 
429
        }
 
430
 
 
431
        /*
 
432
         * Encode the single underlying member.
 
433
         */
 
434
        erval = elm->type->der_encoder(elm->type, memb_ptr,
 
435
                elm->tag_mode, elm->tag, cb, app_key);
 
436
        if(erval.encoded == -1)
 
437
                return erval;
 
438
 
 
439
        ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)",
 
440
                (long)erval.encoded, (long)computed_size);
 
441
 
 
442
        erval.encoded += computed_size;
 
443
 
 
444
        return erval;
 
445
}
 
446
 
 
447
ber_tlv_tag_t
 
448
CHOICE_outmost_tag(asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) {
 
449
        asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 
450
        int present;
 
451
 
 
452
        assert(tag_mode == 0); (void)tag_mode;
 
453
        assert(tag == 0); (void)tag;
 
454
 
 
455
        /*
 
456
         * Figure out which CHOICE element is encoded.
 
457
         */
 
458
        present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
 
459
 
 
460
        if(present > 0 || present <= td->elements_count) {
 
461
                asn_TYPE_member_t *elm = &td->elements[present-1];
 
462
                const void *memb_ptr;
 
463
 
 
464
                if(elm->flags & ATF_POINTER) {
 
465
                        memb_ptr = *(const void * const *)
 
466
                                        ((const char *)ptr + elm->memb_offset);
 
467
                } else {
 
468
                        memb_ptr = (const void *)
 
469
                                        ((const char *)ptr + elm->memb_offset);
 
470
                }
 
471
 
 
472
                return asn_TYPE_outmost_tag(elm->type, memb_ptr,
 
473
                        elm->tag_mode, elm->tag);
 
474
        } else {
 
475
                return (ber_tlv_tag_t)-1;
 
476
        }
 
477
}
 
478
 
 
479
int
 
480
CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 
481
                asn_app_constraint_failed_f *ctfailcb, void *app_key) {
 
482
        asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 
483
        int present;
 
484
 
 
485
        if(!sptr) {
 
486
                _ASN_CTFAIL(app_key, td, sptr,
 
487
                        "%s: value not given (%s:%d)",
 
488
                        td->name, __FILE__, __LINE__);
 
489
                return -1;
 
490
        }
 
491
 
 
492
        /*
 
493
         * Figure out which CHOICE element is encoded.
 
494
         */
 
495
        present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
 
496
        if(present > 0 && present <= td->elements_count) {
 
497
                asn_TYPE_member_t *elm = &td->elements[present-1];
 
498
                const void *memb_ptr;
 
499
 
 
500
                if(elm->flags & ATF_POINTER) {
 
501
                        memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
 
502
                        if(!memb_ptr) {
 
503
                                if(elm->optional)
 
504
                                        return 0;
 
505
                                _ASN_CTFAIL(app_key, td, sptr,
 
506
                                        "%s: mandatory CHOICE element %s absent (%s:%d)",
 
507
                                        td->name, elm->name, __FILE__, __LINE__);
 
508
                                return -1;
 
509
                        }
 
510
                } else {
 
511
                        memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
 
512
                }
 
513
 
 
514
                if(elm->memb_constraints) {
 
515
                        return elm->memb_constraints(elm->type, memb_ptr,
 
516
                                ctfailcb, app_key);
 
517
                } else {
 
518
                        int ret = elm->type->check_constraints(elm->type,
 
519
                                        memb_ptr, ctfailcb, app_key);
 
520
                        /*
 
521
                         * Cannot inherit it eralier:
 
522
                         * need to make sure we get the updated version.
 
523
                         */
 
524
                        elm->memb_constraints = elm->type->check_constraints;
 
525
                        return ret;
 
526
                }
 
527
        } else {
 
528
                _ASN_CTFAIL(app_key, td, sptr,
 
529
                        "%s: no CHOICE element given (%s:%d)",
 
530
                        td->name, __FILE__, __LINE__);
 
531
                return -1;
 
532
        }
 
533
}
 
534
 
 
535
#undef  XER_ADVANCE
 
536
#define XER_ADVANCE(num_bytes)  do {                    \
 
537
                size_t num = num_bytes;                 \
 
538
                buf_ptr = ((const char *)buf_ptr) + num;\
 
539
                size -= num;                            \
 
540
                consumed_myself += num;                 \
 
541
        } while(0)
 
542
 
 
543
/*
 
544
 * Decode the XER (XML) data.
 
545
 */
 
546
asn_dec_rval_t
 
547
CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 
548
        void **struct_ptr, const char *opt_mname,
 
549
                const void *buf_ptr, size_t size) {
 
550
        /*
 
551
         * Bring closer parts of structure description.
 
552
         */
 
553
        asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 
554
        const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
 
555
 
 
556
        /*
 
557
         * Parts of the structure being constructed.
 
558
         */
 
559
        void *st = *struct_ptr; /* Target structure. */
 
560
        asn_struct_ctx_t *ctx;  /* Decoder context */
 
561
 
 
562
        asn_dec_rval_t rval;            /* Return value of a decoder */
 
563
        ssize_t consumed_myself = 0;    /* Consumed bytes from ptr */
 
564
        int edx;                        /* Element index */
 
565
 
 
566
        /*
 
567
         * Create the target structure if it is not present already.
 
568
         */
 
569
        if(st == 0) {
 
570
                st = *struct_ptr = CALLOC(1, specs->struct_size);
 
571
                if(st == 0) RETURN(RC_FAIL);
 
572
        }
 
573
 
 
574
        /*
 
575
         * Restore parsing context.
 
576
         */
 
577
        ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
 
578
        if(ctx->phase == 0 && !*xml_tag)
 
579
                ctx->phase = 1; /* Skip the outer tag checking phase */
 
580
 
 
581
        /*
 
582
         * Phases of XER/XML processing:
 
583
         * Phase 0: Check that the opening tag matches our expectations.
 
584
         * Phase 1: Processing body and reacting on closing tag.
 
585
         * Phase 2: Processing inner type.
 
586
         * Phase 3: Only waiting for closing tag.
 
587
         * Phase 4: Skipping unknown extensions.
 
588
         * Phase 5: PHASED OUT
 
589
         */
 
590
        for(edx = ctx->step; ctx->phase <= 4;) {
 
591
                pxer_chunk_type_e ch_type;      /* XER chunk type */
 
592
                ssize_t ch_size;                /* Chunk size */
 
593
                xer_check_tag_e tcv;            /* Tag check value */
 
594
                asn_TYPE_member_t *elm;
 
595
 
 
596
                /*
 
597
                 * Go inside the member.
 
598
                 */
 
599
                if(ctx->phase == 2) {
 
600
                        asn_dec_rval_t tmprval;
 
601
                        void *memb_ptr;         /* Pointer to the member */
 
602
                        void **memb_ptr2;       /* Pointer to that pointer */
 
603
 
 
604
                        elm = &td->elements[edx];
 
605
 
 
606
                        if(elm->flags & ATF_POINTER) {
 
607
                                /* Member is a pointer to another structure */
 
608
                                memb_ptr2 = (void **)((char *)st
 
609
                                        + elm->memb_offset);
 
610
                        } else {
 
611
                                memb_ptr = (char *)st + elm->memb_offset;
 
612
                                memb_ptr2 = &memb_ptr;
 
613
                        }
 
614
 
 
615
                        /* Start/Continue decoding the inner member */
 
616
                        tmprval = elm->type->xer_decoder(opt_codec_ctx,
 
617
                                        elm->type, memb_ptr2, elm->name,
 
618
                                        buf_ptr, size);
 
619
                        XER_ADVANCE(tmprval.consumed);
 
620
                        ASN_DEBUG("XER/CHOICE: itdf: [%s] code=%d",
 
621
                                elm->type->name, tmprval.code);
 
622
                        if(tmprval.code != RC_OK)
 
623
                                RETURN(tmprval.code);
 
624
                        assert(_fetch_present_idx(st,
 
625
                                specs->pres_offset, specs->pres_size) == 0);
 
626
                        /* Record what we've got */
 
627
                        _set_present_idx(st,
 
628
                                specs->pres_offset, specs->pres_size, edx + 1);
 
629
                        ctx->phase = 3;
 
630
                        /* Fall through */
 
631
                }
 
632
 
 
633
                /* No need to wait for closing tag; special mode. */
 
634
                if(ctx->phase == 3 && !*xml_tag) {
 
635
                        ctx->phase = 5; /* Phase out */
 
636
                        RETURN(RC_OK);
 
637
                }
 
638
 
 
639
                /*
 
640
                 * Get the next part of the XML stream.
 
641
                 */
 
642
                ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type);
 
643
                switch(ch_size) {
 
644
                case -1: RETURN(RC_FAIL);
 
645
                case 0:  RETURN(RC_WMORE);
 
646
                default:
 
647
                        switch(ch_type) {
 
648
                        case PXER_COMMENT:      /* Got XML comment */
 
649
                        case PXER_TEXT:         /* Ignore free-standing text */
 
650
                                XER_ADVANCE(ch_size);   /* Skip silently */
 
651
                                continue;
 
652
                        case PXER_TAG:
 
653
                                break;  /* Check the rest down there */
 
654
                        }
 
655
                }
 
656
 
 
657
                tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
 
658
                ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d",
 
659
                        ch_size>0?((const uint8_t *)buf_ptr)[0]:'?',
 
660
                        ch_size>1?((const uint8_t *)buf_ptr)[1]:'?',
 
661
                        ch_size>2?((const uint8_t *)buf_ptr)[2]:'?',
 
662
                        ch_size>3?((const uint8_t *)buf_ptr)[3]:'?',
 
663
                xml_tag, tcv);
 
664
 
 
665
                /* Skip the extensions section */
 
666
                if(ctx->phase == 4) {
 
667
                        ASN_DEBUG("skip_unknown(%d, %ld)",
 
668
                                tcv, (long)ctx->left);
 
669
                        switch(xer_skip_unknown(tcv, &ctx->left)) {
 
670
                        case -1:
 
671
                                ctx->phase = 5;
 
672
                                RETURN(RC_FAIL);
 
673
                                continue;
 
674
                        case 1:
 
675
                                ctx->phase = 3;
 
676
                                /* Fall through */
 
677
                        case 0:
 
678
                                XER_ADVANCE(ch_size);
 
679
                                continue;
 
680
                        case 2:
 
681
                                ctx->phase = 3;
 
682
                                break;
 
683
                        }
 
684
                }
 
685
 
 
686
                switch(tcv) {
 
687
                case XCT_BOTH:
 
688
                        break;  /* No CHOICE? */
 
689
                case XCT_CLOSING:
 
690
                        if(ctx->phase != 3)
 
691
                                break;
 
692
                        XER_ADVANCE(ch_size);
 
693
                        ctx->phase = 5; /* Phase out */
 
694
                        RETURN(RC_OK);
 
695
                case XCT_OPENING:
 
696
                        if(ctx->phase == 0) {
 
697
                                XER_ADVANCE(ch_size);
 
698
                                ctx->phase = 1; /* Processing body phase */
 
699
                                continue;
 
700
                        }
 
701
                        /* Fall through */
 
702
                case XCT_UNKNOWN_OP:
 
703
                case XCT_UNKNOWN_BO:
 
704
 
 
705
                        if(ctx->phase != 1)
 
706
                                break;  /* Really unexpected */
 
707
 
 
708
                        /*
 
709
                         * Search which inner member corresponds to this tag.
 
710
                         */
 
711
                        for(edx = 0; edx < td->elements_count; edx++) {
 
712
                                elm = &td->elements[edx];
 
713
                                tcv = xer_check_tag(buf_ptr,ch_size,elm->name);
 
714
                                switch(tcv) {
 
715
                                case XCT_BOTH:
 
716
                                case XCT_OPENING:
 
717
                                        /*
 
718
                                         * Process this member.
 
719
                                         */
 
720
                                        ctx->step = edx;
 
721
                                        ctx->phase = 2;
 
722
                                        break;
 
723
                                case XCT_UNKNOWN_OP:
 
724
                                case XCT_UNKNOWN_BO:
 
725
                                        continue;
 
726
                                default:
 
727
                                        edx = td->elements_count;
 
728
                                        break;  /* Phase out */
 
729
                                }
 
730
                                break;
 
731
                        }
 
732
                        if(edx != td->elements_count)
 
733
                                continue;
 
734
 
 
735
                        /* It is expected extension */
 
736
                        if(specs->ext_start != -1) {
 
737
                                ASN_DEBUG("Got anticipated extension");
 
738
                                /*
 
739
                                 * Check for (XCT_BOTH or XCT_UNKNOWN_BO)
 
740
                                 * By using a mask. Only record a pure
 
741
                                 * <opening> tags.
 
742
                                 */
 
743
                                if(tcv & XCT_CLOSING) {
 
744
                                        /* Found </extension> without body */
 
745
                                        ctx->phase = 3; /* Terminating */
 
746
                                } else {
 
747
                                        ctx->left = 1;
 
748
                                        ctx->phase = 4; /* Skip ...'s */
 
749
                                }
 
750
                                XER_ADVANCE(ch_size);
 
751
                                continue;
 
752
                        }
 
753
 
 
754
                        /* Fall through */
 
755
                default:
 
756
                        break;
 
757
                }
 
758
 
 
759
                ASN_DEBUG("Unexpected XML tag [%c%c%c%c] in CHOICE [%s]"
 
760
                        " (ph=%d, tag=%s)",
 
761
                        ch_size>0?((const uint8_t *)buf_ptr)[0]:'?',
 
762
                        ch_size>1?((const uint8_t *)buf_ptr)[1]:'?',
 
763
                        ch_size>2?((const uint8_t *)buf_ptr)[2]:'?',
 
764
                        ch_size>3?((const uint8_t *)buf_ptr)[3]:'?',
 
765
                        td->name, ctx->phase, xml_tag);
 
766
                break;
 
767
        }
 
768
 
 
769
        ctx->phase = 5; /* Phase out, just in case */
 
770
        RETURN(RC_FAIL);
 
771
}
 
772
 
 
773
 
 
774
asn_enc_rval_t
 
775
CHOICE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
 
776
        int ilevel, enum xer_encoder_flags_e flags,
 
777
                asn_app_consume_bytes_f *cb, void *app_key) {
 
778
        asn_CHOICE_specifics_t *specs=(asn_CHOICE_specifics_t *)td->specifics;
 
779
        asn_enc_rval_t er;
 
780
        int present;
 
781
 
 
782
        if(!sptr)
 
783
                _ASN_ENCODE_FAILED;
 
784
 
 
785
        /*
 
786
         * Figure out which CHOICE element is encoded.
 
787
         */
 
788
        present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
 
789
 
 
790
        if(present <= 0 || present > td->elements_count) {
 
791
                _ASN_ENCODE_FAILED;
 
792
        }  else {
 
793
                asn_enc_rval_t tmper;
 
794
                asn_TYPE_member_t *elm = &td->elements[present-1];
 
795
                void *memb_ptr;
 
796
                const char *mname = elm->name;
 
797
                unsigned int mlen = strlen(mname);
 
798
 
 
799
                if(elm->flags & ATF_POINTER) {
 
800
                        memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
 
801
                        if(!memb_ptr) _ASN_ENCODE_FAILED;
 
802
                } else {
 
803
                        memb_ptr = (void *)((char *)sptr + elm->memb_offset);
 
804
                }
 
805
 
 
806
                er.encoded = 0;
 
807
 
 
808
                if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel);
 
809
                _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
 
810
 
 
811
                tmper = elm->type->xer_encoder(elm->type, memb_ptr,
 
812
                                ilevel + 1, flags, cb, app_key);
 
813
                if(tmper.encoded == -1) return tmper;
 
814
 
 
815
                _ASN_CALLBACK3("</", 2, mname, mlen, ">", 1);
 
816
 
 
817
                er.encoded += 5 + (2 * mlen) + tmper.encoded;
 
818
        }
 
819
 
 
820
        if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel - 1);
 
821
 
 
822
        _ASN_ENCODED_OK(er);
 
823
cb_failed:
 
824
        _ASN_ENCODE_FAILED;
 
825
}
 
826
 
 
827
asn_dec_rval_t
 
828
CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
 
829
        asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
 
830
        asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 
831
        asn_dec_rval_t rv;
 
832
        asn_per_constraint_t *ct;
 
833
        asn_TYPE_member_t *elm; /* CHOICE's element */
 
834
        void *memb_ptr;
 
835
        void **memb_ptr2;
 
836
        void *st = *sptr;
 
837
        int value;
 
838
 
 
839
        if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
 
840
                _ASN_DECODE_FAILED;
 
841
 
 
842
        /*
 
843
         * Create the target structure if it is not present already.
 
844
         */
 
845
        if(!st) {
 
846
                st = *sptr = CALLOC(1, specs->struct_size);
 
847
                if(!st) _ASN_DECODE_FAILED;
 
848
        }
 
849
 
 
850
        if(constraints) ct = &constraints->value;
 
851
        else if(td->per_constraints) ct = &td->per_constraints->value;
 
852
        else ct = 0;
 
853
 
 
854
        if(ct && ct->flags & APC_EXTENSIBLE) {
 
855
                value = per_get_few_bits(pd, 1);
 
856
                if(value < 0) _ASN_DECODE_STARVED;
 
857
                if(value) ct = 0;       /* Not restricted */
 
858
        }
 
859
 
 
860
        if(ct && ct->range_bits >= 0) {
 
861
                value = per_get_few_bits(pd, ct->range_bits);
 
862
                if(value < 0) _ASN_DECODE_STARVED;
 
863
                ASN_DEBUG("CHOICE %s got index %d in range %d",
 
864
                        td->name, value, ct->range_bits);
 
865
                if(value > ct->upper_bound)
 
866
                        _ASN_DECODE_FAILED;
 
867
        } else {
 
868
                if(specs->ext_start == -1)
 
869
                        _ASN_DECODE_FAILED;
 
870
                value = uper_get_nsnnwn(pd);
 
871
                if(value < 0) _ASN_DECODE_STARVED;
 
872
                value += specs->ext_start;
 
873
                if(value >= td->elements_count)
 
874
                        _ASN_DECODE_FAILED;
 
875
        }
 
876
 
 
877
        /* Adjust if canonical order is different from natural order */
 
878
        if(specs->canonical_order)
 
879
                value = specs->canonical_order[value];
 
880
 
 
881
        /* Set presence to be able to free it later */
 
882
        _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1);
 
883
 
 
884
        elm = &td->elements[value];
 
885
        if(elm->flags & ATF_POINTER) {
 
886
                /* Member is a pointer to another structure */
 
887
                memb_ptr2 = (void **)((char *)st + elm->memb_offset);
 
888
        } else {
 
889
                memb_ptr = (char *)st + elm->memb_offset;
 
890
                memb_ptr2 = &memb_ptr;
 
891
        }
 
892
        ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name);
 
893
 
 
894
        if(ct && ct->range_bits >= 0) {
 
895
                rv = elm->type->uper_decoder(opt_codec_ctx, elm->type,
 
896
                        elm->per_constraints, memb_ptr2, pd);
 
897
        } else {
 
898
                rv = uper_open_type_get(opt_codec_ctx, elm->type,
 
899
                        elm->per_constraints, memb_ptr2, pd);
 
900
        }
 
901
 
 
902
        if(rv.code != RC_OK)
 
903
                ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d",
 
904
                        elm->name, td->name, rv.code);
 
905
        return rv;
 
906
}
 
907
   
 
908
asn_enc_rval_t
 
909
CHOICE_encode_uper(asn_TYPE_descriptor_t *td,
 
910
        asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
 
911
        asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 
912
        asn_TYPE_member_t *elm; /* CHOICE's element */
 
913
        asn_per_constraint_t *ct;
 
914
        void *memb_ptr;
 
915
        int present;
 
916
 
 
917
        if(!sptr) _ASN_ENCODE_FAILED;
 
918
 
 
919
        ASN_DEBUG("Encoding %s as CHOICE", td->name);
 
920
 
 
921
        if(constraints) ct = &constraints->value;
 
922
        else if(td->per_constraints) ct = &td->per_constraints->value;
 
923
        else ct = 0;
 
924
 
 
925
        present = _fetch_present_idx(sptr,
 
926
                specs->pres_offset, specs->pres_size);
 
927
 
 
928
        /*
 
929
         * If the structure was not initialized properly, it cannot be encoded:
 
930
         * can't deduce what to encode in the choice type.
 
931
         */
 
932
        if(present <= 0 || present > td->elements_count)
 
933
                _ASN_ENCODE_FAILED;
 
934
        else
 
935
                present--;
 
936
 
 
937
        /* Adjust if canonical order is different from natural order */
 
938
        if(specs->canonical_order)
 
939
                present = specs->canonical_order[present];
 
940
 
 
941
        ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present);
 
942
 
 
943
        if(ct && ct->range_bits >= 0) {
 
944
                if(present < ct->lower_bound
 
945
                || present > ct->upper_bound) {
 
946
                        if(ct->flags & APC_EXTENSIBLE) {
 
947
                                if(per_put_few_bits(po, 1, 1))
 
948
                                        _ASN_ENCODE_FAILED;
 
949
                        } else {
 
950
                                _ASN_ENCODE_FAILED;
 
951
                        }
 
952
                        ct = 0;
 
953
                }
 
954
        }
 
955
        if(ct && ct->flags & APC_EXTENSIBLE)
 
956
                if(per_put_few_bits(po, 0, 1))
 
957
                        _ASN_ENCODE_FAILED;
 
958
 
 
959
        elm = &td->elements[present];
 
960
        if(elm->flags & ATF_POINTER) {
 
961
                /* Member is a pointer to another structure */
 
962
                memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
 
963
                if(!memb_ptr) _ASN_ENCODE_FAILED;
 
964
        } else {
 
965
                memb_ptr = (char *)sptr + elm->memb_offset;
 
966
        }
 
967
 
 
968
        if(ct && ct->range_bits >= 0) {
 
969
                if(per_put_few_bits(po, present, ct->range_bits))
 
970
                        _ASN_ENCODE_FAILED;
 
971
 
 
972
                return elm->type->uper_encoder(elm->type, elm->per_constraints,
 
973
                        memb_ptr, po);
 
974
        } else {
 
975
                asn_enc_rval_t rval;
 
976
                if(specs->ext_start == -1)
 
977
                        _ASN_ENCODE_FAILED;
 
978
                if(uper_put_nsnnwn(po, present - specs->ext_start))
 
979
                        _ASN_ENCODE_FAILED;
 
980
                if(uper_open_type_put(elm->type, elm->per_constraints,
 
981
                        memb_ptr, po))
 
982
                        _ASN_ENCODE_FAILED;
 
983
                rval.encoded = 0;
 
984
                _ASN_ENCODED_OK(rval);
 
985
        }
 
986
}
 
987
   
 
988
 
 
989
int
 
990
CHOICE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 
991
                asn_app_consume_bytes_f *cb, void *app_key) {
 
992
        asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 
993
        int present;
 
994
 
 
995
        if(!sptr) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
 
996
 
 
997
        /*
 
998
         * Figure out which CHOICE element is encoded.
 
999
         */
 
1000
        present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
 
1001
 
 
1002
        /*
 
1003
         * Print that element.
 
1004
         */
 
1005
        if(present > 0 && present <= td->elements_count) {
 
1006
                asn_TYPE_member_t *elm = &td->elements[present-1];
 
1007
                const void *memb_ptr;
 
1008
 
 
1009
                if(elm->flags & ATF_POINTER) {
 
1010
                        memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
 
1011
                        if(!memb_ptr) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
 
1012
                } else {
 
1013
                        memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
 
1014
                }
 
1015
 
 
1016
                /* Print member's name and stuff */
 
1017
                if(0) {
 
1018
                        if(cb(elm->name, strlen(elm->name), app_key) < 0
 
1019
                        || cb(": ", 2, app_key) < 0)
 
1020
                                return -1;
 
1021
                }
 
1022
 
 
1023
                return elm->type->print_struct(elm->type, memb_ptr, ilevel,
 
1024
                        cb, app_key);
 
1025
        } else {
 
1026
                return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
 
1027
        }
 
1028
}
 
1029
 
 
1030
void
 
1031
CHOICE_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
 
1032
        asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
 
1033
        int present;
 
1034
 
 
1035
        if(!td || !ptr)
 
1036
                return;
 
1037
 
 
1038
        ASN_DEBUG("Freeing %s as CHOICE", td->name);
 
1039
 
 
1040
        /*
 
1041
         * Figure out which CHOICE element is encoded.
 
1042
         */
 
1043
        present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
 
1044
 
 
1045
        /*
 
1046
         * Free that element.
 
1047
         */
 
1048
        if(present > 0 && present <= td->elements_count) {
 
1049
                asn_TYPE_member_t *elm = &td->elements[present-1];
 
1050
                void *memb_ptr;
 
1051
 
 
1052
                if(elm->flags & ATF_POINTER) {
 
1053
                        memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
 
1054
                        if(memb_ptr)
 
1055
                                ASN_STRUCT_FREE(*elm->type, memb_ptr);
 
1056
                } else {
 
1057
                        memb_ptr = (void *)((char *)ptr + elm->memb_offset);
 
1058
                        ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr);
 
1059
                }
 
1060
        }
 
1061
 
 
1062
        if(!contents_only) {
 
1063
                FREEMEM(ptr);
 
1064
        }
 
1065
}
 
1066
 
 
1067
 
 
1068
/*
 
1069
 * The following functions functions offer protection against -fshort-enums,
 
1070
 * compatible with little- and big-endian machines.
 
1071
 * If assertion is triggered, either disable -fshort-enums, or add an entry
 
1072
 * here with the ->pres_size of your target stracture.
 
1073
 * Unless the target structure is packed, the ".present" member
 
1074
 * is guaranteed to be aligned properly. ASN.1 compiler itself does not
 
1075
 * produce packed code.
 
1076
 */
 
1077
static int
 
1078
_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) {
 
1079
        const void *present_ptr;
 
1080
        int present;
 
1081
 
 
1082
        present_ptr = ((const char *)struct_ptr) + pres_offset;
 
1083
 
 
1084
        switch(pres_size) {
 
1085
        case sizeof(int):       present =   *(const int *)present_ptr; break;
 
1086
        case sizeof(short):     present = *(const short *)present_ptr; break;
 
1087
        case sizeof(char):      present =  *(const char *)present_ptr; break;
 
1088
        default:
 
1089
                /* ANSI C mandates enum to be equivalent to integer */
 
1090
                assert(pres_size != sizeof(int));
 
1091
                return 0;       /* If not aborted, pass back safe value */
 
1092
        }
 
1093
 
 
1094
        return present;
 
1095
}
 
1096
 
 
1097
static void
 
1098
_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) {
 
1099
        void *present_ptr;
 
1100
        present_ptr = ((char *)struct_ptr) + pres_offset;
 
1101
 
 
1102
        switch(pres_size) {
 
1103
        case sizeof(int):       *(int *)present_ptr   = present; break;
 
1104
        case sizeof(short):     *(short *)present_ptr = present; break;
 
1105
        case sizeof(char):      *(char *)present_ptr  = present; break;
 
1106
        default:
 
1107
                /* ANSI C mandates enum to be equivalent to integer */
 
1108
                assert(pres_size != sizeof(int));
 
1109
        }
 
1110
}