Lev Walkin | 9218bc1 | 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); |
| 18 | static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); |
| 19 | |
| 20 | /* |
| 21 | * #10.1, #10.2 |
| 22 | */ |
| 23 | int |
| 24 | uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { |
| 25 | void *buf; |
| 26 | ssize_t size; |
| 27 | |
| 28 | ASN_DEBUG("Encoding as open type %s", td->name); |
| 29 | size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); |
| 30 | if(size <= 0) return -1; |
| 31 | |
| 32 | ASN_DEBUG("Putting %s of length %d", td->name, size); |
| 33 | while(size) { |
| 34 | ssize_t maySave = uper_put_length(po, size); |
| 35 | if(maySave < 0) break; |
| 36 | if(per_put_many_bits(po, buf, maySave * 8)) break; |
| 37 | buf = (char *)buf + maySave; |
| 38 | size -= maySave; |
| 39 | } |
| 40 | |
| 41 | if(size) { |
| 42 | FREEMEM(buf); |
| 43 | return -1; |
| 44 | } |
| 45 | |
| 46 | return 0; |
| 47 | } |
| 48 | |
| 49 | asn_dec_rval_t |
| 50 | uper_open_type_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, |
| 51 | asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { |
| 52 | uper_ugot_key arg; |
| 53 | asn_dec_rval_t rv; |
| 54 | ssize_t padding; |
| 55 | |
| 56 | _ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx); |
| 57 | |
| 58 | ASN_DEBUG("Getting open type off %d (%d+%d), %p", pd->moved, pd->nboff, pd->nbits, pd->buffer); |
| 59 | arg.oldpd = *pd; |
| 60 | arg.unclaimed = 0; |
| 61 | arg.ot_moved = 0; |
| 62 | arg.repeat = 1; |
| 63 | pd->refill = uper_ugot_refill; |
| 64 | pd->refill_key = &arg; |
| 65 | pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ |
| 66 | pd->moved = 0; /* This now counts the open type size in bits */ |
| 67 | |
| 68 | rv = td->uper_decoder(opt_codec_ctx, td, constraints, sptr, pd); |
| 69 | |
| 70 | ASN_DEBUG("Open type %s consumed %d off of %d unclaimed=%d, repeat=%d", |
| 71 | td->name, pd->moved, arg.oldpd.moved, |
| 72 | arg.unclaimed, arg.repeat); |
| 73 | |
| 74 | ASN_DEBUG("OT1 moved %d, estimated %d uncl=%d", |
| 75 | arg.oldpd.moved, |
| 76 | arg.oldpd.nboff + ((((int)arg.oldpd.buffer) & 0x7) << 3), |
| 77 | arg.unclaimed |
| 78 | ); |
| 79 | |
| 80 | padding = pd->moved % 8; |
| 81 | if(padding) { |
| 82 | int32_t pvalue; |
| 83 | if(padding > 7) { |
| 84 | ASN_DEBUG("Too large padding %d in open type", |
| 85 | padding); |
| 86 | rv.code = RC_FAIL; |
| 87 | return rv; |
| 88 | } |
| 89 | padding = 8 - padding; |
| 90 | ASN_DEBUG("Getting padding of %d bits", padding); |
| 91 | pvalue = per_get_few_bits(pd, padding); |
| 92 | switch(pvalue) { |
| 93 | case -1: |
| 94 | ASN_DEBUG("Padding skip failed"); |
| 95 | _ASN_DECODE_STARVED; |
| 96 | case 0: break; |
| 97 | default: |
| 98 | ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", |
| 99 | padding, pvalue); |
| 100 | _ASN_DECODE_FAILED; |
| 101 | } |
| 102 | } |
| 103 | if(pd->nbits != pd->nboff) { |
| 104 | ASN_DEBUG("Open type container overhead of %d bits!", pd->nbits - pd->nboff); |
| 105 | if(1) _ASN_DECODE_FAILED; |
| 106 | arg.unclaimed += pd->nbits - pd->nboff; |
| 107 | } |
| 108 | |
| 109 | /* Adjust pd back so it points to original data */ |
| 110 | pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); |
| 111 | pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); |
| 112 | pd->refill = arg.oldpd.refill; |
| 113 | pd->refill_key = arg.oldpd.refill_key; |
| 114 | |
| 115 | /* Skip data not consumed by the decoder */ |
| 116 | if(arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed); |
| 117 | while(arg.unclaimed) { |
| 118 | size_t toget = 24; |
| 119 | if(arg.unclaimed < toget) |
| 120 | toget = arg.unclaimed; |
| 121 | arg.unclaimed -= toget; |
| 122 | switch(per_get_few_bits(pd, toget)) { |
| 123 | case -1: |
| 124 | ASN_DEBUG("Claim of %d failed", toget); |
| 125 | _ASN_DECODE_STARVED; |
| 126 | case 0: |
| 127 | ASN_DEBUG("Got claim of %d", toget); |
| 128 | continue; |
| 129 | default: |
| 130 | /* Padding must be blank */ |
| 131 | ASN_DEBUG("Non-blank unconsumed padding"); |
| 132 | _ASN_DECODE_FAILED; |
| 133 | } |
| 134 | } |
| 135 | |
Lev Walkin | 3877dca | 2007-06-27 04:17:51 +0000 | [diff] [blame^] | 136 | if(0) /* Special debugging assert */ |
Lev Walkin | 9218bc1 | 2007-06-27 04:09:37 +0000 | [diff] [blame] | 137 | assert(pd->moved == pd->nboff + ((((int)pd->buffer) & 0x7) << 3)); |
| 138 | |
| 139 | if(arg.repeat) { |
| 140 | ASN_DEBUG("Not consumed the whole thing"); |
| 141 | rv.code = RC_FAIL; |
| 142 | return rv; |
| 143 | } |
| 144 | |
| 145 | return rv; |
| 146 | } |
| 147 | |
| 148 | int |
| 149 | uper_open_type_skip(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd) { |
| 150 | asn_TYPE_descriptor_t s_td; |
| 151 | asn_dec_rval_t rv; |
| 152 | |
| 153 | s_td.name = "<unknown extension>"; |
| 154 | s_td.uper_decoder = uper_sot_suck; |
| 155 | |
| 156 | rv = uper_open_type_get(opt_codec_ctx, &s_td, 0, 0, pd); |
| 157 | if(rv.code != RC_OK) |
| 158 | return -1; |
| 159 | else |
| 160 | return 0; |
| 161 | } |
| 162 | |
| 163 | /* |
| 164 | * Internal functions. |
| 165 | */ |
| 166 | |
| 167 | static asn_dec_rval_t |
| 168 | uper_sot_suck(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, |
| 169 | asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { |
| 170 | asn_dec_rval_t rv; |
| 171 | |
| 172 | (void)opt_codec_ctx; |
| 173 | (void)td; |
| 174 | (void)constraints; |
| 175 | (void)sptr; |
| 176 | |
| 177 | while(per_get_few_bits(pd, 24) >= 0); |
| 178 | |
| 179 | rv.code = RC_OK; |
| 180 | rv.consumed = pd->moved; |
| 181 | |
| 182 | return rv; |
| 183 | } |
| 184 | |
| 185 | static int |
| 186 | uper_ugot_refill(asn_per_data_t *pd) { |
| 187 | uper_ugot_key *arg = pd->refill_key; |
| 188 | ssize_t next_chunk_bytes, next_chunk_bits; |
| 189 | ssize_t avail; |
| 190 | |
| 191 | asn_per_data_t *oldpd = &arg->oldpd; |
| 192 | |
| 193 | ASN_DEBUG("REFILLING (%+db) [from %d (%d->%d)_%d] now [%d (%d->%d)_%d] uncl %d", |
| 194 | pd->buffer - oldpd->buffer, |
| 195 | oldpd->nbits - oldpd->nboff, oldpd->nboff, oldpd->nbits, oldpd->moved, |
| 196 | pd->nbits - pd->nboff, pd->nboff, pd->nbits, pd->moved, arg->unclaimed); |
| 197 | |
| 198 | /* Advance our position to where pd is */ |
| 199 | oldpd->buffer = pd->buffer; |
| 200 | oldpd->nboff = pd->nboff; |
| 201 | oldpd->nbits -= pd->moved - arg->ot_moved; |
| 202 | oldpd->moved += pd->moved - arg->ot_moved; |
| 203 | arg->ot_moved = pd->moved; |
| 204 | |
| 205 | if(arg->unclaimed) { |
| 206 | /* Refill the container */ |
| 207 | if(per_get_few_bits(oldpd, 1)) |
| 208 | return -1; |
| 209 | if(oldpd->nboff == 0) { |
| 210 | assert(0); |
| 211 | return -1; |
| 212 | } |
| 213 | pd->buffer = oldpd->buffer; |
| 214 | pd->nboff = oldpd->nboff - 1; |
| 215 | pd->nbits = oldpd->nbits; |
| 216 | ASN_DEBUG("Return from UNCLAIMED"); |
| 217 | return 0; |
| 218 | } |
| 219 | |
| 220 | if(!arg->repeat) { |
| 221 | ASN_DEBUG("Want more but refill doesn't have it"); |
| 222 | return -1; |
| 223 | } |
| 224 | |
| 225 | next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); |
| 226 | ASN_DEBUG("Open type LENGTH %d bytes at off %d, repeat %d", |
| 227 | next_chunk_bytes, oldpd->moved, arg->repeat); |
| 228 | if(next_chunk_bytes < 0) return -1; |
| 229 | if(next_chunk_bytes == 0) { |
| 230 | pd->refill = 0; /* No more refills, naturally */ |
| 231 | assert(!arg->repeat); /* Implementation guarantee */ |
| 232 | } |
| 233 | next_chunk_bits = next_chunk_bytes << 3; |
| 234 | avail = oldpd->nbits - oldpd->nboff; |
| 235 | if(avail >= next_chunk_bits) { |
| 236 | pd->nbits = oldpd->nboff + next_chunk_bits; |
| 237 | arg->unclaimed = 0; |
| 238 | } else { |
| 239 | pd->nbits = oldpd->nbits; |
| 240 | arg->unclaimed = next_chunk_bits - avail; |
| 241 | ASN_DEBUG("Parent has %d, require %d, will claim %d", avail, next_chunk_bits, arg->unclaimed); |
| 242 | } |
| 243 | pd->buffer = oldpd->buffer; |
| 244 | pd->nboff = oldpd->nboff; |
| 245 | return 0; |
| 246 | } |