blob: ebcf076cea7c687e014f3140a71a8a9a3f752307 [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
Lev Walkin55fdd992007-06-29 11:25:49 +000021int asn_debug_indent;
22
Lev Walkin9218bc12007-06-27 04:09:37 +000023/*
Lev Walkin375f0e92007-06-29 02:28:50 +000024 * Encode an "open type field".
Lev Walkin9218bc12007-06-27 04:09:37 +000025 * #10.1, #10.2
26 */
27int
28uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
29 void *buf;
Lev Walkin375f0e92007-06-29 02:28:50 +000030 void *bptr;
Lev Walkin9218bc12007-06-27 04:09:37 +000031 ssize_t size;
Lev Walkin375f0e92007-06-29 02:28:50 +000032 size_t toGo;
Lev Walkin9218bc12007-06-27 04:09:37 +000033
Lev Walkin375f0e92007-06-29 02:28:50 +000034 ASN_DEBUG("Open type put %s ...", td->name);
35
Lev Walkin9218bc12007-06-27 04:09:37 +000036 size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
37 if(size <= 0) return -1;
38
Lev Walkin375f0e92007-06-29 02:28:50 +000039 for(bptr = buf, toGo = size; toGo;) {
40 ssize_t maySave = uper_put_length(po, toGo);
Lev Walkin190419b2010-10-25 19:19:17 -070041 ASN_DEBUG("Prepending length %d to %s and allowing to save %d",
42 (int)size, td->name, (int)maySave);
Lev Walkin9218bc12007-06-27 04:09:37 +000043 if(maySave < 0) break;
Lev Walkin375f0e92007-06-29 02:28:50 +000044 if(per_put_many_bits(po, bptr, maySave * 8)) break;
45 bptr = (char *)bptr + maySave;
46 toGo -= maySave;
Lev Walkin9218bc12007-06-27 04:09:37 +000047 }
48
Lev Walkin375f0e92007-06-29 02:28:50 +000049 FREEMEM(buf);
50 if(toGo) return -1;
51
Lev Walkinfe1ffaf2010-10-25 21:07:59 -070052 ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)",
53 td->name, (long)size);
Lev Walkin9218bc12007-06-27 04:09:37 +000054
55 return 0;
56}
57
Lev Walkin375f0e92007-06-29 02:28:50 +000058static asn_dec_rval_t
59uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
60 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
61 asn_dec_rval_t rv;
62 ssize_t chunk_bytes;
63 int repeat;
64 uint8_t *buf = 0;
65 size_t bufLen = 0;
66 size_t bufSize = 0;
67 asn_per_data_t spd;
Lev Walkin55fdd992007-06-29 11:25:49 +000068 size_t padding;
Lev Walkin375f0e92007-06-29 02:28:50 +000069
70 _ASN_STACK_OVERFLOW_CHECK(ctx);
71
Lev Walkin7c97b882007-06-29 11:32:25 +000072 ASN_DEBUG("Getting open type %s...", td->name);
Lev Walkin375f0e92007-06-29 02:28:50 +000073
74 do {
75 chunk_bytes = uper_get_length(pd, -1, &repeat);
76 if(chunk_bytes < 0) {
77 FREEMEM(buf);
78 _ASN_DECODE_STARVED;
79 }
80 if(bufLen + chunk_bytes > bufSize) {
81 void *ptr;
82 bufSize = chunk_bytes + (bufSize << 2);
83 ptr = REALLOC(buf, bufSize);
84 if(!ptr) {
85 FREEMEM(buf);
86 _ASN_DECODE_FAILED;
87 }
88 buf = ptr;
89 }
90 if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) {
91 FREEMEM(buf);
92 _ASN_DECODE_STARVED;
93 }
94 bufLen += chunk_bytes;
95 } while(repeat);
96
Lev Walkinfe1ffaf2010-10-25 21:07:59 -070097 ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name,
98 (long)bufLen);
Lev Walkin55fdd992007-06-29 11:25:49 +000099
Lev Walkin375f0e92007-06-29 02:28:50 +0000100 memset(&spd, 0, sizeof(spd));
101 spd.buffer = buf;
102 spd.nbits = bufLen << 3;
103
Lev Walkin55fdd992007-06-29 11:25:49 +0000104 asn_debug_indent += 4;
Lev Walkin375f0e92007-06-29 02:28:50 +0000105 rv = td->uper_decoder(ctx, td, constraints, sptr, &spd);
Lev Walkin55fdd992007-06-29 11:25:49 +0000106 asn_debug_indent -= 4;
Lev Walkin375f0e92007-06-29 02:28:50 +0000107
Lev Walkin49f510f2007-06-29 17:33:04 +0000108 if(rv.code == RC_OK) {
109 /* Check padding validity */
110 padding = spd.nbits - spd.nboff;
Lev Walkin190419b2010-10-25 19:19:17 -0700111 if ((padding < 8 ||
112 /* X.691#10.1.3 */
113 (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) &&
Lev Walkina6dd57a2010-10-24 22:03:14 -0700114 per_get_few_bits(&spd, padding) == 0) {
Lev Walkin49f510f2007-06-29 17:33:04 +0000115 /* Everything is cool */
116 FREEMEM(buf);
117 return rv;
118 }
119 FREEMEM(buf);
120 if(padding >= 8) {
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700121 ASN_DEBUG("Too large padding %d in open type", (int)padding);
Lev Walkin49f510f2007-06-29 17:33:04 +0000122 _ASN_DECODE_FAILED;
123 } else {
124 ASN_DEBUG("Non-zero padding");
125 _ASN_DECODE_FAILED;
126 }
127 } else {
128 FREEMEM(buf);
Lev Walkin80515f02007-06-29 23:23:05 +0000129 /* rv.code could be RC_WMORE, nonsense in this context */
130 rv.code = RC_FAIL; /* Noone would give us more */
Lev Walkin55fdd992007-06-29 11:25:49 +0000131 }
132
Lev Walkin375f0e92007-06-29 02:28:50 +0000133 return rv;
134}
135
136static asn_dec_rval_t GCC_NOTUSED
137uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
Lev Walkin9218bc12007-06-27 04:09:37 +0000138 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
139 uper_ugot_key arg;
140 asn_dec_rval_t rv;
141 ssize_t padding;
142
Lev Walkin375f0e92007-06-29 02:28:50 +0000143 _ASN_STACK_OVERFLOW_CHECK(ctx);
Lev Walkin9218bc12007-06-27 04:09:37 +0000144
Lev Walkin375f0e92007-06-29 02:28:50 +0000145 ASN_DEBUG("Getting open type %s from %s", td->name,
146 per_data_string(pd));
Lev Walkin9218bc12007-06-27 04:09:37 +0000147 arg.oldpd = *pd;
148 arg.unclaimed = 0;
149 arg.ot_moved = 0;
150 arg.repeat = 1;
151 pd->refill = uper_ugot_refill;
152 pd->refill_key = &arg;
153 pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */
154 pd->moved = 0; /* This now counts the open type size in bits */
155
Lev Walkin55fdd992007-06-29 11:25:49 +0000156 asn_debug_indent += 4;
Lev Walkin375f0e92007-06-29 02:28:50 +0000157 rv = td->uper_decoder(ctx, td, constraints, sptr, pd);
Lev Walkin55fdd992007-06-29 11:25:49 +0000158 asn_debug_indent -= 4;
Lev Walkin9218bc12007-06-27 04:09:37 +0000159
Lev Walkin375f0e92007-06-29 02:28:50 +0000160#define UPDRESTOREPD do { \
161 /* buffer and nboff are valid, preserve them. */ \
162 pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \
163 pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \
164 pd->refill = arg.oldpd.refill; \
165 pd->refill_key = arg.oldpd.refill_key; \
166 } while(0)
167
168 if(rv.code != RC_OK) {
169 UPDRESTOREPD;
170 return rv;
171 }
172
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700173 ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name,
Lev Walkin375f0e92007-06-29 02:28:50 +0000174 per_data_string(pd),
175 per_data_string(&arg.oldpd),
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700176 (int)arg.unclaimed, (int)arg.repeat);
Lev Walkin9218bc12007-06-27 04:09:37 +0000177
Lev Walkin9218bc12007-06-27 04:09:37 +0000178 padding = pd->moved % 8;
179 if(padding) {
180 int32_t pvalue;
181 if(padding > 7) {
182 ASN_DEBUG("Too large padding %d in open type",
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700183 (int)padding);
Lev Walkin9218bc12007-06-27 04:09:37 +0000184 rv.code = RC_FAIL;
Lev Walkin375f0e92007-06-29 02:28:50 +0000185 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000186 return rv;
187 }
188 padding = 8 - padding;
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700189 ASN_DEBUG("Getting padding of %d bits", (int)padding);
Lev Walkin9218bc12007-06-27 04:09:37 +0000190 pvalue = per_get_few_bits(pd, padding);
191 switch(pvalue) {
192 case -1:
193 ASN_DEBUG("Padding skip failed");
Lev Walkin375f0e92007-06-29 02:28:50 +0000194 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000195 _ASN_DECODE_STARVED;
196 case 0: break;
197 default:
198 ASN_DEBUG("Non-blank padding (%d bits 0x%02x)",
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700199 (int)padding, (int)pvalue);
Lev Walkin375f0e92007-06-29 02:28:50 +0000200 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000201 _ASN_DECODE_FAILED;
202 }
203 }
Lev Walkin375f0e92007-06-29 02:28:50 +0000204 if(pd->nboff != pd->nbits) {
205 ASN_DEBUG("Open type %s overhead pd%s old%s", td->name,
206 per_data_string(pd), per_data_string(&arg.oldpd));
207 if(1) {
208 UPDRESTOREPD;
209 _ASN_DECODE_FAILED;
210 } else {
211 arg.unclaimed += pd->nbits - pd->nboff;
212 }
Lev Walkin9218bc12007-06-27 04:09:37 +0000213 }
214
215 /* Adjust pd back so it points to original data */
Lev Walkin375f0e92007-06-29 02:28:50 +0000216 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000217
218 /* Skip data not consumed by the decoder */
Lev Walkin375f0e92007-06-29 02:28:50 +0000219 if(arg.unclaimed) {
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700220 ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed);
Lev Walkin375f0e92007-06-29 02:28:50 +0000221 switch(per_skip_bits(pd, arg.unclaimed)) {
Lev Walkin9218bc12007-06-27 04:09:37 +0000222 case -1:
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700223 ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed);
Lev Walkin9218bc12007-06-27 04:09:37 +0000224 _ASN_DECODE_STARVED;
225 case 0:
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700226 ASN_DEBUG("Got claim of %d", (int)arg.unclaimed);
Lev Walkin375f0e92007-06-29 02:28:50 +0000227 break;
Lev Walkin9218bc12007-06-27 04:09:37 +0000228 default:
229 /* Padding must be blank */
230 ASN_DEBUG("Non-blank unconsumed padding");
231 _ASN_DECODE_FAILED;
232 }
Lev Walkin375f0e92007-06-29 02:28:50 +0000233 arg.unclaimed = 0;
Lev Walkin9218bc12007-06-27 04:09:37 +0000234 }
235
Lev Walkin9218bc12007-06-27 04:09:37 +0000236 if(arg.repeat) {
237 ASN_DEBUG("Not consumed the whole thing");
238 rv.code = RC_FAIL;
239 return rv;
240 }
241
242 return rv;
243}
244
Lev Walkin375f0e92007-06-29 02:28:50 +0000245
246asn_dec_rval_t
247uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
248 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
249
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700250 return uper_open_type_get_simple(ctx, td, constraints, sptr, pd);
Lev Walkin375f0e92007-06-29 02:28:50 +0000251}
252
Lev Walkin9218bc12007-06-27 04:09:37 +0000253int
Lev Walkin375f0e92007-06-29 02:28:50 +0000254uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) {
Lev Walkin9218bc12007-06-27 04:09:37 +0000255 asn_TYPE_descriptor_t s_td;
256 asn_dec_rval_t rv;
257
258 s_td.name = "<unknown extension>";
259 s_td.uper_decoder = uper_sot_suck;
260
Lev Walkin375f0e92007-06-29 02:28:50 +0000261 rv = uper_open_type_get(ctx, &s_td, 0, 0, pd);
Lev Walkin9218bc12007-06-27 04:09:37 +0000262 if(rv.code != RC_OK)
263 return -1;
264 else
265 return 0;
266}
267
268/*
269 * Internal functions.
270 */
271
272static asn_dec_rval_t
Lev Walkin375f0e92007-06-29 02:28:50 +0000273uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
Lev Walkin9218bc12007-06-27 04:09:37 +0000274 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
275 asn_dec_rval_t rv;
276
Lev Walkin375f0e92007-06-29 02:28:50 +0000277 (void)ctx;
Lev Walkin9218bc12007-06-27 04:09:37 +0000278 (void)td;
279 (void)constraints;
280 (void)sptr;
281
282 while(per_get_few_bits(pd, 24) >= 0);
283
284 rv.code = RC_OK;
285 rv.consumed = pd->moved;
286
287 return rv;
288}
289
290static int
291uper_ugot_refill(asn_per_data_t *pd) {
292 uper_ugot_key *arg = pd->refill_key;
293 ssize_t next_chunk_bytes, next_chunk_bits;
294 ssize_t avail;
295
296 asn_per_data_t *oldpd = &arg->oldpd;
297
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700298 ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld",
299 (long)pd->moved, (long)oldpd->moved);
Lev Walkin9218bc12007-06-27 04:09:37 +0000300
301 /* Advance our position to where pd is */
302 oldpd->buffer = pd->buffer;
303 oldpd->nboff = pd->nboff;
304 oldpd->nbits -= pd->moved - arg->ot_moved;
305 oldpd->moved += pd->moved - arg->ot_moved;
306 arg->ot_moved = pd->moved;
307
308 if(arg->unclaimed) {
309 /* Refill the container */
310 if(per_get_few_bits(oldpd, 1))
311 return -1;
312 if(oldpd->nboff == 0) {
313 assert(0);
314 return -1;
315 }
316 pd->buffer = oldpd->buffer;
317 pd->nboff = oldpd->nboff - 1;
318 pd->nbits = oldpd->nbits;
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700319 ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)",
320 (long)pd->moved);
Lev Walkin9218bc12007-06-27 04:09:37 +0000321 return 0;
322 }
323
324 if(!arg->repeat) {
325 ASN_DEBUG("Want more but refill doesn't have it");
326 return -1;
327 }
328
329 next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat);
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700330 ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld",
331 (long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat);
Lev Walkin9218bc12007-06-27 04:09:37 +0000332 if(next_chunk_bytes < 0) return -1;
333 if(next_chunk_bytes == 0) {
334 pd->refill = 0; /* No more refills, naturally */
335 assert(!arg->repeat); /* Implementation guarantee */
336 }
337 next_chunk_bits = next_chunk_bytes << 3;
338 avail = oldpd->nbits - oldpd->nboff;
339 if(avail >= next_chunk_bits) {
340 pd->nbits = oldpd->nboff + next_chunk_bits;
341 arg->unclaimed = 0;
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700342 ASN_DEBUG("!+Parent frame %ld bits, alloting %ld [%ld..%ld] (%ld)",
343 (long)next_chunk_bits, (long)oldpd->moved,
344 (long)oldpd->nboff, (long)oldpd->nbits,
345 (long)(oldpd->nbits - oldpd->nboff));
Lev Walkin9218bc12007-06-27 04:09:37 +0000346 } else {
347 pd->nbits = oldpd->nbits;
348 arg->unclaimed = next_chunk_bits - avail;
Lev Walkinfe1ffaf2010-10-25 21:07:59 -0700349 ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld",
350 (long)avail, (long)next_chunk_bits,
351 (long)arg->unclaimed);
Lev Walkin9218bc12007-06-27 04:09:37 +0000352 }
353 pd->buffer = oldpd->buffer;
354 pd->nboff = oldpd->nboff;
Lev Walkin375f0e92007-06-29 02:28:50 +0000355 ASN_DEBUG("Refilled pd%s old%s",
356 per_data_string(pd), per_data_string(oldpd));
Lev Walkin9218bc12007-06-27 04:09:37 +0000357 return 0;
358}
Lev Walkin375f0e92007-06-29 02:28:50 +0000359
360static int
361per_skip_bits(asn_per_data_t *pd, int skip_nbits) {
362 int hasNonZeroBits = 0;
363 while(skip_nbits > 0) {
364 int skip;
365 if(skip_nbits < skip)
366 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}