blob: 6ef1e4dff109c0058c0bdaae5eb7713ce11096e5 [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 */
Lev Walkin83668612017-10-21 00:24:31 -070040#define IN_EXTENSION_GROUP(specs, memb_idx) \
41 ((specs)->first_extension >= 0 \
42 && (unsigned)(specs)->first_extension <= (memb_idx))
43
44#define IN_ROOT_GROUP_PRED(edx) \
45 edx < (specs->first_extension < 0 ? td->elements_count \
46 : (size_t)specs->first_extension)
47
48#define FOR_IN_ROOT_GROUP(edx) for(edx = 0; IN_ROOT_GROUP_PRED(edx); edx++)
Lev Walkind88bea92017-07-20 11:21:30 +030049
50/*
51 * Return a standardized complex structure.
52 */
53#undef RETURN
54#define RETURN(_code) do { \
55 rval.code = _code; \
56 rval.consumed = consumed_myself;\
57 return rval; \
58 } while(0)
59
Lev Walkin890e6032017-07-24 01:48:59 +040060/*
61 * Return pointer to a member.
62 */
Lev Walkincfc16d32017-08-30 19:15:08 -070063static void **
64element_ptrptr(void *struct_ptr, asn_TYPE_member_t *elm, void **tmp_save_ptr) {
65 if(elm->flags & ATF_POINTER) {
66 /* Member is a pointer to another structure */
67 return (void **)((char *)struct_ptr + elm->memb_offset);
68 } else {
69 assert(tmp_save_ptr);
70 *tmp_save_ptr = (void *)((char *)struct_ptr + elm->memb_offset);
71 return tmp_save_ptr;
72 }
Lev Walkin890e6032017-07-24 01:48:59 +040073}
74
Lev Walkin20696a42017-10-17 21:27:33 -070075static const void *
76element_ptr(const void *struct_ptr, const asn_TYPE_member_t *elm) {
Lev Walkin890e6032017-07-24 01:48:59 +040077 if(elm->flags & ATF_POINTER) {
78 /* Member is a pointer to another structure */
Lev Walkin20696a42017-10-17 21:27:33 -070079 return *(const void *const *)((const char *)struct_ptr
80 + elm->memb_offset);
Lev Walkin890e6032017-07-24 01:48:59 +040081 } else {
Lev Walkin20696a42017-10-17 21:27:33 -070082 return (const void *)((const char *)struct_ptr + elm->memb_offset);
Lev Walkin890e6032017-07-24 01:48:59 +040083 }
84}
85
Lev Walkind88bea92017-07-20 11:21:30 +030086asn_dec_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -070087SEQUENCE_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
88 const asn_TYPE_descriptor_t *td,
Lev Walkin494fb702017-08-07 20:07:00 -070089 const asn_oer_constraints_t *constraints, void **struct_ptr,
90 const void *ptr, size_t size) {
Lev Walkind84f6032017-10-03 16:33:59 -070091 const asn_SEQUENCE_specifics_t *specs =
92 (const asn_SEQUENCE_specifics_t *)td->specifics;
Lev Walkind88bea92017-07-20 11:21:30 +030093 asn_dec_rval_t rval = {RC_OK, 0};
94 void *st = *struct_ptr; /* Target structure */
95 asn_struct_ctx_t *ctx; /* Decoder context */
96 size_t consumed_myself = 0; /* Consumed bytes from ptr. */
97
98
99 (void)opt_codec_ctx;
Lev Walkin494fb702017-08-07 20:07:00 -0700100 (void)constraints;
Lev Walkind88bea92017-07-20 11:21:30 +0300101
102 /*
103 * Create the target structure if it is not present already.
104 */
105 if(st == 0) {
106 st = *struct_ptr = CALLOC(1, specs->struct_size);
107 if(st == 0) {
108 RETURN(RC_FAIL);
109 }
110 }
111
112 /*
113 * Restore parsing context.
114 */
115 ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
Lev Walkind88bea92017-07-20 11:21:30 +0300116
117 /*
118 * Start to parse where left previously.
119 */
120 switch(ctx->phase) {
121 case 0: {
122 /*
123 * Fetch preamble.
124 */
Lev Walkind14802f2017-10-20 02:58:25 -0700125 asn_bit_data_t *preamble;
Lev Walkin83668612017-10-21 00:24:31 -0700126 int has_extensions_bit = (specs->first_extension >= 0);
Lev Walkin890e6032017-07-24 01:48:59 +0400127 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
Lev Walkinbc0b0c52017-08-02 14:02:48 -0700130 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 0", td->name);
131
Lev Walkin890e6032017-07-24 01:48:59 +0400132 ASN_DEBUG(
133 "Expecting preamble bits %zu for %s (including %d extension bits)",
134 preamble_bits, td->name, has_extensions_bit);
135
Lev Walkind14802f2017-10-20 02:58:25 -0700136 if(preamble_bytes > size) {
Lev Walkind88bea92017-07-20 11:21:30 +0300137 ASN__DECODE_STARVED;
138 }
139
Lev Walkind14802f2017-10-20 02:58:25 -0700140 preamble = asn_bit_data_new_contiguous(ptr, preamble_bits);
141 if(!preamble) {
Lev Walkind88bea92017-07-20 11:21:30 +0300142 RETURN(RC_FAIL);
143 }
Lev Walkin890e6032017-07-24 01:48:59 +0400144 preamble->nboff = has_extensions_bit;
Lev Walkind14802f2017-10-20 02:58:25 -0700145 ctx->ptr = preamble;
Lev Walkind88bea92017-07-20 11:21:30 +0300146 ADVANCE(preamble_bytes);
147 }
148 NEXT_PHASE(ctx);
149 /* FALL THROUGH */
150 case 1: {
151 /* Decode components of the extension root */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700152 asn_bit_data_t *preamble = ctx->ptr;
Lev Walkind88bea92017-07-20 11:21:30 +0300153 size_t edx;
154
Lev Walkin83668612017-10-21 00:24:31 -0700155 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 1 (Root)", td->name);
Lev Walkinbc0b0c52017-08-02 14:02:48 -0700156
Lev Walkind14802f2017-10-20 02:58:25 -0700157 assert(preamble);
158
Lev Walkin83668612017-10-21 00:24:31 -0700159 for(edx = (ctx->step >> 1); IN_ROOT_GROUP_PRED(edx);
Lev Walkind88bea92017-07-20 11:21:30 +0300160 edx++, ctx->step = (ctx->step & ~1) + 2) {
161 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkind88bea92017-07-20 11:21:30 +0300162
Lev Walkin890e6032017-07-24 01:48:59 +0400163 ASN_DEBUG("Decoding %s->%s", td->name, elm->name);
164
Lev Walkin83668612017-10-21 00:24:31 -0700165 assert(!IN_EXTENSION_GROUP(specs, edx));
166
Lev Walkind88bea92017-07-20 11:21:30 +0300167 if(ctx->step & 1) {
168 goto microphase2_decode_continues;
169 }
170
171
Lev Walkind88bea92017-07-20 11:21:30 +0300172 if(elm->optional) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700173 int32_t present = asn_get_few_bits(preamble, 1);
Lev Walkind88bea92017-07-20 11:21:30 +0300174 if(present < 0) {
Lev Walkin890e6032017-07-24 01:48:59 +0400175 ASN_DEBUG("Presence map ended prematurely: %d", present);
Lev Walkind88bea92017-07-20 11:21:30 +0300176 RETURN(RC_FAIL);
177 } else if(present == 0) {
Lev Walkin20696a42017-10-17 21:27:33 -0700178 if(elm->default_value_set) {
Lev Walkind88bea92017-07-20 11:21:30 +0300179 /* Fill-in DEFAULT */
Lev Walkincfc16d32017-08-30 19:15:08 -0700180 void *tmp;
Lev Walkin20696a42017-10-17 21:27:33 -0700181 if(elm->default_value_set(
182 element_ptrptr(st, elm, &tmp))) {
Lev Walkind88bea92017-07-20 11:21:30 +0300183 RETURN(RC_FAIL);
184 }
185 }
186 /* The member is not present. */
187 continue;
188 }
189 /* Present OPTIONAL or DEFAULT component. */
190 }
191
192 /*
193 * MICROPHASE 2: Invoke the member-specific decoder.
194 */
195 ctx->step |= 1; /* Confirm entering next microphase */
196 microphase2_decode_continues:
Lev Walkin14fd3e52017-08-27 01:38:45 -0700197 if(elm->flags & ATF_OPEN_TYPE) {
Lev Walkinf6853ce2017-08-11 00:50:27 -0700198 rval = OPEN_TYPE_oer_get(opt_codec_ctx, td, st, elm, ptr, size);
Lev Walkin7c876302017-08-10 06:11:24 -0700199 } else {
Lev Walkin09bec462017-08-31 01:31:43 -0700200 void *save_memb_ptr; /* Temporary reference. */
Lev Walkinf6853ce2017-08-11 00:50:27 -0700201 void **memb_ptr2; /* Pointer to a pointer to a memmber */
202
Lev Walkin09bec462017-08-31 01:31:43 -0700203 memb_ptr2 = element_ptrptr(st, elm, &save_memb_ptr);
Lev Walkinf6853ce2017-08-11 00:50:27 -0700204
Lev Walkin42f6c882017-10-20 02:39:08 -0700205 rval = elm->type->op->oer_decoder(
206 opt_codec_ctx, elm->type,
207 elm->encoding_constraints.oer_constraints, memb_ptr2, ptr,
208 size);
Lev Walkin7c876302017-08-10 06:11:24 -0700209 }
Lev Walkind88bea92017-07-20 11:21:30 +0300210 switch(rval.code) {
211 case RC_OK:
212 ADVANCE(rval.consumed);
213 break;
214 case RC_WMORE:
Lev Walkin890e6032017-07-24 01:48:59 +0400215 ASN_DEBUG("More bytes needed at element %s \"%s\"", td->name,
216 elm->name);
Lev Walkind88bea92017-07-20 11:21:30 +0300217 ADVANCE(rval.consumed);
218 RETURN(RC_WMORE);
219 case RC_FAIL:
Lev Walkin890e6032017-07-24 01:48:59 +0400220 ASN_DEBUG("Decoding failed at element %s \"%s\"", td->name,
221 elm->name);
Lev Walkind88bea92017-07-20 11:21:30 +0300222 RETURN(RC_FAIL);
223 }
224 } /* for(all root members) */
225
226 }
227 NEXT_PHASE(ctx);
228 /* FALL THROUGH */
Lev Walkind14802f2017-10-20 02:58:25 -0700229 case 2:
230 assert(ctx->ptr);
231 {
Lev Walkind88bea92017-07-20 11:21:30 +0300232 /* Cleanup preamble. */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700233 asn_bit_data_t *preamble = ctx->ptr;
234 asn_bit_data_t *extadds;
Lev Walkin83668612017-10-21 00:24:31 -0700235 int has_extensions_bit = (specs->first_extension >= 0);
Lev Walkind88bea92017-07-20 11:21:30 +0300236 int extensions_present =
Lev Walkin1a503892017-08-31 02:15:11 -0700237 has_extensions_bit
238 && (preamble->buffer == NULL
239 || (((const uint8_t *)preamble->buffer)[0] & 0x80));
Lev Walkind88bea92017-07-20 11:21:30 +0300240 uint8_t unused_bits;
241 size_t len = 0;
242 ssize_t len_len;
Lev Walkinbc0b0c52017-08-02 14:02:48 -0700243
244 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 2", td->name);
245
Lev Walkin1a503892017-08-31 02:15:11 -0700246 preamble->buffer = 0; /* Will do extensions_present==1 next time. */
Lev Walkind88bea92017-07-20 11:21:30 +0300247
248 if(!extensions_present) {
249 ctx->phase = 10;
250 RETURN(RC_OK);
251 }
252
253 /*
254 * X.696 (08/2015) #16.1 (c), #16.4
255 * Read in the extension addition presence bitmap.
256 */
257
258 len_len = oer_fetch_length(ptr, size, &len);
259 if(len_len > 0) {
260 ADVANCE(len_len);
Lev Walkin42f6c882017-10-20 02:39:08 -0700261 } else if(len_len < 0) {
Lev Walkind88bea92017-07-20 11:21:30 +0300262 RETURN(RC_FAIL);
263 } else {
264 RETURN(RC_WMORE);
265 }
266
267 if(len == 0) {
268 /* 16.4.1-2 */
269 RETURN(RC_FAIL);
270 } else if(len > size) {
271 RETURN(RC_WMORE);
272 }
273
274 /* Account for unused bits */
275 unused_bits = 0x7 & *(const uint8_t *)ptr;
276 ADVANCE(1);
277 len--;
278 if(unused_bits && len == 0) {
279 RETURN(RC_FAIL);
280 }
281
282 /* Get the extensions map */
Lev Walkind14802f2017-10-20 02:58:25 -0700283 extadds = asn_bit_data_new_contiguous(ptr, len * 8 - unused_bits);
284 if(!extadds) {
Lev Walkind88bea92017-07-20 11:21:30 +0300285 RETURN(RC_FAIL);
286 }
Lev Walkind14802f2017-10-20 02:58:25 -0700287 FREEMEM(preamble);
288 ctx->ptr = extadds;
Lev Walkind88bea92017-07-20 11:21:30 +0300289 ADVANCE(len);
290 }
291 NEXT_PHASE(ctx);
Lev Walkin83668612017-10-21 00:24:31 -0700292 ctx->step =
293 (specs->first_extension < 0 ? td->elements_count
294 : (size_t)specs->first_extension);
Lev Walkind88bea92017-07-20 11:21:30 +0300295 /* Fall through */
296 case 3:
Lev Walkin83668612017-10-21 00:24:31 -0700297 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 3 (Extensions)", td->name);
298 for(; ctx->step < (signed)td->elements_count; ctx->step++) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700299 asn_bit_data_t *extadds = ctx->ptr;
Lev Walkind88bea92017-07-20 11:21:30 +0300300 size_t edx = ctx->step;
301 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkin42f6c882017-10-20 02:39:08 -0700302 void *tmp_memb_ptr;
303 void **memb_ptr2 = element_ptrptr(st, elm, &tmp_memb_ptr);
Lev Walkind88bea92017-07-20 11:21:30 +0300304
Lev Walkin6cd0d562017-08-25 11:57:01 -0700305 switch(asn_get_few_bits(extadds, 1)) {
Lev Walkind88bea92017-07-20 11:21:30 +0300306 case -1:
307 /*
308 * Not every one of our extensions is known to the remote side.
309 * Continue filling in their defaults though.
310 */
311 /* Fall through */
312 case 0:
313 /* Fill-in DEFAULT */
Lev Walkin20696a42017-10-17 21:27:33 -0700314 if(elm->default_value_set
315 && elm->default_value_set(memb_ptr2)) {
Lev Walkind88bea92017-07-20 11:21:30 +0300316 RETURN(RC_FAIL);
317 }
318 continue;
319 case 1: {
320 /* Read OER open type */
Lev Walkin42f6c882017-10-20 02:39:08 -0700321 ssize_t ot_size =
322 oer_open_type_get(opt_codec_ctx, elm->type,
323 elm->encoding_constraints.oer_constraints,
324 memb_ptr2, ptr, size);
325 assert(ot_size <= (ssize_t)size);
Lev Walkind88bea92017-07-20 11:21:30 +0300326 if(ot_size > 0) {
327 ADVANCE(ot_size);
328 } else if(ot_size < 0) {
329 RETURN(RC_FAIL);
330 } else {
331 /* Roll back open type parsing */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700332 asn_get_undo(extadds, 1);
Lev Walkind88bea92017-07-20 11:21:30 +0300333 RETURN(RC_WMORE);
334 }
335 break;
336 }
337 default:
338 RETURN(RC_FAIL);
339 }
340 }
341
342 NEXT_PHASE(ctx);
343 /* Fall through */
344 case 4:
Lev Walkin890e6032017-07-24 01:48:59 +0400345 ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 4", td->name);
Lev Walkind88bea92017-07-20 11:21:30 +0300346 /* Read in the rest of Open Types while ignoring them */
347 for(;;) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700348 asn_bit_data_t *extadds = ctx->ptr;
349 switch(asn_get_few_bits(extadds, 1)) {
Lev Walkind88bea92017-07-20 11:21:30 +0300350 case 0:
351 continue;
352 case 1: {
Lev Walkin51a1f3f2017-07-20 14:52:25 +0300353 ssize_t skipped = oer_open_type_skip(ptr, size);
354 if(skipped > 0) {
355 ADVANCE(skipped);
356 } else if(skipped < 0) {
Lev Walkind88bea92017-07-20 11:21:30 +0300357 RETURN(RC_FAIL);
358 } else {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700359 asn_get_undo(extadds, 1);
Lev Walkind88bea92017-07-20 11:21:30 +0300360 RETURN(RC_WMORE);
361 }
362 continue;
363 }
364 case -1:
365 /* No more Open Type encoded components */
366 break;
367 default:
368 RETURN(RC_FAIL);
369 }
370 break;
371 }
372 }
373
Lev Walkin42f6c882017-10-20 02:39:08 -0700374 RETURN(RC_OK);
Lev Walkind88bea92017-07-20 11:21:30 +0300375}
376
377/*
378 * Encode as Canonical OER.
379 */
380asn_enc_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700381SEQUENCE_encode_oer(const asn_TYPE_descriptor_t *td,
382 const asn_oer_constraints_t *constraints, const void *sptr,
Lev Walkin494fb702017-08-07 20:07:00 -0700383 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkind84f6032017-10-03 16:33:59 -0700384 const asn_SEQUENCE_specifics_t *specs = (const asn_SEQUENCE_specifics_t *)td->specifics;
Lev Walkin890e6032017-07-24 01:48:59 +0400385 size_t computed_size = 0;
Lev Walkin83668612017-10-21 00:24:31 -0700386 int has_extensions_bit = (specs->first_extension >= 0);
Lev Walkin890e6032017-07-24 01:48:59 +0400387 size_t preamble_bits = (has_extensions_bit + specs->roms_count);
388 uint32_t has_extensions = 0;
389 size_t edx;
390 int ret;
Lev Walkind88bea92017-07-20 11:21:30 +0300391
Lev Walkin494fb702017-08-07 20:07:00 -0700392 (void)constraints;
393
Lev Walkin890e6032017-07-24 01:48:59 +0400394 if(preamble_bits) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700395 asn_bit_outp_t preamble;
Lev Walkind88bea92017-07-20 11:21:30 +0300396
Lev Walkin890e6032017-07-24 01:48:59 +0400397 memset(&preamble, 0, sizeof(preamble));
Lev Walkin6cd0d562017-08-25 11:57:01 -0700398 preamble.output = cb;
Lev Walkin890e6032017-07-24 01:48:59 +0400399 preamble.op_key = app_key;
400
401 if(has_extensions_bit) {
Lev Walkin83668612017-10-21 00:24:31 -0700402 for(edx = specs->first_extension; edx < td->elements_count; edx++) {
Lev Walkin890e6032017-07-24 01:48:59 +0400403 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkin20696a42017-10-17 21:27:33 -0700404 const void *memb_ptr = element_ptr(sptr, elm);
Lev Walkin09bec462017-08-31 01:31:43 -0700405 if(memb_ptr) {
Lev Walkin20696a42017-10-17 21:27:33 -0700406 if(elm->default_value_cmp
407 && elm->default_value_cmp(memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700408 /* Do not encode default values in extensions */
409 } else {
410 has_extensions = 1;
411 break;
412 }
Lev Walkin890e6032017-07-24 01:48:59 +0400413 }
414 }
Lev Walkin6cd0d562017-08-25 11:57:01 -0700415 ret = asn_put_few_bits(&preamble, has_extensions, 1);
Lev Walkin890e6032017-07-24 01:48:59 +0400416 assert(ret == 0);
417 if(ret < 0) {
418 ASN__ENCODE_FAILED;
419 }
420 }
421
422 /*
423 * Encode optional components bitmap.
424 */
425 if(specs->roms_count) {
Lev Walkin83668612017-10-21 00:24:31 -0700426 FOR_IN_ROOT_GROUP(edx) {
Lev Walkin890e6032017-07-24 01:48:59 +0400427 asn_TYPE_member_t *elm = &td->elements[edx];
428
429 if(IN_EXTENSION_GROUP(specs, edx)) break;
430
431 if(elm->optional) {
Lev Walkin20696a42017-10-17 21:27:33 -0700432 const void *memb_ptr = element_ptr(sptr, elm);
Lev Walkin09bec462017-08-31 01:31:43 -0700433 uint32_t has_component = memb_ptr != NULL;
Lev Walkin20696a42017-10-17 21:27:33 -0700434 if(has_component && elm->default_value_cmp
Lev Walkin3c373852017-10-21 01:09:13 -0700435 && elm->default_value_cmp(memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700436 has_component = 0;
437 }
Lev Walkin6cd0d562017-08-25 11:57:01 -0700438 ret = asn_put_few_bits(&preamble, has_component, 1);
Lev Walkin890e6032017-07-24 01:48:59 +0400439 if(ret < 0) {
440 ASN__ENCODE_FAILED;
441 }
442 }
443 }
444 }
445
Lev Walkin6cd0d562017-08-25 11:57:01 -0700446 asn_put_aligned_flush(&preamble);
Lev Walkin890e6032017-07-24 01:48:59 +0400447 computed_size += preamble.flushed_bytes;
448 } /* if(preamble_bits) */
449
450 /*
451 * Put root components and extensions root.
452 */
453 for(edx = 0; edx < td->elements_count; edx++) {
454 asn_TYPE_member_t *elm = &td->elements[edx];
455 asn_enc_rval_t er;
Lev Walkin20696a42017-10-17 21:27:33 -0700456 const void *memb_ptr;
Lev Walkin890e6032017-07-24 01:48:59 +0400457
458 if(IN_EXTENSION_GROUP(specs, edx)) break;
459
460 memb_ptr = element_ptr(sptr, elm);
Lev Walkin09bec462017-08-31 01:31:43 -0700461 if(memb_ptr) {
Lev Walkin20696a42017-10-17 21:27:33 -0700462 if(elm->default_value_cmp
463 && elm->default_value_cmp(memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700464 /* Skip default values in encoding */
465 continue;
466 }
467 } else {
Lev Walkin890e6032017-07-24 01:48:59 +0400468 if(elm->optional) continue;
469 /* Mandatory element is missing */
470 ASN__ENCODE_FAILED;
471 }
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +0800472 if(!elm->type->op->oer_encoder) {
Lev Walkin890e6032017-07-24 01:48:59 +0400473 ASN_DEBUG("OER encoder is not defined for type %s", elm->type->name);
474 ASN__ENCODE_FAILED;
475 }
Lev Walkina5972be2017-09-29 23:15:58 -0700476 er = elm->type->op->oer_encoder(
477 elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb,
478 app_key);
Lev Walkin890e6032017-07-24 01:48:59 +0400479 if(er.encoded == -1) {
480 ASN_DEBUG("... while encoding %s member \"%s\"\n", td->name,
481 elm->name);
482 return er;
483 }
484 computed_size += er.encoded;
485 }
486
487 /*
488 * Before encode extensions, encode extensions additions presense bitmap
489 # X.696 (08/2015) #16.4.
490 */
491 if(has_extensions) {
Lev Walkin6cd0d562017-08-25 11:57:01 -0700492 asn_bit_outp_t extadds;
Lev Walkin890e6032017-07-24 01:48:59 +0400493
494 /* Special case allowing us to use exactly one byte for #8.6 */
495 size_t aoms_length_bits = specs->aoms_count;
Lev Walkin09bec462017-08-31 01:31:43 -0700496 size_t aoms_length_bytes = (7 + aoms_length_bits) >> 3;
Lev Walkin890e6032017-07-24 01:48:59 +0400497 uint8_t unused_bits = 0x07 & (8 - (aoms_length_bits & 0x07));
498
499 assert(1 + aoms_length_bytes <= 127);
500
501 memset(&extadds, 0, sizeof(extadds));
Lev Walkin6cd0d562017-08-25 11:57:01 -0700502 extadds.output = cb;
Lev Walkin890e6032017-07-24 01:48:59 +0400503 extadds.op_key = app_key;
504
505 /* #8.6 length determinant */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700506 ret = asn_put_few_bits(&extadds, (1 + aoms_length_bytes), 8);
Lev Walkin890e6032017-07-24 01:48:59 +0400507 if(ret < 0) ASN__ENCODE_FAILED;
508
509 /* Number of unused bytes, #16.4.2 */
Lev Walkin6cd0d562017-08-25 11:57:01 -0700510 ret = asn_put_few_bits(&extadds, unused_bits, 8);
Lev Walkin890e6032017-07-24 01:48:59 +0400511 if(ret < 0) ASN__ENCODE_FAILED;
512
513 /* Encode presence bitmap #16.4.3 */
Lev Walkin83668612017-10-21 00:24:31 -0700514 for(edx = specs->first_extension; edx < td->elements_count; edx++) {
Lev Walkin890e6032017-07-24 01:48:59 +0400515 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkin20696a42017-10-17 21:27:33 -0700516 const void *memb_ptr = element_ptr(sptr, elm);
517 if(memb_ptr && elm->default_value_cmp
518 && elm->default_value_cmp(memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700519 memb_ptr = 0; /* Do not encode default value. */
520 }
Lev Walkin6cd0d562017-08-25 11:57:01 -0700521 ret |= asn_put_few_bits(&extadds, memb_ptr ? 1 : 0, 1);
Lev Walkin890e6032017-07-24 01:48:59 +0400522 }
523 if(ret < 0) ASN__ENCODE_FAILED;
524
Lev Walkin6cd0d562017-08-25 11:57:01 -0700525 asn_put_aligned_flush(&extadds);
Lev Walkin890e6032017-07-24 01:48:59 +0400526 computed_size += extadds.flushed_bytes;
527
528 /* Now, encode extensions */
Lev Walkin83668612017-10-21 00:24:31 -0700529 for(edx = specs->first_extension; edx < td->elements_count; edx++) {
Lev Walkin890e6032017-07-24 01:48:59 +0400530 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkin20696a42017-10-17 21:27:33 -0700531 const void *memb_ptr = element_ptr(sptr, elm);
Lev Walkin890e6032017-07-24 01:48:59 +0400532
533 if(memb_ptr) {
Lev Walkin20696a42017-10-17 21:27:33 -0700534 if(elm->default_value_cmp
535 && elm->default_value_cmp(memb_ptr) == 0) {
Lev Walkin09bec462017-08-31 01:31:43 -0700536 /* Do not encode default value. */
537 } else {
Lev Walkin42f6c882017-10-20 02:39:08 -0700538 ssize_t wrote = oer_open_type_put(
Lev Walkina5972be2017-09-29 23:15:58 -0700539 elm->type, elm->encoding_constraints.oer_constraints,
540 memb_ptr, cb, app_key);
Lev Walkin42f6c882017-10-20 02:39:08 -0700541 if(wrote == -1) {
542 ASN__ENCODE_FAILED;
Lev Walkin09bec462017-08-31 01:31:43 -0700543 }
Lev Walkin42f6c882017-10-20 02:39:08 -0700544 computed_size += wrote;
Lev Walkin890e6032017-07-24 01:48:59 +0400545 }
Lev Walkin890e6032017-07-24 01:48:59 +0400546 } else if(!elm->optional) {
547 ASN__ENCODE_FAILED;
548 }
549 }
550 } /* if(has_extensions) */
551
552
553 {
554 asn_enc_rval_t er = {0, 0, 0};
555 er.encoded = computed_size;
556 ASN__ENCODED_OK(er);
557 }
Lev Walkind88bea92017-07-20 11:21:30 +0300558}
559
560#endif /* ASN_DISABLE_OER_SUPPORT */