blob: 404aa72645555f515a439167eb2aece3a66be603 [file] [log] [blame]
Lev Walkin9218bc12007-06-27 04:09:37 +00001/*
2 * Copyright (c) 2007 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#include <per_support.h>
7#include <constr_TYPE.h>
8#include <per_opentype.h>
9
10typedef struct uper_ugot_key {
11 asn_per_data_t oldpd; /* Old per data source */
12 size_t unclaimed;
13 size_t ot_moved; /* Number of bits moved by OT processing */
14 int repeat;
15} uper_ugot_key;
16
17static int uper_ugot_refill(asn_per_data_t *pd);
Lev Walkin375f0e92007-06-29 02:28:50 +000018static int per_skip_bits(asn_per_data_t *pd, int skip_nbits);
19static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd);
Lev Walkin9218bc12007-06-27 04:09:37 +000020
21/*
Lev Walkin375f0e92007-06-29 02:28:50 +000022 * Encode an "open type field".
Lev Walkin9218bc12007-06-27 04:09:37 +000023 * #10.1, #10.2
24 */
25int
26uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
27 void *buf;
Lev Walkin375f0e92007-06-29 02:28:50 +000028 void *bptr;
Lev Walkin9218bc12007-06-27 04:09:37 +000029 ssize_t size;
Lev Walkin375f0e92007-06-29 02:28:50 +000030 size_t toGo;
Lev Walkin9218bc12007-06-27 04:09:37 +000031
Lev Walkin375f0e92007-06-29 02:28:50 +000032 ASN_DEBUG("Open type put %s ...", td->name);
33
Lev Walkin9218bc12007-06-27 04:09:37 +000034 size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
35 if(size <= 0) return -1;
36
Lev Walkin375f0e92007-06-29 02:28:50 +000037 for(bptr = buf, toGo = size; toGo;) {
38 ssize_t maySave = uper_put_length(po, toGo);
Lev Walkin190419b2010-10-25 19:19:17 -070039 ASN_DEBUG("Prepending length %d to %s and allowing to save %d",
40 (int)size, td->name, (int)maySave);
Lev Walkin9218bc12007-06-27 04:09:37 +000041 if(maySave < 0) break;
Lev Walkin375f0e92007-06-29 02:28:50 +000042 if(per_put_many_bits(po, bptr, maySave * 8)) break;
43 bptr = (char *)bptr + maySave;
44 toGo -= maySave;
Lev Walkin9218bc12007-06-27 04:09:37 +000045 }
46
Lev Walkin375f0e92007-06-29 02:28:50 +000047 FREEMEM(buf);
48 if(toGo) return -1;
49
Lev Walkinfe1ffaf2010-10-25 21:07:59 -070050 ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)",
51 td->name, (long)size);
Lev Walkin9218bc12007-06-27 04:09:37 +000052
53 return 0;
54}
55
Lev Walkin375f0e92007-06-29 02:28:50 +000056static asn_dec_rval_t
57uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
58 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
59 asn_dec_rval_t rv;
60 ssize_t chunk_bytes;
61 int repeat;
62 uint8_t *buf = 0;
63 size_t bufLen = 0;
64 size_t bufSize = 0;
65 asn_per_data_t spd;
Lev Walkin55fdd992007-06-29 11:25:49 +000066 size_t padding;
Lev Walkin375f0e92007-06-29 02:28:50 +000067
Lev Walkin7c1dc052016-03-14 03:08:15 -070068 ASN__STACK_OVERFLOW_CHECK(ctx);
Lev Walkin375f0e92007-06-29 02:28:50 +000069
Lev Walkin7c97b882007-06-29 11:32:25 +000070 ASN_DEBUG("Getting open type %s...", td->name);
Lev Walkin375f0e92007-06-29 02:28:50 +000071
72 do {
73 chunk_bytes = uper_get_length(pd, -1, &repeat);
74 if(chunk_bytes < 0) {
75 FREEMEM(buf);
Lev Walkin7c1dc052016-03-14 03:08:15 -070076 ASN__DECODE_STARVED;
Lev Walkin375f0e92007-06-29 02:28:50 +000077 }
78 if(bufLen + chunk_bytes > bufSize) {
79 void *ptr;
80 bufSize = chunk_bytes + (bufSize << 2);
81 ptr = REALLOC(buf, bufSize);
82 if(!ptr) {
83 FREEMEM(buf);
Lev Walkin7c1dc052016-03-14 03:08:15 -070084 ASN__DECODE_FAILED;
Lev Walkin375f0e92007-06-29 02:28:50 +000085 }
86 buf = ptr;
87 }
88 if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) {
89 FREEMEM(buf);
Lev Walkin7c1dc052016-03-14 03:08:15 -070090 ASN__DECODE_STARVED;
Lev Walkin375f0e92007-06-29 02:28:50 +000091 }
92 bufLen += chunk_bytes;
93 } while(repeat);
94
Lev Walkinfe1ffaf2010-10-25 21:07:59 -070095 ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name,
96 (long)bufLen);
Lev Walkin55fdd992007-06-29 11:25:49 +000097
Lev Walkin375f0e92007-06-29 02:28:50 +000098 memset(&spd, 0, sizeof(spd));
99 spd.buffer = buf;
100 spd.nbits = bufLen << 3;
101
Lev Walkin69c73dc2012-02-21 02:15:08 -0800102 ASN_DEBUG_INDENT_ADD(+4);
Lev Walkin375f0e92007-06-29 02:28:50 +0000103 rv = td->uper_decoder(ctx, td, constraints, sptr, &spd);
Lev Walkin69c73dc2012-02-21 02:15:08 -0800104 ASN_DEBUG_INDENT_ADD(-4);
Lev Walkin375f0e92007-06-29 02:28:50 +0000105
Lev Walkin49f510f2007-06-29 17:33:04 +0000106 if(rv.code == RC_OK) {
107 /* Check padding validity */
108 padding = spd.nbits - spd.nboff;
Lev Walkin190419b2010-10-25 19:19:17 -0700109 if ((padding < 8 ||
110 /* X.691#10.1.3 */
111 (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) &&
Lev Walkina6dd57a2010-10-24 22:03:14 -0700112 per_get_few_bits(&spd, padding) == 0) {
Lev Walkin49f510f2007-06-29 17:33:04 +0000113 /* Everything is cool */
114 FREEMEM(buf);
115 return rv;
116 }
117 FREEMEM(buf);
118 if(padding >= 8) {
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700119 ASN_DEBUG("Too large padding %d in open type", (int)padding);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700120 ASN__DECODE_FAILED;
Lev Walkin49f510f2007-06-29 17:33:04 +0000121 } else {
122 ASN_DEBUG("Non-zero padding");
Lev Walkin7c1dc052016-03-14 03:08:15 -0700123 ASN__DECODE_FAILED;
Lev Walkin49f510f2007-06-29 17:33:04 +0000124 }
125 } else {
126 FREEMEM(buf);
Lev Walkin80515f02007-06-29 23:23:05 +0000127 /* rv.code could be RC_WMORE, nonsense in this context */
128 rv.code = RC_FAIL; /* Noone would give us more */
Lev Walkin55fdd992007-06-29 11:25:49 +0000129 }
130
Lev Walkin375f0e92007-06-29 02:28:50 +0000131 return rv;
132}
133
134static asn_dec_rval_t GCC_NOTUSED
135uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
Lev Walkin9218bc12007-06-27 04:09:37 +0000136 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
137 uper_ugot_key arg;
138 asn_dec_rval_t rv;
139 ssize_t padding;
140
Lev Walkin7c1dc052016-03-14 03:08:15 -0700141 ASN__STACK_OVERFLOW_CHECK(ctx);
Lev Walkin9218bc12007-06-27 04:09:37 +0000142
Lev Walkin375f0e92007-06-29 02:28:50 +0000143 ASN_DEBUG("Getting open type %s from %s", td->name,
144 per_data_string(pd));
Lev Walkin9218bc12007-06-27 04:09:37 +0000145 arg.oldpd = *pd;
146 arg.unclaimed = 0;
147 arg.ot_moved = 0;
148 arg.repeat = 1;
149 pd->refill = uper_ugot_refill;
150 pd->refill_key = &arg;
151 pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */
152 pd->moved = 0; /* This now counts the open type size in bits */
153
Lev Walkin69c73dc2012-02-21 02:15:08 -0800154 ASN_DEBUG_INDENT_ADD(+4);
Lev Walkin375f0e92007-06-29 02:28:50 +0000155 rv = td->uper_decoder(ctx, td, constraints, sptr, pd);
Lev Walkin69c73dc2012-02-21 02:15:08 -0800156 ASN_DEBUG_INDENT_ADD(-4);
Lev Walkin9218bc12007-06-27 04:09:37 +0000157
Lev Walkin375f0e92007-06-29 02:28:50 +0000158#define UPDRESTOREPD do { \
159 /* buffer and nboff are valid, preserve them. */ \
160 pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \
161 pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \
162 pd->refill = arg.oldpd.refill; \
163 pd->refill_key = arg.oldpd.refill_key; \
164 } while(0)
165
166 if(rv.code != RC_OK) {
167 UPDRESTOREPD;
168 return rv;
169 }
170
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700171 ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name,
Lev Walkin375f0e92007-06-29 02:28:50 +0000172 per_data_string(pd),
173 per_data_string(&arg.oldpd),
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700174 (int)arg.unclaimed, (int)arg.repeat);
Lev Walkin9218bc12007-06-27 04:09:37 +0000175
Lev Walkin9218bc12007-06-27 04:09:37 +0000176 padding = pd->moved % 8;
177 if(padding) {
178 int32_t pvalue;
179 if(padding > 7) {
180 ASN_DEBUG("Too large padding %d in open type",
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700181 (int)padding);
Lev Walkin9218bc12007-06-27 04:09:37 +0000182 rv.code = RC_FAIL;
Lev Walkin375f0e92007-06-29 02:28:50 +0000183 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000184 return rv;
185 }
186 padding = 8 - padding;
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700187 ASN_DEBUG("Getting padding of %d bits", (int)padding);
Lev Walkin9218bc12007-06-27 04:09:37 +0000188 pvalue = per_get_few_bits(pd, padding);
189 switch(pvalue) {
190 case -1:
191 ASN_DEBUG("Padding skip failed");
Lev Walkin375f0e92007-06-29 02:28:50 +0000192 UPDRESTOREPD;
Lev Walkin7c1dc052016-03-14 03:08:15 -0700193 ASN__DECODE_STARVED;
Lev Walkin9218bc12007-06-27 04:09:37 +0000194 case 0: break;
195 default:
196 ASN_DEBUG("Non-blank padding (%d bits 0x%02x)",
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700197 (int)padding, (int)pvalue);
Lev Walkin375f0e92007-06-29 02:28:50 +0000198 UPDRESTOREPD;
Lev Walkin7c1dc052016-03-14 03:08:15 -0700199 ASN__DECODE_FAILED;
Lev Walkin9218bc12007-06-27 04:09:37 +0000200 }
201 }
Lev Walkin375f0e92007-06-29 02:28:50 +0000202 if(pd->nboff != pd->nbits) {
203 ASN_DEBUG("Open type %s overhead pd%s old%s", td->name,
204 per_data_string(pd), per_data_string(&arg.oldpd));
205 if(1) {
206 UPDRESTOREPD;
Lev Walkin7c1dc052016-03-14 03:08:15 -0700207 ASN__DECODE_FAILED;
Lev Walkin375f0e92007-06-29 02:28:50 +0000208 } else {
209 arg.unclaimed += pd->nbits - pd->nboff;
210 }
Lev Walkin9218bc12007-06-27 04:09:37 +0000211 }
212
213 /* Adjust pd back so it points to original data */
Lev Walkin375f0e92007-06-29 02:28:50 +0000214 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000215
216 /* Skip data not consumed by the decoder */
Lev Walkin375f0e92007-06-29 02:28:50 +0000217 if(arg.unclaimed) {
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700218 ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed);
Lev Walkin375f0e92007-06-29 02:28:50 +0000219 switch(per_skip_bits(pd, arg.unclaimed)) {
Lev Walkin9218bc12007-06-27 04:09:37 +0000220 case -1:
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700221 ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700222 ASN__DECODE_STARVED;
Lev Walkin9218bc12007-06-27 04:09:37 +0000223 case 0:
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700224 ASN_DEBUG("Got claim of %d", (int)arg.unclaimed);
Lev Walkin375f0e92007-06-29 02:28:50 +0000225 break;
Lev Walkin9218bc12007-06-27 04:09:37 +0000226 default:
227 /* Padding must be blank */
228 ASN_DEBUG("Non-blank unconsumed padding");
Lev Walkin7c1dc052016-03-14 03:08:15 -0700229 ASN__DECODE_FAILED;
Lev Walkin9218bc12007-06-27 04:09:37 +0000230 }
Lev Walkin375f0e92007-06-29 02:28:50 +0000231 arg.unclaimed = 0;
Lev Walkin9218bc12007-06-27 04:09:37 +0000232 }
233
Lev Walkin9218bc12007-06-27 04:09:37 +0000234 if(arg.repeat) {
235 ASN_DEBUG("Not consumed the whole thing");
236 rv.code = RC_FAIL;
237 return rv;
238 }
239
240 return rv;
241}
242
Lev Walkin375f0e92007-06-29 02:28:50 +0000243
244asn_dec_rval_t
245uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
246 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
247
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700248 return uper_open_type_get_simple(ctx, td, constraints, sptr, pd);
Lev Walkin375f0e92007-06-29 02:28:50 +0000249}
250
Lev Walkin9218bc12007-06-27 04:09:37 +0000251int
Lev Walkin375f0e92007-06-29 02:28:50 +0000252uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) {
Lev Walkin9218bc12007-06-27 04:09:37 +0000253 asn_TYPE_descriptor_t s_td;
254 asn_dec_rval_t rv;
255
256 s_td.name = "<unknown extension>";
257 s_td.uper_decoder = uper_sot_suck;
258
Lev Walkin375f0e92007-06-29 02:28:50 +0000259 rv = uper_open_type_get(ctx, &s_td, 0, 0, pd);
Lev Walkin9218bc12007-06-27 04:09:37 +0000260 if(rv.code != RC_OK)
261 return -1;
262 else
263 return 0;
264}
265
266/*
267 * Internal functions.
268 */
269
270static asn_dec_rval_t
Lev Walkin375f0e92007-06-29 02:28:50 +0000271uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
Lev Walkin9218bc12007-06-27 04:09:37 +0000272 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
273 asn_dec_rval_t rv;
274
Lev Walkin375f0e92007-06-29 02:28:50 +0000275 (void)ctx;
Lev Walkin9218bc12007-06-27 04:09:37 +0000276 (void)td;
277 (void)constraints;
278 (void)sptr;
279
280 while(per_get_few_bits(pd, 24) >= 0);
281
282 rv.code = RC_OK;
283 rv.consumed = pd->moved;
284
285 return rv;
286}
287
288static int
289uper_ugot_refill(asn_per_data_t *pd) {
290 uper_ugot_key *arg = pd->refill_key;
291 ssize_t next_chunk_bytes, next_chunk_bits;
292 ssize_t avail;
293
294 asn_per_data_t *oldpd = &arg->oldpd;
295
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700296 ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld",
297 (long)pd->moved, (long)oldpd->moved);
Lev Walkin9218bc12007-06-27 04:09:37 +0000298
299 /* Advance our position to where pd is */
300 oldpd->buffer = pd->buffer;
301 oldpd->nboff = pd->nboff;
302 oldpd->nbits -= pd->moved - arg->ot_moved;
303 oldpd->moved += pd->moved - arg->ot_moved;
304 arg->ot_moved = pd->moved;
305
306 if(arg->unclaimed) {
307 /* Refill the container */
308 if(per_get_few_bits(oldpd, 1))
309 return -1;
310 if(oldpd->nboff == 0) {
311 assert(0);
312 return -1;
313 }
314 pd->buffer = oldpd->buffer;
315 pd->nboff = oldpd->nboff - 1;
316 pd->nbits = oldpd->nbits;
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700317 ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)",
318 (long)pd->moved);
Lev Walkin9218bc12007-06-27 04:09:37 +0000319 return 0;
320 }
321
322 if(!arg->repeat) {
323 ASN_DEBUG("Want more but refill doesn't have it");
324 return -1;
325 }
326
327 next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat);
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700328 ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld",
329 (long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat);
Lev Walkin9218bc12007-06-27 04:09:37 +0000330 if(next_chunk_bytes < 0) return -1;
331 if(next_chunk_bytes == 0) {
332 pd->refill = 0; /* No more refills, naturally */
333 assert(!arg->repeat); /* Implementation guarantee */
334 }
335 next_chunk_bits = next_chunk_bytes << 3;
336 avail = oldpd->nbits - oldpd->nboff;
337 if(avail >= next_chunk_bits) {
338 pd->nbits = oldpd->nboff + next_chunk_bits;
339 arg->unclaimed = 0;
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700340 ASN_DEBUG("!+Parent frame %ld bits, alloting %ld [%ld..%ld] (%ld)",
341 (long)next_chunk_bits, (long)oldpd->moved,
342 (long)oldpd->nboff, (long)oldpd->nbits,
343 (long)(oldpd->nbits - oldpd->nboff));
Lev Walkin9218bc12007-06-27 04:09:37 +0000344 } else {
345 pd->nbits = oldpd->nbits;
346 arg->unclaimed = next_chunk_bits - avail;
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700347 ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld",
348 (long)avail, (long)next_chunk_bits,
349 (long)arg->unclaimed);
Lev Walkin9218bc12007-06-27 04:09:37 +0000350 }
351 pd->buffer = oldpd->buffer;
352 pd->nboff = oldpd->nboff;
Lev Walkin375f0e92007-06-29 02:28:50 +0000353 ASN_DEBUG("Refilled pd%s old%s",
354 per_data_string(pd), per_data_string(oldpd));
Lev Walkin9218bc12007-06-27 04:09:37 +0000355 return 0;
356}
Lev Walkin375f0e92007-06-29 02:28:50 +0000357
358static int
359per_skip_bits(asn_per_data_t *pd, int skip_nbits) {
360 int hasNonZeroBits = 0;
361 while(skip_nbits > 0) {
362 int skip;
Lev Walkinda161982013-03-20 03:35:21 -0700363
364 /* per_get_few_bits() is more efficient when nbits <= 24 */
365 if(skip_nbits < 24)
Lev Walkin375f0e92007-06-29 02:28:50 +0000366 skip = skip_nbits;
367 else
368 skip = 24;
369 skip_nbits -= skip;
370
371 switch(per_get_few_bits(pd, skip)) {
372 case -1: return -1; /* Starving */
373 case 0: continue; /* Skipped empty space */
374 default: hasNonZeroBits = 1; continue;
375 }
376 }
377 return hasNonZeroBits;
378}