]> git.stg.codes - stg.git/blob - libs/smux/per_opentype.c
Convert some tests from TUT to Boost.Test
[stg.git] / libs / smux / per_opentype.c
1 /*
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
10 typedef 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
17 static int uper_ugot_refill(asn_per_data_t *pd);
18 static int per_skip_bits(asn_per_data_t *pd, int skip_nbits);
19 static 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);
20
21 /*
22  * Encode an "open type field".
23  * #10.1, #10.2
24  */
25 int
26 uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
27         void *buf;
28         void *bptr;
29         ssize_t size;
30         size_t toGo;
31
32         ASN_DEBUG("Open type put %s ...", td->name);
33
34         size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
35         if(size <= 0) return -1;
36
37         for(bptr = buf, toGo = size; toGo;) {
38                 ssize_t maySave = uper_put_length(po, toGo);
39                 ASN_DEBUG("Prepending length %d to %s and allowing to save %d",
40                         (int)size, td->name, (int)maySave);
41                 if(maySave < 0) break;
42                 if(per_put_many_bits(po, bptr, maySave * 8)) break;
43                 bptr = (char *)bptr + maySave;
44                 toGo -= maySave;
45         }
46
47         FREEMEM(buf);
48         if(toGo) return -1;
49
50         ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)",
51                 td->name, (long)size);
52
53         return 0;
54 }
55
56 static asn_dec_rval_t
57 uper_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;
66         size_t padding;
67
68         ASN__STACK_OVERFLOW_CHECK(ctx);
69
70         ASN_DEBUG("Getting open type %s...", td->name);
71
72         do {
73                 chunk_bytes = uper_get_length(pd, -1, &repeat);
74                 if(chunk_bytes < 0) {
75                         FREEMEM(buf);
76                         ASN__DECODE_STARVED;
77                 }
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);
84                                 ASN__DECODE_FAILED;
85                         }
86                         buf = ptr;
87                 }
88                 if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) {
89                         FREEMEM(buf);
90                         ASN__DECODE_STARVED;
91                 }
92                 bufLen += chunk_bytes;
93         } while(repeat);
94
95         ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name,
96                 (long)bufLen);
97
98         memset(&spd, 0, sizeof(spd));
99         spd.buffer = buf;
100         spd.nbits = bufLen << 3;
101
102         ASN_DEBUG_INDENT_ADD(+4);
103         rv = td->uper_decoder(ctx, td, constraints, sptr, &spd);
104         ASN_DEBUG_INDENT_ADD(-4);
105
106         if(rv.code == RC_OK) {
107                 /* Check padding validity */
108                 padding = spd.nbits - spd.nboff;
109                 if ((padding < 8 ||
110                 /* X.691#10.1.3 */
111                 (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) &&
112                     per_get_few_bits(&spd, padding) == 0) {
113                         /* Everything is cool */
114                         FREEMEM(buf);
115                         return rv;
116                 }
117                 FREEMEM(buf);
118                 if(padding >= 8) {
119                         ASN_DEBUG("Too large padding %d in open type", (int)padding);
120                         ASN__DECODE_FAILED;
121                 } else {
122                         ASN_DEBUG("Non-zero padding");
123                         ASN__DECODE_FAILED;
124                 }
125         } else {
126                 FREEMEM(buf);
127                 /* rv.code could be RC_WMORE, nonsense in this context */
128                 rv.code = RC_FAIL; /* Noone would give us more */
129         }
130
131         return rv;
132 }
133
134 static asn_dec_rval_t GCC_NOTUSED
135 uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
136         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
141         ASN__STACK_OVERFLOW_CHECK(ctx);
142
143         ASN_DEBUG("Getting open type %s from %s", td->name,
144                 per_data_string(pd));
145         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
154         ASN_DEBUG_INDENT_ADD(+4);
155         rv = td->uper_decoder(ctx, td, constraints, sptr, pd);
156         ASN_DEBUG_INDENT_ADD(-4);
157
158 #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
171         ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name,
172                 per_data_string(pd),
173                 per_data_string(&arg.oldpd),
174                 (int)arg.unclaimed, (int)arg.repeat);
175
176         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",
181                                 (int)padding);
182                         rv.code = RC_FAIL;
183                         UPDRESTOREPD;
184                         return rv;
185                 }
186                 padding = 8 - padding;
187                 ASN_DEBUG("Getting padding of %d bits", (int)padding);
188                 pvalue = per_get_few_bits(pd, padding);
189                 switch(pvalue) {
190                 case -1:
191                         ASN_DEBUG("Padding skip failed");
192                         UPDRESTOREPD;
193                         ASN__DECODE_STARVED;
194                 case 0: break;
195                 default:
196                         ASN_DEBUG("Non-blank padding (%d bits 0x%02x)",
197                                 (int)padding, (int)pvalue);
198                         UPDRESTOREPD;
199                         ASN__DECODE_FAILED;
200                 }
201         }
202         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;
207                         ASN__DECODE_FAILED;
208                 } else {
209                         arg.unclaimed += pd->nbits - pd->nboff;
210                 }
211         }
212
213         /* Adjust pd back so it points to original data */
214         UPDRESTOREPD;
215
216         /* Skip data not consumed by the decoder */
217         if(arg.unclaimed) {
218                 ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed);
219                 switch(per_skip_bits(pd, arg.unclaimed)) {
220                 case -1:
221                         ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed);
222                         ASN__DECODE_STARVED;
223                 case 0:
224                         ASN_DEBUG("Got claim of %d", (int)arg.unclaimed);
225                         break;
226                 default:
227                         /* Padding must be blank */
228                         ASN_DEBUG("Non-blank unconsumed padding");
229                         ASN__DECODE_FAILED;
230                 }
231                 arg.unclaimed = 0;
232         }
233
234         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
243
244 asn_dec_rval_t
245 uper_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
248         return uper_open_type_get_simple(ctx, td, constraints, sptr, pd);
249 }
250
251 int
252 uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) {
253         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
259         rv = uper_open_type_get(ctx, &s_td, 0, 0, pd);
260         if(rv.code != RC_OK)
261                 return -1;
262         else
263                 return 0;
264 }
265
266 /*
267  * Internal functions.
268  */
269
270 static asn_dec_rval_t
271 uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td,
272         asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
273         asn_dec_rval_t rv;
274
275         (void)ctx;
276         (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
288 static int
289 uper_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
296         ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld",
297                 (long)pd->moved, (long)oldpd->moved);
298
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;
317                 ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)",
318                         (long)pd->moved);
319                 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);
328         ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld",
329                 (long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat);
330         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;
340                 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));
344         } else {
345                 pd->nbits = oldpd->nbits;
346                 arg->unclaimed = next_chunk_bits - avail;
347                 ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld",
348                         (long)avail, (long)next_chunk_bits,
349                         (long)arg->unclaimed);
350         }
351         pd->buffer = oldpd->buffer;
352         pd->nboff = oldpd->nboff;
353         ASN_DEBUG("Refilled pd%s old%s",
354                 per_data_string(pd), per_data_string(oldpd));
355         return 0;
356 }
357
358 static int
359 per_skip_bits(asn_per_data_t *pd, int skip_nbits) {
360         int hasNonZeroBits = 0;
361         while(skip_nbits > 0) {
362                 int skip;
363
364                 /* per_get_few_bits() is more efficient when nbits <= 24 */
365                 if(skip_nbits < 24)
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 }