~ubuntu-branches/ubuntu/dapper/asn1c/dapper

« back to all changes in this revision

Viewing changes to skeletons/ber_decoder.c

  • Committer: Bazaar Package Importer
  • Author(s): W. Borgert
  • Date: 2005-05-28 12:36:42 UTC
  • Revision ID: james.westby@ubuntu.com-20050528123642-3h6kstws5u0xcovl
Tags: upstream-0.9.14
ImportĀ upstreamĀ versionĀ 0.9.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
 
3
 * Redistribution and modifications are permitted subject to BSD license.
 
4
 */
 
5
#include <asn_internal.h>
 
6
 
 
7
#undef  ADVANCE
 
8
#define ADVANCE(num_bytes)      do {                                    \
 
9
                size_t num = num_bytes;                                 \
 
10
                ptr = ((const char *)ptr) + num;                        \
 
11
                size -= num;                                            \
 
12
                consumed_myself += num;                                 \
 
13
        } while(0)
 
14
#undef  RETURN
 
15
#define RETURN(_code)   do {                                            \
 
16
                asn_dec_rval_t rval;                                    \
 
17
                rval.code = _code;                                      \
 
18
                if(opt_ctx) opt_ctx->step = step; /* Save context */    \
 
19
                if(_code == RC_OK || opt_ctx)                           \
 
20
                        rval.consumed = consumed_myself;                \
 
21
                else                                                    \
 
22
                        rval.consumed = 0;      /* Context-free */      \
 
23
                return rval;                                            \
 
24
        } while(0)
 
25
 
 
26
/*
 
27
 * The BER decoder of any type.
 
28
 */
 
29
asn_dec_rval_t
 
30
ber_decode(asn_codec_ctx_t *opt_codec_ctx,
 
31
        asn_TYPE_descriptor_t *type_descriptor,
 
32
        void **struct_ptr, const void *ptr, size_t size) {
 
33
        asn_codec_ctx_t s_codec_ctx;
 
34
 
 
35
        /*
 
36
         * Satisfy the requirement that the codec context
 
37
         * must be allocated on the stack.
 
38
         */
 
39
        if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
 
40
                s_codec_ctx = *opt_codec_ctx;
 
41
                opt_codec_ctx = &s_codec_ctx;
 
42
        }
 
43
 
 
44
        /*
 
45
         * Invoke type-specific decoder.
 
46
         */
 
47
        return type_descriptor->ber_decoder(opt_codec_ctx, type_descriptor,
 
48
                struct_ptr,     /* Pointer to the destination structure */
 
49
                ptr, size,      /* Buffer and its size */
 
50
                0               /* Default tag mode is 0 */
 
51
                );
 
52
}
 
53
 
 
54
/*
 
55
 * Check the set of <TL<TL<TL...>>> tags matches the definition.
 
56
 */
 
57
asn_dec_rval_t
 
58
ber_check_tags(asn_codec_ctx_t *opt_codec_ctx,
 
59
                asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx,
 
60
                const void *ptr, size_t size, int tag_mode, int last_tag_form,
 
61
                ber_tlv_len_t *last_length, int *opt_tlv_form) {
 
62
        ssize_t consumed_myself = 0;
 
63
        ssize_t tag_len;
 
64
        ssize_t len_len;
 
65
        ber_tlv_tag_t tlv_tag;
 
66
        ber_tlv_len_t tlv_len;
 
67
        ber_tlv_len_t limit_len = -1;
 
68
        int expect_00_terminators = 0;
 
69
        int tlv_constr = -1;    /* If CHOICE, opt_tlv_form is not given */
 
70
        int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */
 
71
        int tagno;
 
72
 
 
73
        /*
 
74
         * Make sure we didn't exceed the maximum stack size.
 
75
         */
 
76
        if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
 
77
                ptrdiff_t usedstack = ((char *)opt_codec_ctx - (char *)&size);
 
78
                /* double negative is required to avoid int wrap-around */
 
79
                if(usedstack > 0) usedstack = -usedstack;
 
80
                ASN_DEBUG("Current stack size %ld", -(long)usedstack);
 
81
                if(usedstack < -(ptrdiff_t)opt_codec_ctx->max_stack_size) {
 
82
                        ASN_DEBUG("Stack limit %ld reached",
 
83
                                (long)opt_codec_ctx->max_stack_size);
 
84
                        RETURN(RC_FAIL);
 
85
                }
 
86
        }
 
