]> git.stg.codes - stg.git/blob - libs/smux/constr_SET_OF_oer.c
Add an option to opt-out Firebird store.
[stg.git] / libs / smux / constr_SET_OF_oer.c
1 /*
2  * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3  * All rights reserved.
4  * Redistribution and modifications are permitted subject to BSD license.
5  */
6 #ifndef ASN_DISABLE_OER_SUPPORT
7
8 #include <asn_internal.h>
9 #include <constr_SET_OF.h>
10 #include <asn_SET_OF.h>
11 #include <errno.h>
12
13 /*
14  * This macro "eats" the part of the buffer which is definitely "consumed",
15  * i.e. was correctly converted into local representation or rightfully skipped.
16  */
17 #undef  ADVANCE
18 #define ADVANCE(num_bytes)                   \
19     do {                                     \
20         size_t num = num_bytes;              \
21         ptr = ((const char *)ptr) + num;     \
22         size -= num;                         \
23         consumed_myself += num;              \
24     } while(0)
25
26 /*
27  * Switch to the next phase of parsing.
28  */
29 #undef  NEXT_PHASE
30 #define NEXT_PHASE(ctx) \
31     do {                \
32         ctx->phase++;   \
33         ctx->step = 0;  \
34     } while(0)
35 #undef  SET_PHASE
36 #define SET_PHASE(ctx, value) \
37     do {                      \
38         ctx->phase = value;   \
39         ctx->step = 0;        \
40     } while(0)
41
42 /*
43  * Return a standardized complex structure.
44  */
45 #undef  RETURN
46 #define RETURN(_code)                    \
47     do {                                 \
48         asn_dec_rval_t rval;             \
49         rval.code = _code;               \
50         rval.consumed = consumed_myself; \
51         return rval;                     \
52     } while(0)
53
54 /*
55  * The SEQUENCE OF and SET OF values utilize a "quantity field".
56  * It is is a pointless combination of #8.6 (length determinant, capable
57  * of encoding tiny and huge numbers in the shortest possible number of octets)
58  * and the variable sized integer. What could have been encoded by #8.6 alone
59  * is required to be encoded by #8.6 followed by that number of unsigned octets.
60  * This doesn't make too much sense. It seems that the original version of OER
61  * standard have been using the unconstrained unsigned integer as a quantity
62  * field, and this legacy have gone through ISO/ITU-T standardization process.
63  */
64 static ssize_t
65 oer_fetch_quantity(const void *ptr, size_t size, size_t *qty_r) {
66     const uint8_t *b;
67     const uint8_t *bend;
68     size_t len = 0;
69     size_t qty;
70
71     ssize_t len_len = oer_fetch_length(ptr, size, &len);
72     if(len_len <= 0) {
73         *qty_r = 0;
74         return len_len;
75     }
76
77     if((len_len + len) > size) {
78         *qty_r = 0;
79         return 0;
80     }
81
82     b = (const uint8_t *)ptr + len_len;
83     bend = b + len;
84
85     /* Skip the leading 0-bytes */
86     for(; b < bend && *b == 0; b++) {
87     }
88
89     if((bend - b) > (ssize_t)sizeof(size_t)) {
90         /* Length is not representable by the native size_t type */
91         *qty_r = 0;
92         return -1;
93     }
94
95     for(qty = 0; b < bend; b++) {
96         qty = (qty << 8) + *b;
97     }
98
99     if(qty > RSIZE_MAX) { /* A bit of C11 validation */
100         *qty_r = 0;
101         return -1;
102     }
103
104     *qty_r = qty;
105     assert((size_t)len_len + len == (size_t)(bend - (const uint8_t *)ptr));
106     return len_len + len;
107 }
108
109 asn_dec_rval_t
110 SET_OF_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
111                   const asn_TYPE_descriptor_t *td,
112                   const asn_oer_constraints_t *constraints, void **struct_ptr,
113                   const void *ptr, size_t size) {
114     const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics;
115     asn_dec_rval_t rval = {RC_OK, 0};
116     void *st = *struct_ptr; /* Target structure */
117     asn_struct_ctx_t *ctx; /* Decoder context */
118     size_t consumed_myself = 0; /* Consumed bytes from ptr. */
119
120     (void)constraints;
121
122     if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
123         ASN__DECODE_FAILED;
124
125     /*
126      * Create the target structure if it is not present already.
127      */
128     if(st == 0) {
129         st = *struct_ptr = CALLOC(1, specs->struct_size);
130         if(st == 0) {
131             RETURN(RC_FAIL);
132         }
133     }
134
135     /*
136      * Restore parsing context.
137      */
138     ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
139
140     /*
141      * Start to parse where left previously.
142      */
143     switch(ctx->phase) {
144     case 0: {
145         /*
146          * Fetch number of elements to decode.
147          */
148         size_t length = 0;
149         size_t len_size = oer_fetch_quantity(ptr, size, &length);
150         switch(len_size) {
151         case 0:
152             RETURN(RC_WMORE);
153         case -1:
154             RETURN(RC_FAIL);
155         default:
156             ADVANCE(len_size);
157             ctx->left = length;
158         }
159     }
160         NEXT_PHASE(ctx);
161         /* FALL THROUGH */
162     case 1: {
163         /* Decode components of the extension root */
164         asn_TYPE_member_t *elm = td->elements;
165         asn_anonymous_set_ *list = _A_SET_FROM_VOID(st);
166         const void *base_ptr = ptr;
167         ber_tlv_len_t base_ctx_left = ctx->left;
168
169         assert(td->elements_count == 1);
170
171         ASN_DEBUG("OER SET OF %s Decoding PHASE 1", td->name);
172
173         for(; ctx->left > 0; ctx->left--) {
174             asn_dec_rval_t rv = elm->type->op->oer_decoder(
175                 opt_codec_ctx, elm->type,
176                 elm->encoding_constraints.oer_constraints, &ctx->ptr, ptr,
177                 size);
178             ADVANCE(rv.consumed);
179             switch(rv.code) {
180             case RC_OK:
181                 if(ASN_SET_ADD(list, ctx->ptr) != 0) {
182                     RETURN(RC_FAIL);
183                 } else {
184                     ctx->ptr = 0;
185                     /*
186                      * This check is to avoid compression bomb with
187                      * specs like SEQUENCE/SET OF NULL which don't
188                      * consume data at all.
189                      */
190                     if(rv.consumed == 0 && base_ptr == ptr
191                        && (base_ctx_left - ctx->left) > 200) {
192                         ASN__DECODE_FAILED;
193                     }
194                     break;
195                 }
196             case RC_WMORE:
197                 RETURN(RC_WMORE);
198             case RC_FAIL:
199                 ASN_STRUCT_FREE(*elm->type, ctx->ptr);
200                 ctx->ptr = 0;
201                 SET_PHASE(ctx, 3);
202                 RETURN(RC_FAIL);
203             }
204         }
205         /* Decoded decently. */
206         NEXT_PHASE(ctx);
207     }
208         /* Fall through */
209     case 2:
210         /* Ignore fully decoded */
211         assert(ctx->left == 0);
212         RETURN(RC_OK);
213     case 3:
214         /* Failed to decode. */
215         RETURN(RC_FAIL);
216     }
217
218     return rval;
219 }
220
221 static ssize_t
222 oer_put_quantity(size_t qty, asn_app_consume_bytes_f *cb, void *app_key) {
223     uint8_t buf[1 + sizeof(size_t)];
224     uint8_t *b = &buf[sizeof(size_t)]; /* Last addressable */
225     size_t encoded;
226
227     do {
228         *b-- = qty;
229         qty >>= 8;
230     } while(qty);
231
232     *b = sizeof(buf) - (b-buf) - 1;
233     encoded = sizeof(buf) - (b-buf);
234     if(cb(b, encoded, app_key) < 0)
235         return -1;
236     return encoded;
237 }
238
239 /*
240  * Encode as Canonical OER.
241  */
242 asn_enc_rval_t
243 SET_OF_encode_oer(const asn_TYPE_descriptor_t *td,
244                   const asn_oer_constraints_t *constraints, const void *sptr,
245                   asn_app_consume_bytes_f *cb, void *app_key) {
246     const asn_TYPE_member_t *elm;
247     const asn_anonymous_set_ *list;
248     size_t computed_size = 0;
249     ssize_t qty_len;
250     int n;
251
252     (void)constraints;
253
254     if(!sptr) ASN__ENCODE_FAILED;
255
256     elm = td->elements;
257     list = _A_CSET_FROM_VOID(sptr);
258
259     qty_len = oer_put_quantity(list->count, cb, app_key);
260     if(qty_len < 0) {
261         ASN__ENCODE_FAILED;
262     }
263     computed_size += qty_len;
264
265     for(n = 0; n < list->count; n++) {
266         void *memb_ptr = list->array[n];
267         asn_enc_rval_t er;
268         er = elm->type->op->oer_encoder(
269             elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb,
270             app_key);
271         if(er.encoded < 0) {
272             return er;
273         } else {
274             computed_size += er.encoded;
275         }
276     }
277
278     {
279         asn_enc_rval_t erval;
280         erval.encoded = computed_size;
281         ASN__ENCODED_OK(erval);
282     }
283 }
284
285 #endif  /* ASN_DISABLE_OER_SUPPORT */