blob: 2e5a7e11804eb480d215dc19bce5b3a3616d99ce [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 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
50 ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)",
51 td->name, 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
68 _ASN_STACK_OVERFLOW_CHECK(ctx);
69
Lev Walkin55fdd992007-06-29 11:25:49 +000070 ASN_DEBUG("Getting open type %s from %s...", td->name,
Lev Walkin375f0e92007-06-29 02:28:50 +000071 per_data_string(pd));
72
73 do {
74 chunk_bytes = uper_get_length(pd, -1, &repeat);
75 if(chunk_bytes < 0) {
76 FREEMEM(buf);
77 _ASN_DECODE_STARVED;
78 }
79 if(bufLen + chunk_bytes > bufSize) {
80 void *ptr;
81 bufSize = chunk_bytes + (bufSize << 2);
82 ptr = REALLOC(buf, bufSize);
83 if(!ptr) {
84 FREEMEM(buf);
85 _ASN_DECODE_FAILED;
86 }
87 buf = ptr;
88 }
89 if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) {
90 FREEMEM(buf);
91 _ASN_DECODE_STARVED;
92 }
93 bufLen += chunk_bytes;
94 } while(repeat);
95
Lev Walkin55fdd992007-06-29 11:25:49 +000096 ASN_DEBUG("Getting open type %s encoded in %d bytes", td->name,
97 bufLen);
98
Lev Walkin375f0e92007-06-29 02:28:50 +000099 memset(&spd, 0, sizeof(spd));
100 spd.buffer = buf;
101 spd.nbits = bufLen << 3;
102
Lev Walkin55fdd992007-06-29 11:25:49 +0000103 asn_debug_indent += 4;
Lev Walkin375f0e92007-06-29 02:28:50 +0000104 rv = td->uper_decoder(ctx, td, constraints, sptr, &spd);
Lev Walkin55fdd992007-06-29 11:25:49 +0000105 asn_debug_indent -= 4;
Lev Walkin375f0e92007-06-29 02:28:50 +0000106
107 FREEMEM(buf);
108
Lev Walkin55fdd992007-06-29 11:25:49 +0000109 /* Check padding validity */
110 padding = spd.nbits - spd.nboff;
111 if(padding >= 8) {
112 ASN_DEBUG("Too large padding %d in open type", padding);
113 _ASN_DECODE_FAILED;
114 } else if(per_get_few_bits(&spd, padding)) {
115 /* Can't be "no more data", then it's non-zero padding */
116 ASN_DEBUG("Non-zero padding");
117 _ASN_DECODE_FAILED;
118 }
119
Lev Walkin375f0e92007-06-29 02:28:50 +0000120 return rv;
121}
122
123static asn_dec_rval_t GCC_NOTUSED
124uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
Lev Walkin9218bc12007-06-27 04:09:37 +0000125 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
126 uper_ugot_key arg;
127 asn_dec_rval_t rv;
128 ssize_t padding;
129
Lev Walkin375f0e92007-06-29 02:28:50 +0000130 _ASN_STACK_OVERFLOW_CHECK(ctx);
Lev Walkin9218bc12007-06-27 04:09:37 +0000131
Lev Walkin375f0e92007-06-29 02:28:50 +0000132 ASN_DEBUG("Getting open type %s from %s", td->name,
133 per_data_string(pd));
Lev Walkin9218bc12007-06-27 04:09:37 +0000134 arg.oldpd = *pd;
135 arg.unclaimed = 0;
136 arg.ot_moved = 0;
137 arg.repeat = 1;
138 pd->refill = uper_ugot_refill;
139 pd->refill_key = &arg;
140 pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */
141 pd->moved = 0; /* This now counts the open type size in bits */
142
Lev Walkin55fdd992007-06-29 11:25:49 +0000143 asn_debug_indent += 4;
Lev Walkin375f0e92007-06-29 02:28:50 +0000144 rv = td->uper_decoder(ctx, td, constraints, sptr, pd);
Lev Walkin55fdd992007-06-29 11:25:49 +0000145 asn_debug_indent -= 4;
Lev Walkin9218bc12007-06-27 04:09:37 +0000146
Lev Walkin375f0e92007-06-29 02:28:50 +0000147#define UPDRESTOREPD do { \
148 /* buffer and nboff are valid, preserve them. */ \
149 pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \
150 pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \
151 pd->refill = arg.oldpd.refill; \
152 pd->refill_key = arg.oldpd.refill_key; \
153 } while(0)
154
155 if(rv.code != RC_OK) {
156 UPDRESTOREPD;
157 return rv;
158 }
159
160 ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d"
161 , td->name,
162 per_data_string(pd),
163 per_data_string(&arg.oldpd),
Lev Walkin9218bc12007-06-27 04:09:37 +0000164 arg.unclaimed, arg.repeat);
165
Lev Walkin9218bc12007-06-27 04:09:37 +0000166 padding = pd->moved % 8;
167 if(padding) {
168 int32_t pvalue;
169 if(padding > 7) {
170 ASN_DEBUG("Too large padding %d in open type",
171 padding);
172 rv.code = RC_FAIL;
Lev Walkin375f0e92007-06-29 02:28:50 +0000173 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000174 return rv;
175 }
176 padding = 8 - padding;
177 ASN_DEBUG("Getting padding of %d bits", padding);
178 pvalue = per_get_few_bits(pd, padding);
179 switch(pvalue) {
180 case -1:
181 ASN_DEBUG("Padding skip failed");
Lev Walkin375f0e92007-06-29 02:28:50 +0000182 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000183 _ASN_DECODE_STARVED;
184 case 0: break;
185 default:
186 ASN_DEBUG("Non-blank padding (%d bits 0x%02x)",
187 padding, pvalue);
Lev Walkin375f0e92007-06-29 02:28:50 +0000188 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000189 _ASN_DECODE_FAILED;
190 }
191 }
Lev Walkin375f0e92007-06-29 02:28:50 +0000192 if(pd->nboff != pd->nbits) {
193 ASN_DEBUG("Open type %s overhead pd%s old%s", td->name,
194 per_data_string(pd), per_data_string(&arg.oldpd));
195 if(1) {
196 UPDRESTOREPD;
197 _ASN_DECODE_FAILED;
198 } else {
199 arg.unclaimed += pd->nbits - pd->nboff;
200 }
Lev Walkin9218bc12007-06-27 04:09:37 +0000201 }
202
203 /* Adjust pd back so it points to original data */
Lev Walkin375f0e92007-06-29 02:28:50 +0000204 UPDRESTOREPD;
Lev Walkin9218bc12007-06-27 04:09:37 +0000205
206 /* Skip data not consumed by the decoder */
207 if(arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed);
Lev Walkin375f0e92007-06-29 02:28:50 +0000208 if(arg.unclaimed) {
209 switch(per_skip_bits(pd, arg.unclaimed)) {
Lev Walkin9218bc12007-06-27 04:09:37 +0000210 case -1:
Lev Walkin375f0e92007-06-29 02:28:50 +0000211 ASN_DEBUG("Claim of %d failed", arg.unclaimed);
Lev Walkin9218bc12007-06-27 04:09:37 +0000212 _ASN_DECODE_STARVED;
213 case 0:
Lev Walkin375f0e92007-06-29 02:28:50 +0000214 ASN_DEBUG("Got claim of %d", arg.unclaimed);
215 break;
Lev Walkin9218bc12007-06-27 04:09:37 +0000216 default:
217 /* Padding must be blank */
218 ASN_DEBUG("Non-blank unconsumed padding");
219 _ASN_DECODE_FAILED;
220 }
Lev Walkin375f0e92007-06-29 02:28:50 +0000221 arg.unclaimed = 0;
Lev Walkin9218bc12007-06-27 04:09:37 +0000222 }
223
Lev Walkin9218bc12007-06-27 04:09:37 +0000224 if(arg.repeat) {
225 ASN_DEBUG("Not consumed the whole thing");
226 rv.code = RC_FAIL;
227 return rv;
228 }
229
230 return rv;
231}
232
Lev Walkin375f0e92007-06-29 02:28:50 +0000233
234asn_dec_rval_t
235uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
236 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
237
238 return uper_open_type_get_simple(ctx, td, constraints,
239 sptr, pd);
240
241}
242
Lev Walkin9218bc12007-06-27 04:09:37 +0000243int
Lev Walkin375f0e92007-06-29 02:28:50 +0000244uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) {
Lev Walkin9218bc12007-06-27 04:09:37 +0000245 asn_TYPE_descriptor_t s_td;
246 asn_dec_rval_t rv;
247
248 s_td.name = "<unknown extension>";
249 s_td.uper_decoder = uper_sot_suck;
250
Lev Walkin375f0e92007-06-29 02:28:50 +0000251 rv = uper_open_type_get(ctx, &s_td, 0, 0, pd);
Lev Walkin9218bc12007-06-27 04:09:37 +0000252 if(rv.code != RC_OK)
253 return -1;
254 else
255 return 0;
256}
257
258/*
259 * Internal functions.
260 */
261
262static asn_dec_rval_t
Lev Walkin375f0e92007-06-29 02:28:50 +0000263uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
Lev Walkin9218bc12007-06-27 04:09:37 +0000264 asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
265 asn_dec_rval_t rv;
266
Lev Walkin375f0e92007-06-29 02:28:50 +0000267 (void)ctx;
Lev Walkin9218bc12007-06-27 04:09:37 +0000268 (void)td;
269 (void)constraints;
270 (void)sptr;
271
272 while(per_get_few_bits(pd, 24) >= 0);
273
274 rv.code = RC_OK;
275 rv.consumed = pd->moved;
276
277 return rv;
278}
279
280static int
281uper_ugot_refill(asn_per_data_t *pd) {
282 uper_ugot_key *arg = pd->refill_key;
283 ssize_t next_chunk_bytes, next_chunk_bits;
284 ssize_t avail;
285
286 asn_per_data_t *oldpd = &arg->oldpd;
287
Lev Walkin375f0e92007-06-29 02:28:50 +0000288 ASN_DEBUG("REFILLING pd->moved=%d, oldpd->moved=%d",
289 pd->moved, oldpd->moved);
Lev Walkin9218bc12007-06-27 04:09:37 +0000290
291 /* Advance our position to where pd is */
292 oldpd->buffer = pd->buffer;
293 oldpd->nboff = pd->nboff;
294 oldpd->nbits -= pd->moved - arg->ot_moved;
295 oldpd->moved += pd->moved - arg->ot_moved;
296 arg->ot_moved = pd->moved;
297
298 if(arg->unclaimed) {
299 /* Refill the container */
300 if(per_get_few_bits(oldpd, 1))
301 return -1;
302 if(oldpd->nboff == 0) {
303 assert(0);
304 return -1;
305 }
306 pd->buffer = oldpd->buffer;
307 pd->nboff = oldpd->nboff - 1;
308 pd->nbits = oldpd->nbits;
Lev Walkin375f0e92007-06-29 02:28:50 +0000309 ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%d)", pd->moved);
Lev Walkin9218bc12007-06-27 04:09:37 +0000310 return 0;
311 }
312
313 if(!arg->repeat) {
314 ASN_DEBUG("Want more but refill doesn't have it");
315 return -1;
316 }
317
318 next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat);
319 ASN_DEBUG("Open type LENGTH %d bytes at off %d, repeat %d",
320 next_chunk_bytes, oldpd->moved, arg->repeat);
321 if(next_chunk_bytes < 0) return -1;
322 if(next_chunk_bytes == 0) {
323 pd->refill = 0; /* No more refills, naturally */
324 assert(!arg->repeat); /* Implementation guarantee */
325 }
326 next_chunk_bits = next_chunk_bytes << 3;
327 avail = oldpd->nbits - oldpd->nboff;
328 if(avail >= next_chunk_bits) {
329 pd->nbits = oldpd->nboff + next_chunk_bits;
330 arg->unclaimed = 0;
Lev Walkin375f0e92007-06-29 02:28:50 +0000331 ASN_DEBUG("!+Parent frame %d bits, alloting %d [%d..%d] (%d)",
332 next_chunk_bits, oldpd->moved,
333 oldpd->nboff, oldpd->nbits,
334 oldpd->nbits - oldpd->nboff);
Lev Walkin9218bc12007-06-27 04:09:37 +0000335 } else {
336 pd->nbits = oldpd->nbits;
337 arg->unclaimed = next_chunk_bits - avail;
Lev Walkin375f0e92007-06-29 02:28:50 +0000338 ASN_DEBUG("!-Parent frame %d, require %d, will claim %d", avail, next_chunk_bits, arg->unclaimed);
Lev Walkin9218bc12007-06-27 04:09:37 +0000339 }
340 pd->buffer = oldpd->buffer;
341 pd->nboff = oldpd->nboff;
Lev Walkin375f0e92007-06-29 02:28:50 +0000342 ASN_DEBUG("Refilled pd%s old%s",
343 per_data_string(pd), per_data_string(oldpd));
Lev Walkin9218bc12007-06-27 04:09:37 +0000344 return 0;
345}
Lev Walkin375f0e92007-06-29 02:28:50 +0000346
347static int
348per_skip_bits(asn_per_data_t *pd, int skip_nbits) {
349 int hasNonZeroBits = 0;
350 while(skip_nbits > 0) {
351 int skip;
352 if(skip_nbits < skip)
353 skip = skip_nbits;
354 else
355 skip = 24;
356 skip_nbits -= skip;
357
358 switch(per_get_few_bits(pd, skip)) {
359 case -1: return -1; /* Starving */
360 case 0: continue; /* Skipped empty space */
361 default: hasNonZeroBits = 1; continue;
362 }
363 }
364 return hasNonZeroBits;
365}