blob: 43bd11abc8e48adef43662c54b29da8f1e4a411c [file] [log] [blame]
Lev Walkind88bea92017-07-20 11:21:30 +03001/*
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_SEQUENCE.h>
Lev Walkinf6853ce2017-08-11 00:50:27 -070010#include <OPEN_TYPE.h>
Lev Walkind88bea92017-07-20 11:21:30 +030011#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#undef PHASE_OUT
31#define NEXT_PHASE(ctx) \
32 do { \
33 ctx->phase++; \
34 ctx->step = 0; \
35 } while(0)
36
37/*
38 * Check whether we are inside the extensions group.
39 */
40#define IN_EXTENSION_GROUP(specs, memb_idx) \
Lev Walkin494fb702017-08-07 20:07:00 -070041 ( (((ssize_t)(memb_idx)) > (specs)->ext_after) \
42 &&(((ssize_t)(memb_idx)) < (specs)->ext_before))
Lev Walkind88bea92017-07-20 11:21:30 +030043
44/*
45 * Return a standardized complex structure.
46 */
47#undef RETURN
48#define RETURN(_code) do { \
49 rval.code = _code; \
50 rval.consumed = consumed_myself;\
51 return rval; \
52 } while(0)
53
Lev Walkin890e6032017-07-24 01:48:59 +040054/*
55 * Return pointer to a member.
56 */
Lev Walkincfc16d32017-08-30 19:15:08 -070057static void **
58element_ptrptr(void *struct_ptr, asn_TYPE_member_t *elm, void **tmp_save_ptr) {
59 if(elm->flags & ATF_POINTER) {
60 /* Member is a pointer to another structure */
61 return (void **)((char *)struct_ptr + elm->memb_offset);
62 } else {
63 assert(tmp_save_ptr);
64 *tmp_save_ptr = (void *)((char *)struct_ptr + elm->memb_offset);
65 return tmp_save_ptr;
66 }
Lev Walkin890e6032017-07-24 01:48:59 +040067}
68
Lev Walkin20696a42017-10-17 21:27:33 -070069static const void *
70element_ptr(const void *struct_ptr, const asn_TYPE_member_t *elm) {
Lev Walkin890e6032017-07-24 01:48:59 +040071 if(elm->flags & ATF_POINTER) {
72 /* Member is a pointer to another structure */
Lev Walkin20696a42017-10-17 21:27:33 -070073 return *(const void *const *)((const char *)struct_ptr
74 + elm->memb_offset);
Lev Walkin890e6032017-07-24 01:48:59 +040075 } else {
Lev Walkin20696a42017-10-17 21:27:33 -070076 return (const void *)((const char *)struct_ptr + elm->memb_offset);
Lev Walkin890e6032017-07-24 01:48:59 +040077 }
78}
79
Lev Walkind88bea92017-07-20 11:21:30 +030080asn_dec_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -070081SEQUENCE_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
82 const asn_TYPE_descriptor_t *td,
Lev Walkin494fb702017-08-07 20:07:00 -070083 const asn_oer_constraints_t *constraints, void **struct_ptr,
84 const void *ptr, size_t size) {
Lev Walkind84f6032017-10-03 16:33:59 -070085 const asn_SEQUENCE_specifics_t *specs =
86 (const asn_SEQUENCE_specifics_t *)td->specifics;
Lev Walkind88bea92017-07-20 11:21:30 +030087 asn_dec_rval_t rval = {RC_OK, 0};
88 void *st = *struct_ptr; /* Target structure */
89 asn_struct_ctx_t *ctx; /* Decoder context */
90 size_t consumed_myself = 0; /* Consumed bytes from ptr. */
91
92
93 (void)opt_codec_ctx;
Lev Walkin494fb702017-08-07 20:07:00 -070094 (void)constraints;
Lev Walkind88bea92017-07-20 11:21:30 +030095
96 /*
97 * Create the target structure if it is not present already.
98 */
99 if(st == 0) {
100 st = *struct_ptr = CALLOC(1, specs->struct_size);
101 if(st == 0) {
102 RETURN(RC_FAIL);
103 }
104 }
105
106 /*
107 * Restore parsing context.
108 */
109 ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
110 if(ctx->ptr == 0) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700111 ctx->ptr = CALLOC(1, sizeof(asn_bit_data_t));
Lev Walkind88bea92017-07-20 11:21:30 +0300112 if(!ctx->ptr) {
113 RETURN(RC_FAIL);
114 }
115 }
116
117 /*
118 * Start to parse where left previously.
119 */
120 switch(ctx->phase) {
121 case 0: {
122 /*
123 * Fetch preamble.
124 */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700125 asn_bit_data_t *preamble = ctx->ptr;
Lev Walkin890e6032017-07-24 01:48:59 +0400126 int has_extensions_bit = (specs->ext_before >= 0);
127 size_t preamble_bits = (has_extensions_bit + specs->roms_count);
128 size_t preamble_bytes = ((7 + preamble_bits) >> 3);
Lev Walkind88bea92017-07-20 11:21:30 +0300129 uint8_t *pbytes;
130
Lev Walkinbc0b0c52017-08-02 14:02:48 -0700131 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 0", td->name);
132
Lev Walkin890e6032017-07-24 01:48:59 +0400133 ASN_DEBUG(
134 "Expecting preamble bits %zu for %s (including %d extension bits)",
135 preamble_bits, td->name, has_extensions_bit);
136
Lev Walkind88bea92017-07-20 11:21:30 +0300137 if(size < preamble_bytes) {
138 ASN__DECODE_STARVED;
139 }
140
141 pbytes = MALLOC(preamble_bytes + 1);
142 if(!pbytes) {
143 RETURN(RC_FAIL);
144 }
145 preamble->buffer = (const void *)pbytes;
146 memcpy(pbytes, ptr, preamble_bytes);
147 pbytes[preamble_bytes] = '\0'; /* Just in case */
Lev Walkin890e6032017-07-24 01:48:59 +0400148 preamble->nboff = has_extensions_bit;
Lev Walkind88bea92017-07-20 11:21:30 +0300149 preamble->nbits = preamble_bits;
150 ADVANCE(preamble_bytes);
151 }
152 NEXT_PHASE(ctx);
153 /* FALL THROUGH */
154 case 1: {
155 /* Decode components of the extension root */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700156 asn_bit_data_t *preamble = ctx->ptr;
Lev Walkind88bea92017-07-20 11:21:30 +0300157 size_t edx;
158
Lev Walkinbc0b0c52017-08-02 14:02:48 -0700159 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 1", td->name);
160
Lev Walkind88bea92017-07-20 11:21:30 +0300161 for(edx = (ctx->step >> 1); edx < td->elements_count;
162 edx++, ctx->step = (ctx->step & ~1) + 2) {
163 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkind88bea92017-07-20 11:21:30 +0300164
Lev Walkin890e6032017-07-24 01:48:59 +0400165 ASN_DEBUG("Decoding %s->%s", td->name, elm->name);
166
Lev Walkind88bea92017-07-20 11:21:30 +0300167 if(ctx->step & 1) {
168 goto microphase2_decode_continues;
169 }
170
171
172 if(IN_EXTENSION_GROUP(specs, edx)) {
173 /* Ignore non-root components in PHASE 1 */
Lev Walkin890e6032017-07-24 01:48:59 +0400174 break;
Lev Walkind88bea92017-07-20 11:21:30 +0300175 }
176
177 if(elm->optional) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700178 int32_t present = asn_get_few_bits(preamble, 1);
Lev Walkind88bea92017-07-20 11:21:30 +0300179 if(present < 0) {
Lev Walkin890e6032017-07-24 01:48:59 +0400180 ASN_DEBUG("Presence map ended prematurely: %d", present);
Lev Walkind88bea92017-07-20 11:21:30 +0300181 RETURN(RC_FAIL);
182 } else if(present == 0) {
Lev Walkin20696a42017-10-17 21:27:33 -0700183 if(elm->default_value_set) {
Lev Walkind88bea92017-07-20 11:21:30 +0300184 /* Fill-in DEFAULT */
Lev Walkincfc16d32017-08-30 19:15:08 -0700185 void *tmp;
Lev Walkin20696a42017-10-17 21:27:33 -0700186 if(elm->default_value_set(
187 element_ptrptr(st, elm, &tmp))) {
Lev Walkind88bea92017-07-20 11:21:30 +0300188 RETURN(RC_FAIL);
189 }
190 }
191 /* The member is not present. */
192 continue;
193 }
194 /* Present OPTIONAL or DEFAULT component. */
195 }
196
197 /*
198 * MICROPHASE 2: Invoke the member-specific decoder.
199 */
200 ctx->step |= 1; /* Confirm entering next microphase */
201 microphase2_decode_continues:
Lev Walkin14fd3e52017-08-27 01:38:45 -0700202 if(elm->flags & ATF_OPEN_TYPE) {
Lev Walkinf6853ce2017-08-11 00:50:27 -0700203 rval = OPEN_TYPE_oer_get(opt_codec_ctx, td, st, elm, ptr, size);
Lev Walkin7c876302017-08-10 06:11:24 -0700204 } else {
Lev Walkin09bec462017-08-31 01:31:43 -0700205 void *save_memb_ptr; /* Temporary reference. */
Lev Walkinf6853ce2017-08-11 00:50:27 -0700206 void **memb_ptr2; /* Pointer to a pointer to a memmber */
207
Lev Walkin09bec462017-08-31 01:31:43 -0700208 memb_ptr2 = element_ptrptr(st, elm, &save_memb_ptr);
Lev Walkinf6853ce2017-08-11 00:50:27 -0700209
Lev Walkin42f6c882017-10-20 02:39:08 -0700210 rval = elm->type->op->oer_decoder(
211 opt_codec_ctx, elm->type,
212 elm->encoding_constraints.oer_constraints, memb_ptr2, ptr,
213 size);
Lev Walkin7c876302017-08-10 06:11:24 -0700214 }
Lev Walkind88bea92017-07-20 11:21:30 +0300215 switch(rval.code) {
216 case RC_OK:
217 ADVANCE(rval.consumed);
218 break;
219 case RC_WMORE:
Lev Walkin890e6032017-07-24 01:48:59 +0400220 ASN_DEBUG("More bytes needed at element %s \"%s\"", td->name,
221 elm->name);
Lev Walkind88bea92017-07-20 11:21:30 +0300222 ADVANCE(rval.consumed);
223 RETURN(RC_WMORE);
224 case RC_FAIL:
Lev Walkin890e6032017-07-24 01:48:59 +0400225 ASN_DEBUG("Decoding failed at element %s \"%s\"", td->name,
226 elm->name);
Lev Walkind88bea92017-07-20 11:21:30 +0300227 RETURN(RC_FAIL);
228 }
229 } /* for(all root members) */
230
231 }
232 NEXT_PHASE(ctx);
233 /* FALL THROUGH */
234 case 2: {
235 /* Cleanup preamble. */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700236 asn_bit_data_t *preamble = ctx->ptr;
237 asn_bit_data_t *extadds;
Lev Walkin890e6032017-07-24 01:48:59 +0400238 int has_extensions_bit = (specs->ext_before >= 0);
Lev Walkind88bea92017-07-20 11:21:30 +0300239 int extensions_present =
Lev Walkin1a503892017-08-31 02:15:11 -0700240 has_extensions_bit
241 && (preamble->buffer == NULL
242 || (((const uint8_t *)preamble->buffer)[0] & 0x80));
Lev Walkind88bea92017-07-20 11:21:30 +0300243 uint8_t unused_bits;
244 size_t len = 0;
245 ssize_t len_len;
246 uint8_t *ebytes;
247
248 union {
249 const uint8_t *cptr;
250 uint8_t *uptr;
251 } unconst;
Lev Walkinbc0b0c52017-08-02 14:02:48 -0700252
253 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 2", td->name);
254
Lev Walkind88bea92017-07-20 11:21:30 +0300255 unconst.cptr = preamble->buffer;
256 FREEMEM(unconst.uptr);
Lev Walkin1a503892017-08-31 02:15:11 -0700257 preamble->buffer = 0; /* Will do extensions_present==1 next time. */
Lev Walkind88bea92017-07-20 11:21:30 +0300258
259 if(!extensions_present) {
260 ctx->phase = 10;
261 RETURN(RC_OK);
262 }
263
264 /*
265 * X.696 (08/2015) #16.1 (c), #16.4
266 * Read in the extension addition presence bitmap.
267 */
268
269 len_len = oer_fetch_length(ptr, size, &len);
270 if(len_len > 0) {
271 ADVANCE(len_len);
Lev Walkin42f6c882017-10-20 02:39:08 -0700272 } else if(len_len < 0) {
Lev Walkind88bea92017-07-20 11:21:30 +0300273 RETURN(RC_FAIL);
274 } else {
275 RETURN(RC_WMORE);
276 }
277
278 if(len == 0) {
279 /* 16.4.1-2 */
280 RETURN(RC_FAIL);
281 } else if(len > size) {
282 RETURN(RC_WMORE);
283 }
284
285 /* Account for unused bits */
286 unused_bits = 0x7 & *(const uint8_t *)ptr;
287 ADVANCE(1);
288 len--;
289 if(unused_bits && len == 0) {
290 RETURN(RC_FAIL);
291 }
292
293 /* Get the extensions map */
294 ebytes = MALLOC(len + 1);
295 if(!ebytes) {
296 RETURN(RC_FAIL);
297 }
298 memcpy(ebytes, ptr, len);
299 ebytes[len] = '\0';
300
301 extadds = preamble;
302 memset(extadds, 0, sizeof(*extadds));
303 extadds->buffer = ebytes;
304 extadds->nboff = 0;
305 extadds->nbits = 8 * len - unused_bits;
306
307 ADVANCE(len);
308 }
309 NEXT_PHASE(ctx);
310 ctx->step = (specs->ext_after + 1);
311 /* Fall through */
312 case 3:
Lev Walkin890e6032017-07-24 01:48:59 +0400313 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 3", td->name);
314 for(; ctx->step < specs->ext_before - 1; ctx->step++) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700315 asn_bit_data_t *extadds = ctx->ptr;
Lev Walkind88bea92017-07-20 11:21:30 +0300316 size_t edx = ctx->step;
317 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkin42f6c882017-10-20 02:39:08 -0700318 void *tmp_memb_ptr;
319 void **memb_ptr2 = element_ptrptr(st, elm, &tmp_memb_ptr);
Lev Walkind88bea92017-07-20 11:21:30 +0300320
Lev Walkin6cd0d562017-08-25 11:57:01 -0700321 switch(asn_get_few_bits(extadds, 1)) {
Lev Walkind88bea92017-07-20 11:21:30 +0300322 case -1:
323 /*
324 * Not every one of our extensions is known to the remote side.
325 * Continue filling in their defaults though.
326 */
327 /* Fall through */
328 case 0:
329 /* Fill-in DEFAULT */
Lev Walkin20696a42017-10-17 21:27:33 -0700330 if(elm->default_value_set
331 && elm->default_value_set(memb_ptr2)) {
Lev Walkind88bea92017-07-20 11:21:30 +0300332 RETURN(RC_FAIL);
333 }
334 continue;
335 case 1: {
336 /* Read OER open type */
Lev Walkin42f6c882017-10-20 02:39:08 -0700337 ssize_t ot_size =
338 oer_open_type_get(opt_codec_ctx, elm->type,
339 elm->encoding_constraints.oer_constraints,
340 memb_ptr2, ptr, size);
341 assert(ot_size <= (ssize_t)size);
Lev Walkind88bea92017-07-20 11:21:30 +0300342 if(ot_size > 0) {
343 ADVANCE(ot_size);
344 } else if(ot_size < 0) {
345 RETURN(RC_FAIL);
346 } else {
347 /* Roll back open type parsing */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700348 asn_get_undo(extadds, 1);
Lev Walkind88bea92017-07-20 11:21:30 +0300349 RETURN(RC_WMORE);
350 }
351 break;
352 }
353 default:
354 RETURN(RC_FAIL);
355 }
356 }
357
358 NEXT_PHASE(ctx);
359 /* Fall through */
360 case 4:
Lev Walkin890e6032017-07-24 01:48:59 +0400361 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 4", td->name);
Lev Walkind88bea92017-07-20 11:21:30 +0300362 /* Read in the rest of Open Types while ignoring them */
363 for(;;) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700364 asn_bit_data_t *extadds = ctx->ptr;
365 switch(asn_get_few_bits(extadds, 1)) {
Lev Walkind88bea92017-07-20 11:21:30 +0300366 case 0:
367 continue;
368 case 1: {
Lev Walkin51a1f3f2017-07-20 14:52:25 +0300369 ssize_t skipped = oer_open_type_skip(ptr, size);
370 if(skipped > 0) {
371 ADVANCE(skipped);
372 } else if(skipped < 0) {
Lev Walkind88bea92017-07-20 11:21:30 +0300373 RETURN(RC_FAIL);
374 } else {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700375 asn_get_undo(extadds, 1);
Lev Walkind88bea92017-07-20 11:21:30 +0300376 RETURN(RC_WMORE);
377 }
378 continue;
379 }
380 case -1:
381 /* No more Open Type encoded components */
382 break;
383 default:
384 RETURN(RC_FAIL);
385 }
386 break;
387 }
388 }
389
Lev Walkin42f6c882017-10-20 02:39:08 -0700390 RETURN(RC_OK);
Lev Walkind88bea92017-07-20 11:21:30 +0300391}
392
393/*
394 * Encode as Canonical OER.
395 */
396asn_enc_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700397SEQUENCE_encode_oer(const asn_TYPE_descriptor_t *td,
398 const asn_oer_constraints_t *constraints, const void *sptr,
Lev Walkin494fb702017-08-07 20:07:00 -0700399 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkind84f6032017-10-03 16:33:59 -0700400 const asn_SEQUENCE_specifics_t *specs = (const asn_SEQUENCE_specifics_t *)td->specifics;
Lev Walkin890e6032017-07-24 01:48:59 +0400401 size_t computed_size = 0;
402 int has_extensions_bit = (specs->ext_before >= 0);
403 size_t preamble_bits = (has_extensions_bit + specs->roms_count);
404 uint32_t has_extensions = 0;
405 size_t edx;
406 int ret;
Lev Walkind88bea92017-07-20 11:21:30 +0300407
Lev Walkin494fb702017-08-07 20:07:00 -0700408 (void)constraints;
409
Lev Walkin890e6032017-07-24 01:48:59 +0400410 if(preamble_bits) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700411 asn_bit_outp_t preamble;
Lev Walkind88bea92017-07-20 11:21:30 +0300412
Lev Walkin890e6032017-07-24 01:48:59 +0400413 memset(&preamble, 0, sizeof(preamble));
Lev Walkin6cd0d562017-08-25 11:57:01 -0700414 preamble.output = cb;
Lev Walkin890e6032017-07-24 01:48:59 +0400415 preamble.op_key = app_key;
416
417 if(has_extensions_bit) {
Lev Walkin494fb702017-08-07 20:07:00 -0700418 for(edx = specs->ext_after + 1;
419 (ssize_t)edx < specs->ext_before - 1; edx++) {
Lev Walkin890e6032017-07-24 01:48:59 +0400420 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkin20696a42017-10-17 21:27:33 -0700421 const void *memb_ptr = element_ptr(sptr, elm);
Lev Walkin09bec462017-08-31 01:31:43 -0700422 if(memb_ptr) {
Lev Walkin20696a42017-10-17 21:27:33 -0700423 if(elm->default_value_cmp
424 && elm->default_value_cmp(memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700425 /* Do not encode default values in extensions */
426 } else {
427 has_extensions = 1;
428 break;
429 }
Lev Walkin890e6032017-07-24 01:48:59 +0400430 }
431 }
Lev Walkin6cd0d562017-08-25 11:57:01 -0700432 ret = asn_put_few_bits(&preamble, has_extensions, 1);
Lev Walkin890e6032017-07-24 01:48:59 +0400433 assert(ret == 0);
434 if(ret < 0) {
435 ASN__ENCODE_FAILED;
436 }
437 }
438
439 /*
440 * Encode optional components bitmap.
441 */
442 if(specs->roms_count) {
443 for(edx = 0; edx < td->elements_count; edx++) {
444 asn_TYPE_member_t *elm = &td->elements[edx];
445
446 if(IN_EXTENSION_GROUP(specs, edx)) break;
447
448 if(elm->optional) {
Lev Walkin20696a42017-10-17 21:27:33 -0700449 const void *memb_ptr = element_ptr(sptr, elm);
Lev Walkin09bec462017-08-31 01:31:43 -0700450 uint32_t has_component = memb_ptr != NULL;
Lev Walkin20696a42017-10-17 21:27:33 -0700451 if(has_component && elm->default_value_cmp
452 && elm->default_value_cmp(&memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700453 has_component = 0;
454 }
Lev Walkin6cd0d562017-08-25 11:57:01 -0700455 ret = asn_put_few_bits(&preamble, has_component, 1);
Lev Walkin890e6032017-07-24 01:48:59 +0400456 if(ret < 0) {
457 ASN__ENCODE_FAILED;
458 }
459 }
460 }
461 }
462
Lev Walkin6cd0d562017-08-25 11:57:01 -0700463 asn_put_aligned_flush(&preamble);
Lev Walkin890e6032017-07-24 01:48:59 +0400464 computed_size += preamble.flushed_bytes;
465 } /* if(preamble_bits) */
466
467 /*
468 * Put root components and extensions root.
469 */
470 for(edx = 0; edx < td->elements_count; edx++) {
471 asn_TYPE_member_t *elm = &td->elements[edx];
472 asn_enc_rval_t er;
Lev Walkin20696a42017-10-17 21:27:33 -0700473 const void *memb_ptr;
Lev Walkin890e6032017-07-24 01:48:59 +0400474
475 if(IN_EXTENSION_GROUP(specs, edx)) break;
476
477 memb_ptr = element_ptr(sptr, elm);
Lev Walkin09bec462017-08-31 01:31:43 -0700478 if(memb_ptr) {
Lev Walkin20696a42017-10-17 21:27:33 -0700479 if(elm->default_value_cmp
480 && elm->default_value_cmp(memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700481 /* Skip default values in encoding */
482 continue;
483 }
484 } else {
Lev Walkin890e6032017-07-24 01:48:59 +0400485 if(elm->optional) continue;
486 /* Mandatory element is missing */
487 ASN__ENCODE_FAILED;
488 }
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +0800489 if(!elm->type->op->oer_encoder) {
Lev Walkin890e6032017-07-24 01:48:59 +0400490 ASN_DEBUG("OER encoder is not defined for type %s", elm->type->name);
491 ASN__ENCODE_FAILED;
492 }
Lev Walkina5972be2017-09-29 23:15:58 -0700493 er = elm->type->op->oer_encoder(
494 elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb,
495 app_key);
Lev Walkin890e6032017-07-24 01:48:59 +0400496 if(er.encoded == -1) {
497 ASN_DEBUG("... while encoding %s member \"%s\"\n", td->name,
498 elm->name);
499 return er;
500 }
501 computed_size += er.encoded;
502 }
503
504 /*
505 * Before encode extensions, encode extensions additions presense bitmap
506 # X.696 (08/2015) #16.4.
507 */
508 if(has_extensions) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700509 asn_bit_outp_t extadds;
Lev Walkin890e6032017-07-24 01:48:59 +0400510
511 /* Special case allowing us to use exactly one byte for #8.6 */
512 size_t aoms_length_bits = specs->aoms_count;
Lev Walkin09bec462017-08-31 01:31:43 -0700513 size_t aoms_length_bytes = (7 + aoms_length_bits) >> 3;
Lev Walkin890e6032017-07-24 01:48:59 +0400514 uint8_t unused_bits = 0x07 & (8 - (aoms_length_bits & 0x07));
515
516 assert(1 + aoms_length_bytes <= 127);
517
518 memset(&extadds, 0, sizeof(extadds));
Lev Walkin6cd0d562017-08-25 11:57:01 -0700519 extadds.output = cb;
Lev Walkin890e6032017-07-24 01:48:59 +0400520 extadds.op_key = app_key;
521
522 /* #8.6 length determinant */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700523 ret = asn_put_few_bits(&extadds, (1 + aoms_length_bytes), 8);
Lev Walkin890e6032017-07-24 01:48:59 +0400524 if(ret < 0) ASN__ENCODE_FAILED;
525
526 /* Number of unused bytes, #16.4.2 */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700527 ret = asn_put_few_bits(&extadds, unused_bits, 8);
Lev Walkin890e6032017-07-24 01:48:59 +0400528 if(ret < 0) ASN__ENCODE_FAILED;
529
530 /* Encode presence bitmap #16.4.3 */
Lev Walkin494fb702017-08-07 20:07:00 -0700531 for(edx = specs->ext_after + 1; (ssize_t)edx < specs->ext_before - 1;
532 edx++) {
Lev Walkin890e6032017-07-24 01:48:59 +0400533 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkin20696a42017-10-17 21:27:33 -0700534 const void *memb_ptr = element_ptr(sptr, elm);
535 if(memb_ptr && elm->default_value_cmp
536 && elm->default_value_cmp(memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700537 memb_ptr = 0; /* Do not encode default value. */
538 }
Lev Walkin6cd0d562017-08-25 11:57:01 -0700539 ret |= asn_put_few_bits(&extadds, memb_ptr ? 1 : 0, 1);
Lev Walkin890e6032017-07-24 01:48:59 +0400540 }
541 if(ret < 0) ASN__ENCODE_FAILED;
542
Lev Walkin6cd0d562017-08-25 11:57:01 -0700543 asn_put_aligned_flush(&extadds);
Lev Walkin890e6032017-07-24 01:48:59 +0400544 computed_size += extadds.flushed_bytes;
545
546 /* Now, encode extensions */
Lev Walkin494fb702017-08-07 20:07:00 -0700547 for(edx = specs->ext_after + 1; (ssize_t)edx < specs->ext_before - 1;
548 edx++) {
Lev Walkin890e6032017-07-24 01:48:59 +0400549 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkin20696a42017-10-17 21:27:33 -0700550 const void *memb_ptr = element_ptr(sptr, elm);
Lev Walkin890e6032017-07-24 01:48:59 +0400551
552 if(memb_ptr) {
Lev Walkin20696a42017-10-17 21:27:33 -0700553 if(elm->default_value_cmp
554 && elm->default_value_cmp(memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700555 /* Do not encode default value. */
556 } else {
Lev Walkin42f6c882017-10-20 02:39:08 -0700557 ssize_t wrote = oer_open_type_put(
Lev Walkina5972be2017-09-29 23:15:58 -0700558 elm->type, elm->encoding_constraints.oer_constraints,
559 memb_ptr, cb, app_key);
Lev Walkin42f6c882017-10-20 02:39:08 -0700560 if(wrote == -1) {
561 ASN__ENCODE_FAILED;
Lev Walkin09bec462017-08-31 01:31:43 -0700562 }
Lev Walkin42f6c882017-10-20 02:39:08 -0700563 computed_size += wrote;
Lev Walkin890e6032017-07-24 01:48:59 +0400564 }
Lev Walkin890e6032017-07-24 01:48:59 +0400565 } else if(!elm->optional) {
566 ASN__ENCODE_FAILED;
567 }
568 }
569 } /* if(has_extensions) */
570
571
572 {
573 asn_enc_rval_t er = {0, 0, 0};
574 er.encoded = computed_size;
575 ASN__ENCODED_OK(er);
576 }
Lev Walkind88bea92017-07-20 11:21:30 +0300577}
578
579#endif /* ASN_DISABLE_OER_SUPPORT */