vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 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); |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 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); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 20 | |
| 21 | /* |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 22 | * Encode an "open type field". |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 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; |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 28 | void *bptr; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 29 | ssize_t size; |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 30 | size_t toGo; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 31 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 32 | ASN_DEBUG("Open type put %s ...", td->name); |
| 33 | |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 34 | size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); |
| 35 | if(size <= 0) return -1; |
| 36 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 37 | for(bptr = buf, toGo = size; toGo;) { |
| 38 | ssize_t maySave = uper_put_length(po, toGo); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 39 | if(maySave < 0) break; |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 40 | if(per_put_many_bits(po, bptr, maySave * 8)) break; |
| 41 | bptr = (char *)bptr + maySave; |
| 42 | toGo -= maySave; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 43 | } |
| 44 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 45 | FREEMEM(buf); |
| 46 | if(toGo) return -1; |
| 47 | |
| 48 | ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)", |
| 49 | td->name, size); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 50 | |
| 51 | return 0; |
| 52 | } |
| 53 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 54 | static asn_dec_rval_t |
| 55 | uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, |
| 56 | asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { |
| 57 | asn_dec_rval_t rv; |
| 58 | ssize_t chunk_bytes; |
| 59 | int repeat; |
| 60 | uint8_t *buf = 0; |
| 61 | size_t bufLen = 0; |
| 62 | size_t bufSize = 0; |
| 63 | asn_per_data_t spd; |
| 64 | |
| 65 | _ASN_STACK_OVERFLOW_CHECK(ctx); |
| 66 | |
| 67 | ASN_DEBUG("Getting open type %s from %s", td->name, |
| 68 | per_data_string(pd)); |
| 69 | |
| 70 | do { |
| 71 | chunk_bytes = uper_get_length(pd, -1, &repeat); |
| 72 | if(chunk_bytes < 0) { |
| 73 | FREEMEM(buf); |
| 74 | _ASN_DECODE_STARVED; |
| 75 | } |
| 76 | if(bufLen + chunk_bytes > bufSize) { |
| 77 | void *ptr; |
| 78 | bufSize = chunk_bytes + (bufSize << 2); |
| 79 | ptr = REALLOC(buf, bufSize); |
| 80 | if(!ptr) { |
| 81 | FREEMEM(buf); |
| 82 | _ASN_DECODE_FAILED; |
| 83 | } |
| 84 | buf = ptr; |
| 85 | } |
| 86 | if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) { |
| 87 | FREEMEM(buf); |
| 88 | _ASN_DECODE_STARVED; |
| 89 | } |
| 90 | bufLen += chunk_bytes; |
| 91 | } while(repeat); |
| 92 | |
| 93 | memset(&spd, 0, sizeof(spd)); |
| 94 | spd.buffer = buf; |
| 95 | spd.nbits = bufLen << 3; |
| 96 | |
| 97 | rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); |
| 98 | |
| 99 | FREEMEM(buf); |
| 100 | |
| 101 | return rv; |
| 102 | } |
| 103 | |
| 104 | static asn_dec_rval_t GCC_NOTUSED |
| 105 | uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 106 | asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { |
| 107 | uper_ugot_key arg; |
| 108 | asn_dec_rval_t rv; |
| 109 | ssize_t padding; |
| 110 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 111 | _ASN_STACK_OVERFLOW_CHECK(ctx); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 112 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 113 | ASN_DEBUG("Getting open type %s from %s", td->name, |
| 114 | per_data_string(pd)); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 115 | arg.oldpd = *pd; |
| 116 | arg.unclaimed = 0; |
| 117 | arg.ot_moved = 0; |
| 118 | arg.repeat = 1; |
| 119 | pd->refill = uper_ugot_refill; |
| 120 | pd->refill_key = &arg; |
| 121 | pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ |
| 122 | pd->moved = 0; /* This now counts the open type size in bits */ |
| 123 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 124 | /*asn_debug_indent += 4;*/ |
| 125 | rv = td->uper_decoder(ctx, td, constraints, sptr, pd); |
| 126 | /*asn_debug_indent -= 4;*/ |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 127 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 128 | #define UPDRESTOREPD do { \ |
| 129 | /* buffer and nboff are valid, preserve them. */ \ |
| 130 | pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ |
| 131 | pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ |
| 132 | pd->refill = arg.oldpd.refill; \ |
| 133 | pd->refill_key = arg.oldpd.refill_key; \ |
| 134 | } while(0) |
| 135 | |
| 136 | if(rv.code != RC_OK) { |
| 137 | UPDRESTOREPD; |
| 138 | return rv; |
| 139 | } |
| 140 | |
| 141 | ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d" |
| 142 | , td->name, |
| 143 | per_data_string(pd), |
| 144 | per_data_string(&arg.oldpd), |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 145 | arg.unclaimed, arg.repeat); |
| 146 | |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 147 | padding = pd->moved % 8; |
| 148 | if(padding) { |
| 149 | int32_t pvalue; |
| 150 | if(padding > 7) { |
| 151 | ASN_DEBUG("Too large padding %d in open type", |
| 152 | padding); |
| 153 | rv.code = RC_FAIL; |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 154 | UPDRESTOREPD; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 155 | return rv; |
| 156 | } |
| 157 | padding = 8 - padding; |
| 158 | ASN_DEBUG("Getting padding of %d bits", padding); |
| 159 | pvalue = per_get_few_bits(pd, padding); |
| 160 | switch(pvalue) { |
| 161 | case -1: |
| 162 | ASN_DEBUG("Padding skip failed"); |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 163 | UPDRESTOREPD; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 164 | _ASN_DECODE_STARVED; |
| 165 | case 0: break; |
| 166 | default: |
| 167 | ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", |
| 168 | padding, pvalue); |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 169 | UPDRESTOREPD; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 170 | _ASN_DECODE_FAILED; |
| 171 | } |
| 172 | } |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 173 | if(pd->nboff != pd->nbits) { |
| 174 | ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, |
| 175 | per_data_string(pd), per_data_string(&arg.oldpd)); |
| 176 | if(1) { |
| 177 | UPDRESTOREPD; |
| 178 | _ASN_DECODE_FAILED; |
| 179 | } else { |
| 180 | arg.unclaimed += pd->nbits - pd->nboff; |
| 181 | } |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | /* Adjust pd back so it points to original data */ |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 185 | UPDRESTOREPD; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 186 | |
| 187 | /* Skip data not consumed by the decoder */ |
| 188 | if(arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed); |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 189 | if(arg.unclaimed) { |
| 190 | switch(per_skip_bits(pd, arg.unclaimed)) { |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 191 | case -1: |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 192 | ASN_DEBUG("Claim of %d failed", arg.unclaimed); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 193 | _ASN_DECODE_STARVED; |
| 194 | case 0: |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 195 | ASN_DEBUG("Got claim of %d", arg.unclaimed); |
| 196 | break; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 197 | default: |
| 198 | /* Padding must be blank */ |
| 199 | ASN_DEBUG("Non-blank unconsumed padding"); |
| 200 | _ASN_DECODE_FAILED; |
| 201 | } |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 202 | arg.unclaimed = 0; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 203 | } |
| 204 | |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 205 | if(arg.repeat) { |
| 206 | ASN_DEBUG("Not consumed the whole thing"); |
| 207 | rv.code = RC_FAIL; |
| 208 | return rv; |
| 209 | } |
| 210 | |
| 211 | return rv; |
| 212 | } |
| 213 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 214 | |
| 215 | asn_dec_rval_t |
| 216 | uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, |
| 217 | asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { |
| 218 | |
| 219 | return uper_open_type_get_simple(ctx, td, constraints, |
| 220 | sptr, pd); |
| 221 | |
| 222 | } |
| 223 | |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 224 | int |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 225 | uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) { |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 226 | asn_TYPE_descriptor_t s_td; |
| 227 | asn_dec_rval_t rv; |
| 228 | |
| 229 | s_td.name = "<unknown extension>"; |
| 230 | s_td.uper_decoder = uper_sot_suck; |
| 231 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 232 | rv = uper_open_type_get(ctx, &s_td, 0, 0, pd); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 233 | if(rv.code != RC_OK) |
| 234 | return -1; |
| 235 | else |
| 236 | return 0; |
| 237 | } |
| 238 | |
| 239 | /* |
| 240 | * Internal functions. |
| 241 | */ |
| 242 | |
| 243 | static asn_dec_rval_t |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 244 | uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 245 | asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { |
| 246 | asn_dec_rval_t rv; |
| 247 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 248 | (void)ctx; |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 249 | (void)td; |
| 250 | (void)constraints; |
| 251 | (void)sptr; |
| 252 | |
| 253 | while(per_get_few_bits(pd, 24) >= 0); |
| 254 | |
| 255 | rv.code = RC_OK; |
| 256 | rv.consumed = pd->moved; |
| 257 | |
| 258 | return rv; |
| 259 | } |
| 260 | |
| 261 | static int |
| 262 | uper_ugot_refill(asn_per_data_t *pd) { |
| 263 | uper_ugot_key *arg = pd->refill_key; |
| 264 | ssize_t next_chunk_bytes, next_chunk_bits; |
| 265 | ssize_t avail; |
| 266 | |
| 267 | asn_per_data_t *oldpd = &arg->oldpd; |
| 268 | |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 269 | ASN_DEBUG("REFILLING pd->moved=%d, oldpd->moved=%d", |
| 270 | pd->moved, oldpd->moved); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 271 | |
| 272 | /* Advance our position to where pd is */ |
| 273 | oldpd->buffer = pd->buffer; |
| 274 | oldpd->nboff = pd->nboff; |
| 275 | oldpd->nbits -= pd->moved - arg->ot_moved; |
| 276 | oldpd->moved += pd->moved - arg->ot_moved; |
| 277 | arg->ot_moved = pd->moved; |
| 278 | |
| 279 | if(arg->unclaimed) { |
| 280 | /* Refill the container */ |
| 281 | if(per_get_few_bits(oldpd, 1)) |
| 282 | return -1; |
| 283 | if(oldpd->nboff == 0) { |
| 284 | assert(0); |
| 285 | return -1; |
| 286 | } |
| 287 | pd->buffer = oldpd->buffer; |
| 288 | pd->nboff = oldpd->nboff - 1; |
| 289 | pd->nbits = oldpd->nbits; |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 290 | ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%d)", pd->moved); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 291 | return 0; |
| 292 | } |
| 293 | |
| 294 | if(!arg->repeat) { |
| 295 | ASN_DEBUG("Want more but refill doesn't have it"); |
| 296 | return -1; |
| 297 | } |
| 298 | |
| 299 | next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); |
| 300 | ASN_DEBUG("Open type LENGTH %d bytes at off %d, repeat %d", |
| 301 | next_chunk_bytes, oldpd->moved, arg->repeat); |
| 302 | if(next_chunk_bytes < 0) return -1; |
| 303 | if(next_chunk_bytes == 0) { |
| 304 | pd->refill = 0; /* No more refills, naturally */ |
| 305 | assert(!arg->repeat); /* Implementation guarantee */ |
| 306 | } |
| 307 | next_chunk_bits = next_chunk_bytes << 3; |
| 308 | avail = oldpd->nbits - oldpd->nboff; |
| 309 | if(avail >= next_chunk_bits) { |
| 310 | pd->nbits = oldpd->nboff + next_chunk_bits; |
| 311 | arg->unclaimed = 0; |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 312 | ASN_DEBUG("!+Parent frame %d bits, alloting %d [%d..%d] (%d)", |
| 313 | next_chunk_bits, oldpd->moved, |
| 314 | oldpd->nboff, oldpd->nbits, |
| 315 | oldpd->nbits - oldpd->nboff); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 316 | } else { |
| 317 | pd->nbits = oldpd->nbits; |
| 318 | arg->unclaimed = next_chunk_bits - avail; |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 319 | ASN_DEBUG("!-Parent frame %d, require %d, will claim %d", avail, next_chunk_bits, arg->unclaimed); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 320 | } |
| 321 | pd->buffer = oldpd->buffer; |
| 322 | pd->nboff = oldpd->nboff; |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 323 | ASN_DEBUG("Refilled pd%s old%s", |
| 324 | per_data_string(pd), per_data_string(oldpd)); |
vlm | 5d3db2f | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 325 | return 0; |
| 326 | } |
vlm | b08408b | 2007-06-29 02:28:50 +0000 | [diff] [blame^] | 327 | |
| 328 | static int |
| 329 | per_skip_bits(asn_per_data_t *pd, int skip_nbits) { |
| 330 | int hasNonZeroBits = 0; |
| 331 | while(skip_nbits > 0) { |
| 332 | int skip; |
| 333 | if(skip_nbits < skip) |
| 334 | skip = skip_nbits; |
| 335 | else |
| 336 | skip = 24; |
| 337 | skip_nbits -= skip; |
| 338 | |
| 339 | switch(per_get_few_bits(pd, skip)) { |
| 340 | case -1: return -1; /* Starving */ |
| 341 | case 0: continue; /* Skipped empty space */ |
| 342 | default: hasNonZeroBits = 1; continue; |
| 343 | } |
| 344 | } |
| 345 | return hasNonZeroBits; |
| 346 | } |