87
 
 
88
        /*
 
89
         * So what does all this implicit skip stuff mean?
 
90
         * Imagine two types,
 
91
         *      A ::= [5] IMPLICIT      T
 
92
         *      B ::= [2] EXPLICIT      T
 
93
         * Where T is defined as
 
94
         *      T ::= [4] IMPLICIT SEQUENCE { ... }
 
95
         * 
 
96
         * Let's say, we are starting to decode type A, given the
 
97
         * following TLV stream: <5> <0>. What does this mean?
 
98
         * It means that the type A contains type T which is,
 
99
         * in turn, empty.
 
100
         * Remember though, that we are still in A. We cannot
 
101
         * just pass control to the type T decoder. Why? Because
 
102
         * the type T decoder expects <4> <0>, not <5> <0>.
 
103
         * So, we must make sure we are going to receive <5> while
 
104
         * still in A, then pass control to the T decoder, indicating
 
105
         * that the tag <4> was implicitly skipped. The decoder of T
 
106
         * hence will be prepared to treat <4> as valid tag, and decode
 
107
         * it appropriately.
 
108
         */
 
109
 
 
110
        tagno = step    /* Continuing where left previously */
 
111
                + (tag_mode==1?-1:0)
 
112
                ;
 
113
        ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)",
 
114
                td->name, (long)size, tag_mode, step, tagno);
 
115
        /* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */
 
116
 
 
117
        if(tag_mode == 0 && tagno == td->tags_count) {
 
118
                /*
 
119
                 * This must be the _untagged_ ANY type,
 
120
                 * which outermost tag isn't known in advance.
 
121
                 * Fetch the tag and length separately.
 
122
                 */
 
123
                tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
 
124
                switch(tag_len) {
 
125
                case -1: RETURN(RC_FAIL);
 
126
                case 0: RETURN(RC_WMORE);
 
127
                }
 
128
                tlv_constr = BER_TLV_CONSTRUCTED(ptr);
 
129
                len_len = ber_fetch_length(tlv_constr,
 
130
                        (const char *)ptr + tag_len, size - tag_len, &tlv_len);
 
131
                switch(len_len) {
 
132
                case -1: RETURN(RC_FAIL);
 
133
                case 0: RETURN(RC_WMORE);
 
134
                }
 
135
                ASN_DEBUG("Advancing %ld in ANY case",
 
136
                        (long)(tag_len + len_len));
 
137
                ADVANCE(tag_len + len_len);
 
138
        } else {
 
139
                assert(tagno < td->tags_count); /* At least one loop */
 
140
        }
 
