--- /dev/null
+/*\r
+ * Copyright (c) 2007 Lev Walkin <vlm@lionet.info>. All rights reserved.\r
+ * Redistribution and modifications are permitted subject to BSD license.\r
+ */\r
+#include <asn_internal.h>\r
+#include <per_support.h>\r
+#include <constr_TYPE.h>\r
+#include <per_opentype.h>\r
+\r
+typedef struct uper_ugot_key {\r
+ asn_per_data_t oldpd; /* Old per data source */\r
+ size_t unclaimed;\r
+ size_t ot_moved; /* Number of bits moved by OT processing */\r
+ int repeat;\r
+} uper_ugot_key;\r
+\r
+static int uper_ugot_refill(asn_per_data_t *pd);\r
+static int per_skip_bits(asn_per_data_t *pd, int skip_nbits);\r
+static asn_dec_rval_t uper_sot_suck(const asn_codec_ctx_t *,\r
+ const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints,\r
+ void **sptr, asn_per_data_t *pd);\r
+\r
+/*\r
+ * Encode an "open type field".\r
+ * #10.1, #10.2\r
+ */\r
+int\r
+uper_open_type_put(const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints, const void *sptr,\r
+ asn_per_outp_t *po) {\r
+ void *buf;\r
+ void *bptr;\r
+ ssize_t size;\r
+\r
+ ASN_DEBUG("Open type put %s ...", td->name);\r
+\r
+ size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);\r
+ if(size <= 0) return -1;\r
+\r
+ ASN_DEBUG("Open type put %s of length %" ASN_PRI_SSIZE " + overhead (1byte?)", td->name,\r
+ size);\r
+\r
+ bptr = buf;\r
+ do {\r
+ int need_eom = 0;\r
+ ssize_t may_save = uper_put_length(po, size, &need_eom);\r
+ ASN_DEBUG("Prepending length %" ASN_PRI_SSIZE\r
+ " to %s and allowing to save %" ASN_PRI_SSIZE,\r
+ size, td->name, may_save);\r
+ if(may_save < 0) break;\r
+ if(per_put_many_bits(po, bptr, may_save * 8)) break;\r
+ bptr = (char *)bptr + may_save;\r
+ size -= may_save;\r
+ if(need_eom && uper_put_length(po, 0, 0)) {\r
+ FREEMEM(buf);\r
+ return -1;\r
+ }\r
+ } while(size);\r
+\r
+ FREEMEM(buf);\r
+ if(size) return -1;\r
+\r
+ return 0;\r
+}\r
+\r
+static asn_dec_rval_t\r
+uper_open_type_get_simple(const asn_codec_ctx_t *ctx,\r
+ const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints, void **sptr,\r
+ asn_per_data_t *pd) {\r
+ asn_dec_rval_t rv;\r
+ ssize_t chunk_bytes;\r
+ int repeat;\r
+ uint8_t *buf = 0;\r
+ size_t bufLen = 0;\r
+ size_t bufSize = 0;\r
+ asn_per_data_t spd;\r
+ size_t padding;\r
+\r
+ ASN__STACK_OVERFLOW_CHECK(ctx);\r
+\r
+ ASN_DEBUG("Getting open type %s...", td->name);\r
+\r
+ do {\r
+ chunk_bytes = uper_get_length(pd, -1, 0, &repeat);\r
+ if(chunk_bytes < 0) {\r
+ FREEMEM(buf);\r
+ ASN__DECODE_STARVED;\r
+ }\r
+ if(bufLen + chunk_bytes > bufSize) {\r
+ void *ptr;\r
+ bufSize = chunk_bytes + (bufSize << 2);\r
+ ptr = REALLOC(buf, bufSize);\r
+ if(!ptr) {\r
+ FREEMEM(buf);\r
+ ASN__DECODE_FAILED;\r
+ }\r
+ buf = ptr;\r
+ }\r
+ if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) {\r
+ FREEMEM(buf);\r
+ ASN__DECODE_STARVED;\r
+ }\r
+ bufLen += chunk_bytes;\r
+ } while(repeat);\r
+\r
+ ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name,\r
+ (long)bufLen);\r
+\r
+ memset(&spd, 0, sizeof(spd));\r
+ spd.buffer = buf;\r
+ spd.nbits = bufLen << 3;\r
+\r
+ ASN_DEBUG_INDENT_ADD(+4);\r
+ rv = td->op->uper_decoder(ctx, td, constraints, sptr, &spd);\r
+ ASN_DEBUG_INDENT_ADD(-4);\r
+\r
+ if(rv.code == RC_OK) {\r
+ /* Check padding validity */\r
+ padding = spd.nbits - spd.nboff;\r
+ if (((padding > 0 && padding < 8) ||\r
+ /* X.691#10.1.3 */\r
+ (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) &&\r
+ per_get_few_bits(&spd, padding) == 0) {\r
+ /* Everything is cool */\r
+ FREEMEM(buf);\r
+ return rv;\r
+ }\r
+ FREEMEM(buf);\r
+ if(padding >= 8) {\r
+ ASN_DEBUG("Too large padding %d in open type", (int)padding);\r
+ ASN__DECODE_FAILED;\r
+ } else {\r
+ ASN_DEBUG("No padding");\r
+ }\r
+ } else {\r
+ FREEMEM(buf);\r
+ /* rv.code could be RC_WMORE, nonsense in this context */\r
+ rv.code = RC_FAIL; /* Noone would give us more */\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+static asn_dec_rval_t CC_NOTUSED\r
+uper_open_type_get_complex(const asn_codec_ctx_t *ctx,\r
+ const asn_TYPE_descriptor_t *td,\r
+ asn_per_constraints_t *constraints, void **sptr,\r
+ asn_per_data_t *pd) {\r
+ uper_ugot_key arg;\r
+ asn_dec_rval_t rv;\r
+ ssize_t padding;\r
+\r
+ ASN__STACK_OVERFLOW_CHECK(ctx);\r
+\r
+ ASN_DEBUG("Getting open type %s from %s", td->name,\r
+ asn_bit_data_string(pd));\r
+ arg.oldpd = *pd;\r
+ arg.unclaimed = 0;\r
+ arg.ot_moved = 0;\r
+ arg.repeat = 1;\r
+ pd->refill = uper_ugot_refill;\r
+ pd->refill_key = &arg;\r
+ pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */\r
+ pd->moved = 0; /* This now counts the open type size in bits */\r
+\r
+ ASN_DEBUG_INDENT_ADD(+4);\r
+ rv = td->op->uper_decoder(ctx, td, constraints, sptr, pd);\r
+ ASN_DEBUG_INDENT_ADD(-4);\r
+\r
+#define UPDRESTOREPD do { \\r
+ /* buffer and nboff are valid, preserve them. */ \\r
+ pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \\r
+ pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \\r
+ pd->refill = arg.oldpd.refill; \\r
+ pd->refill_key = arg.oldpd.refill_key; \\r
+ } while(0)\r
+\r
+ if(rv.code != RC_OK) {\r
+ UPDRESTOREPD;\r
+ return rv;\r
+ }\r
+\r
+ ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name,\r
+ asn_bit_data_string(pd),\r
+ asn_bit_data_string(&arg.oldpd),\r
+ (int)arg.unclaimed, (int)arg.repeat);\r
+\r
+ padding = pd->moved % 8;\r
+ if(padding) {\r
+ int32_t pvalue;\r
+ if(padding > 7) {\r
+ ASN_DEBUG("Too large padding %d in open type",\r
+ (int)padding);\r
+ rv.code = RC_FAIL;\r
+ UPDRESTOREPD;\r
+ return rv;\r
+ }\r
+ padding = 8 - padding;\r
+ ASN_DEBUG("Getting padding of %d bits", (int)padding);\r
+ pvalue = per_get_few_bits(pd, padding);\r
+ switch(pvalue) {\r
+ case -1:\r
+ ASN_DEBUG("Padding skip failed");\r
+ UPDRESTOREPD;\r
+ ASN__DECODE_STARVED;\r
+ case 0: break;\r
+ default:\r
+ ASN_DEBUG("Non-blank padding (%d bits 0x%02x)",\r
+ (int)padding, (int)pvalue);\r
+ UPDRESTOREPD;\r
+ ASN__DECODE_FAILED;\r
+ }\r
+ }\r
+ if(pd->nboff != pd->nbits) {\r
+ ASN_DEBUG("Open type %s overhead pd%s old%s", td->name,\r
+ asn_bit_data_string(pd), asn_bit_data_string(&arg.oldpd));\r
+ if(1) {\r
+ UPDRESTOREPD;\r
+ ASN__DECODE_FAILED;\r
+ } else {\r
+ arg.unclaimed += pd->nbits - pd->nboff;\r
+ }\r
+ }\r
+\r
+ /* Adjust pd back so it points to original data */\r
+ UPDRESTOREPD;\r
+\r
+ /* Skip data not consumed by the decoder */\r
+ if(arg.unclaimed) {\r
+ ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed);\r
+ switch(per_skip_bits(pd, arg.unclaimed)) {\r
+ case -1:\r
+ ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed);\r
+ ASN__DECODE_STARVED;\r
+ case 0:\r
+ ASN_DEBUG("Got claim of %d", (int)arg.unclaimed);\r
+ break;\r
+ default:\r
+ /* Padding must be blank */\r
+ ASN_DEBUG("Non-blank unconsumed padding");\r
+ ASN__DECODE_FAILED;\r
+ }\r
+ arg.unclaimed = 0;\r
+ }\r
+\r
+ if(arg.repeat) {\r
+ ASN_DEBUG("Not consumed the whole thing");\r
+ rv.code = RC_FAIL;\r
+ return rv;\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+\r
+asn_dec_rval_t\r
+uper_open_type_get(const asn_codec_ctx_t *ctx, const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints, void **sptr,\r
+ asn_per_data_t *pd) {\r
+ return uper_open_type_get_simple(ctx, td, constraints, sptr, pd);\r
+}\r
+\r
+int\r
+uper_open_type_skip(const asn_codec_ctx_t *ctx, asn_per_data_t *pd) {\r
+ asn_TYPE_descriptor_t s_td;\r
+ asn_TYPE_operation_t s_op;\r
+ asn_dec_rval_t rv;\r
+\r
+ s_td.name = "<unknown extension>";\r
+ s_td.op = &s_op;\r
+ s_op.uper_decoder = uper_sot_suck;\r
+\r
+ rv = uper_open_type_get(ctx, &s_td, 0, 0, pd);\r
+ if(rv.code != RC_OK)\r
+ return -1;\r
+ else\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * Internal functions.\r
+ */\r
+\r
+static asn_dec_rval_t\r
+uper_sot_suck(const asn_codec_ctx_t *ctx, const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints, void **sptr,\r
+ asn_per_data_t *pd) {\r
+ asn_dec_rval_t rv;\r
+\r
+ (void)ctx;\r
+ (void)td;\r
+ (void)constraints;\r
+ (void)sptr;\r
+\r
+ while(per_get_few_bits(pd, 1) >= 0);\r
+\r
+ rv.code = RC_OK;\r
+ rv.consumed = pd->moved;\r
+\r
+ return rv;\r
+}\r
+\r
+static int\r
+uper_ugot_refill(asn_per_data_t *pd) {\r
+ uper_ugot_key *arg = pd->refill_key;\r
+ ssize_t next_chunk_bytes, next_chunk_bits;\r
+ ssize_t avail;\r
+\r
+ asn_per_data_t *oldpd = &arg->oldpd;\r
+\r
+ ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld",\r
+ (long)pd->moved, (long)oldpd->moved);\r
+\r
+ /* Advance our position to where pd is */\r
+ oldpd->buffer = pd->buffer;\r
+ oldpd->nboff = pd->nboff;\r
+ oldpd->nbits -= pd->moved - arg->ot_moved;\r
+ oldpd->moved += pd->moved - arg->ot_moved;\r
+ arg->ot_moved = pd->moved;\r
+\r
+ if(arg->unclaimed) {\r
+ /* Refill the container */\r
+ if(per_get_few_bits(oldpd, 1))\r
+ return -1;\r
+ if(oldpd->nboff == 0) {\r
+ assert(0);\r
+ return -1;\r
+ }\r
+ pd->buffer = oldpd->buffer;\r
+ pd->nboff = oldpd->nboff - 1;\r
+ pd->nbits = oldpd->nbits;\r
+ ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)",\r
+ (long)pd->moved);\r
+ return 0;\r
+ }\r
+\r
+ if(!arg->repeat) {\r
+ ASN_DEBUG("Want more but refill doesn't have it");\r
+ return -1;\r
+ }\r
+\r
+ next_chunk_bytes = uper_get_length(oldpd, -1, 0, &arg->repeat);\r
+ ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld",\r
+ (long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat);\r
+ if(next_chunk_bytes < 0) return -1;\r
+ if(next_chunk_bytes == 0) {\r
+ pd->refill = 0; /* No more refills, naturally */\r
+ assert(!arg->repeat); /* Implementation guarantee */\r
+ }\r
+ next_chunk_bits = next_chunk_bytes << 3;\r
+ avail = oldpd->nbits - oldpd->nboff;\r
+ if(avail >= next_chunk_bits) {\r
+ pd->nbits = oldpd->nboff + next_chunk_bits;\r
+ arg->unclaimed = 0;\r
+ ASN_DEBUG("!+Parent frame %ld bits, alloting %ld [%ld..%ld] (%ld)",\r
+ (long)next_chunk_bits, (long)oldpd->moved,\r
+ (long)oldpd->nboff, (long)oldpd->nbits,\r
+ (long)(oldpd->nbits - oldpd->nboff));\r
+ } else {\r
+ pd->nbits = oldpd->nbits;\r
+ arg->unclaimed = next_chunk_bits - avail;\r
+ ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld",\r
+ (long)avail, (long)next_chunk_bits,\r
+ (long)arg->unclaimed);\r
+ }\r
+ pd->buffer = oldpd->buffer;\r
+ pd->nboff = oldpd->nboff;\r
+ ASN_DEBUG("Refilled pd%s old%s",\r
+ asn_bit_data_string(pd), asn_bit_data_string(oldpd));\r
+ return 0;\r
+}\r
+\r
+static int\r
+per_skip_bits(asn_per_data_t *pd, int skip_nbits) {\r
+ int hasNonZeroBits = 0;\r
+ while(skip_nbits > 0) {\r
+ int skip;\r
+\r
+ /* per_get_few_bits() is more efficient when nbits <= 24 */\r
+ if(skip_nbits < 24)\r
+ skip = skip_nbits;\r
+ else\r
+ skip = 24;\r
+ skip_nbits -= skip;\r
+\r
+ switch(per_get_few_bits(pd, skip)) {\r
+ case -1: return -1; /* Starving */\r
+ case 0: continue; /* Skipped empty space */\r
+ default: hasNonZeroBits = 1; continue;\r
+ }\r
+ }\r
+ return hasNonZeroBits;\r
+}\r
+\r
+static asn_dec_rval_t\r
+aper_open_type_get_simple(const asn_codec_ctx_t *ctx,\r
+ const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {\r
+ asn_dec_rval_t rv;\r
+ ssize_t chunk_bytes;\r
+ int repeat;\r
+ uint8_t *buf = 0;\r
+ size_t bufLen = 0;\r
+ size_t bufSize = 0;\r
+ asn_per_data_t spd;\r
+ size_t padding;\r
+\r
+ ASN__STACK_OVERFLOW_CHECK(ctx);\r
+\r
+ ASN_DEBUG("Getting open type %s...", td->name);\r
+\r
+ do {\r
+ chunk_bytes = aper_get_length(pd, -1, -1, &repeat);\r
+ if(chunk_bytes < 0) {\r
+ FREEMEM(buf);\r
+ ASN__DECODE_STARVED;\r
+ }\r
+ if(bufLen + chunk_bytes > bufSize) {\r
+ void *ptr;\r
+ bufSize = chunk_bytes + (bufSize << 2);\r
+ ptr = REALLOC(buf, bufSize);\r
+ if(!ptr) {\r
+ FREEMEM(buf);\r
+ ASN__DECODE_FAILED;\r
+ }\r
+ buf = ptr;\r
+ }\r
+ if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) {\r
+ FREEMEM(buf);\r
+ ASN__DECODE_STARVED;\r
+ }\r
+ bufLen += chunk_bytes;\r
+ } while(repeat);\r
+\r
+ ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name,\r
+ (long)bufLen);\r
+\r
+ memset(&spd, 0, sizeof(spd));\r
+ spd.buffer = buf;\r
+ spd.nbits = bufLen << 3;\r
+\r
+ ASN_DEBUG_INDENT_ADD(+4);\r
+ rv = td->op->aper_decoder(ctx, td, constraints, sptr, &spd);\r
+ ASN_DEBUG_INDENT_ADD(-4);\r
+\r
+ if(rv.code == RC_OK) {\r
+ /* Check padding validity */\r
+ padding = spd.nbits - spd.nboff;\r
+ if (((padding > 0 && padding < 8) ||\r
+ /* X.691#10.1.3 */\r
+ (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) &&\r
+ per_get_few_bits(&spd, padding) == 0) {\r
+ /* Everything is cool */\r
+ FREEMEM(buf);\r
+ return rv;\r
+ }\r
+ FREEMEM(buf);\r
+ if(padding >= 8) {\r
+ ASN_DEBUG("Too large padding %d in open type", (int)padding);\r
+ ASN__DECODE_FAILED;\r
+ } else {\r
+ ASN_DEBUG("No padding");\r
+ }\r
+ } else {\r
+ FREEMEM(buf);\r
+ /* rv.code could be RC_WMORE, nonsense in this context */\r
+ rv.code = RC_FAIL; /* Noone would give us more */\r
+ }\r
+\r
+ return rv;\r
+}\r
+\r
+int\r
+aper_open_type_put(const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints,\r
+ const void *sptr, asn_per_outp_t *po) {\r
+ void *buf;\r
+ void *bptr;\r
+ ssize_t size;\r
+ size_t toGo;\r
+\r
+ ASN_DEBUG("Open type put %s ...", td->name);\r
+\r
+ size = aper_encode_to_new_buffer(td, constraints, sptr, &buf);\r
+ if(size <= 0) return -1;\r
+\r
+ for(bptr = buf, toGo = size; toGo;) {\r
+ ssize_t maySave = aper_put_length(po, -1, toGo);\r
+ if(maySave < 0) break;\r
+ if(per_put_many_bits(po, bptr, maySave * 8)) break;\r
+ bptr = (char *)bptr + maySave;\r
+ toGo -= maySave;\r
+ }\r
+\r
+ FREEMEM(buf);\r
+ if(toGo) return -1;\r
+\r
+ ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)",\r
+ td->name, size);\r
+\r
+ return 0;\r
+}\r
+\r
+asn_dec_rval_t\r
+aper_open_type_get(const asn_codec_ctx_t *ctx,\r
+ const asn_TYPE_descriptor_t *td,\r
+ const asn_per_constraints_t *constraints,\r
+ void **sptr, asn_per_data_t *pd) {\r
+\r
+ return aper_open_type_get_simple(ctx, td, constraints, sptr, pd);\r
+}\r
+\r
+int\r
+aper_open_type_skip(const asn_codec_ctx_t *ctx, asn_per_data_t *pd) {\r
+ asn_TYPE_descriptor_t s_td;\r
+ asn_dec_rval_t rv;\r
+ asn_TYPE_operation_t op_t;\r
+\r
+ memset(&op_t, 0, sizeof(op_t));\r
+ s_td.name = "<unknown extension>";\r
+ s_td.op = &op_t;\r
+ s_td.op->aper_decoder = uper_sot_suck;\r
+\r
+ rv = aper_open_type_get(ctx, &s_td, 0, 0, pd);\r
+ if(rv.code != RC_OK)\r
+ return -1;\r
+ else\r
+ return 0;\r
+}\r
+\r
+\r