141
        for((void)tagno; tagno < td->tags_count; tagno++, step++) {
 
142
 
 
143
                /*
 
144
                 * Fetch and process T from TLV.
 
145
                 */
 
146
                tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
 
147
                        ASN_DEBUG("Fetching tag from {%p,%ld}: "
 
148
                                "len %ld, step %d, tagno %d got %s",
 
149
                                ptr, (long)size,
 
150
                                (long)tag_len, step, tagno,
 
151
                                ber_tlv_tag_string(tlv_tag));
 
152
                switch(tag_len) {
 
153
                case -1: RETURN(RC_FAIL);
 
154
                case 0: RETURN(RC_WMORE);
 
155
                }
 
156
 
 
157
                tlv_constr = BER_TLV_CONSTRUCTED(ptr);
 
158
 
 
159
                /*
 
160
                 * If {I}, don't check anything.
 
161
                 * If {I,B,C}, check B and C unless we're at I.
 
162
                 */
 
163
                if(tag_mode != 0 && step == 0) {
 
164
                        /*
 
165
                         * We don't expect tag to match here.
 
166
                         * It's just because we don't know how the tag
 
167
                         * is supposed to look like.
 
168
                         */
 
169
                } else {
 
170
                    assert(tagno >= 0); /* Guaranteed by the code above */
 
171
                    if(tlv_tag != td->tags[tagno]) {
 
172
                        /*
 
173
                         * Unexpected tag. Too bad.
 
174
                         */
 
175
                        ASN_DEBUG("Expected: %s, "
 
176
                                "expectation failed (tn=%d, tm=%d)",
 
177
                                ber_tlv_tag_string(td->tags[tagno]),
 
178
                                tagno, tag_mode
 
179
                        );
 
180
                        RETURN(RC_FAIL);
 
181
                    }
 
182
                }
 
183
 
 
184
                /*
 
185
                 * Attention: if there are more tags expected,
 
186
                 * ensure that the current tag is presented
 
187
                 * in constructed form (it contains other tags!).
 
188
                 * If this one is the last one, check that the tag form
 
189
                 * matches the one given in descriptor.
 
190
                 */
 
191
                if(tagno < (td->tags_count - 1)) {
 
192
                        if(tlv_constr == 0) {
 
193
                                ASN_DEBUG("tlv_constr = %d, expfail",
 
194
                                        tlv_constr);
 
195
                                RETURN(RC_FAIL);
 
196
                        }
 
197
                } else {
 
198
                        if(last_tag_form != tlv_constr
 
199
                        && last_tag_form != -1) {
 
200
                                ASN_DEBUG("last_tag_form %d != %d",
 
201
                                        last_tag_form, tlv_constr);
 
202
                                RETURN(RC_FAIL);
 
203
                        }
 
204
                }
 
205
 
 
206
                /*
 
207
                 * Fetch and process L from TLV.
 
208
                 */
 
209
                len_len = ber_fetch_length(tlv_constr,
 
210
                        (const char *)ptr + tag_len, size - tag_len, &tlv_len);
 
211
                ASN_DEBUG("Fetchinig len = %ld", (long)len_len);
 
212
                switch(len_len) {
 
213
                case -1: RETURN(RC_FAIL);
 
214
                case 0: RETURN(RC_WMORE);
 
215
                }
 
216
 
 
217
                /*
 
218
                 * FIXME
 
219
                 * As of today, the chain of tags
 
220
                 * must either contain several indefinite length TLVs,
 
221
                 * or several definite length ones.
 
222
                 * No mixing is allowed.
 
223
                 */
 
224
                if(tlv_len == -1) {
 
225
                        /*
 
226
                         * Indefinite length.
 
227
                         */
 
228
                        if(limit_len == -1) {
 
229
                                expect_00_terminators++;
 
230
                        } else {
 
231
                                ASN_DEBUG("Unexpected indefinite length "
 
232
                                        "in a chain of definite lengths");
 
233
                                RETURN(RC_FAIL);
 
234
                        }
 
235
                        ADVANCE(tag_len + len_len);
 
236
                        continue;
 
237
                } else {
 
238
                        if(expect_00_terminators) {
 
239
                                ASN_DEBUG("Unexpected definite length "
 
240
                                        "in a chain of indefinite lengths");
 
241
                                RETURN(RC_FAIL);
 
242
                        }
 
243
                }
 
244
 
 
245
                /*
 
246
                 * Check that multiple TLVs specify ever decreasing length,
 
247
                 * which is consistent.
 
248
                 */
 
249
                if(limit_len == -1) {
 
250
                        limit_len    = tlv_len + tag_len + len_len;
 
251
                        if(limit_len < 0) {
 
252
                                /* Too great tlv_len value? */
 
253
                                RETURN(RC_FAIL);
 
254
                        }
 
255
                } else if(limit_len != tlv_len + tag_len + len_len) {
 
256
                        /*
 
257
                         * Inner TLV specifies length which is inconsistent
 
258
                         * with the outer TLV's length value.
 
259
                         */
 
260
                        ASN_DEBUG("Outer TLV is %ld and inner is %ld",
 
261
                                (long)limit_len, (long)tlv_len);
 
262
                        RETURN(RC_FAIL);
 
263
                }
 
264
 
 
265
                ADVANCE(tag_len + len_len);
 
266
 
 
267
                limit_len -= (tag_len + len_len);
 
268
                if((ssize_t)size > limit_len) {
 
269
                        /*
 
270
                         * Make sure that we won't consume more bytes
 
271
                         * from the parent frame than the inferred limit.
 
272
                         */
 
273
                        size = limit_len;
 
274
                }
 
275
        }
 
276
 
 
277
        if(opt_tlv_form)
 
278
                *opt_tlv_form = tlv_constr;
 
279
        if(expect_00_terminators)
 
280
                *last_length = -expect_00_terminators;
 
281
        else
 
282
                *last_length = tlv_len;
 
283
 
 
284
        RETURN(RC_OK);
 
285
}