aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2007-06-24 06:26:47 +0000
committerLev Walkin <vlm@lionet.info>2007-06-24 06:26:47 +0000
commit5b78e1cbcb5dcde33578c2f1a394b3d5f1ad1d50 (patch)
tree45d7a275bf253af915d5c136c1397c28299cf20d
parentf55a6dde5441308f453f024b612ed2539d0f4ef6 (diff)
uper extensions decoding
-rw-r--r--skeletons/constr_SEQUENCE.c302
-rw-r--r--skeletons/per_decoder.c1
-rw-r--r--skeletons/per_support.c48
-rw-r--r--skeletons/per_support.h7
4 files changed, 302 insertions, 56 deletions
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index 9f870f75..5e16f574 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -1026,12 +1026,168 @@ SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
return 0;
}
+/*
+ * #10.1, #10.2
+ */
+static int
+uper_put_open_type(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
+ void *buf;
+ ssize_t size;
+
+ ASN_DEBUG("Encoding as open type %s", td->name);
+ size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
+ if(size <= 0) return -1;
+
+ ASN_DEBUG("Putting %s of length %d", td->name, size);
+ while(size) {
+ ssize_t maySave = uper_put_length(po, size);
+ if(maySave < 0) break;
+ if(per_put_many_bits(po, buf, maySave * 8)) break;
+ buf = (char *)buf + maySave;
+ size -= maySave;
+ }
+
+ if(size) {
+ FREEMEM(buf);
+ return -1;
+ }
+
+ return 0;
+}
+
+typedef struct uper_ugot_key {
+ asn_per_data_t oldpd; /* Old per data source */
+ size_t unclaimed;
+ int repeat;
+} uper_ugot_key;
+static int
+uper_ugot_refill(asn_per_data_t *pd) {
+ uper_ugot_key *arg = pd->refill_key;
+ ssize_t next_chunk_bytes, next_chunk_bits;
+ ssize_t consumed;
+ ssize_t avail;
+
+ asn_per_data_t *oldpd = &arg->oldpd;
+
+ /* Advance our position to where pd is */
+ consumed = (pd->buffer - oldpd->buffer) << 3;
+ ASN_DEBUG("Refilling [consumed: %d bits from %d (%d->%d)] now [%d (%d->%d)]",
+ consumed,
+ oldpd->nbits - oldpd->nboff, oldpd->nboff, oldpd->nbits,
+ pd->nbits - pd->nboff, pd->nboff, pd->nbits);
+ oldpd->nbits -= consumed;
+ oldpd->buffer = pd->buffer;
+ oldpd->nboff = pd->nboff;
+
+ if(arg->unclaimed) {
+ /* Refill the container */
+ if(per_get_few_bits(oldpd, 0))
+ return -1;
+ assert(0);
+ }
+
+ if(!arg->repeat) {
+ ASN_DEBUG("Want more but refill doesn't have it");
+ assert(0);
+ return -1;
+ }
+
+ next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat);
+ ASN_DEBUG("Open type length %d bytes, old %d (%d->%d)",
+ next_chunk_bytes, oldpd->nbits - oldpd->nboff, oldpd->nboff, oldpd->nbits);
+ if(next_chunk_bytes < 0) return -1;
+ if(next_chunk_bytes == 0 || !arg->repeat)
+ pd->refill = 0; /* No more refills, naturally */
+ pd->buffer = oldpd->buffer;
+ pd->nboff = oldpd->nboff;
+ pd->nbits = oldpd->nbits;
+ next_chunk_bits = next_chunk_bytes << 3;
+ avail = pd->nbits - pd->nboff;
+ if(avail >= next_chunk_bits) {
+ pd->nbits = pd->nboff + next_chunk_bits;
+ arg->unclaimed = 0;
+ } else {
+ arg->unclaimed = next_chunk_bits - avail;
+ }
+ return 0;
+}
+
+asn_dec_rval_t
+uper_get_open_type(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
+ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
+ uper_ugot_key arg;
+ asn_dec_rval_t rv;
+ ssize_t padding;
+
+ _ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx);
+
+ ASN_DEBUG("Getting open type from %d bits (%d+%d), %p", pd->nbits - pd->nboff, pd->nboff, pd->nbits, pd->buffer);
+ arg.oldpd = *pd;
+ pd->refill = uper_ugot_refill;
+ pd->refill_key = &arg;
+ pd->nbits = pd->nboff; /* 0 bits at this point, wait for refill */
+ arg.unclaimed = 0;
+ arg.repeat = 1;
+
+ rv = td->uper_decoder(opt_codec_ctx, td, constraints, sptr, pd);
+
+ /* Skip data not consumed by the decoder */
+ while(arg.unclaimed) {
+ int toget = 24;
+ if(arg.unclaimed < toget) {
+ toget = arg.unclaimed;
+ arg.unclaimed = 0;
+ } else {
+ arg.unclaimed -= toget;
+ }
+ switch(per_get_few_bits(pd, toget)) {
+ case -1: _ASN_DECODE_STARVED;
+ case 0: continue;
+ default:
+ /* Padding must be blank */
+ ASN_DEBUG("Non-blank unconsumed padding");
+ _ASN_DECODE_FAILED;
+ }
+ }
+
+ if(arg.repeat) {
+ ASN_DEBUG("Not consumed the whole thing");
+ rv.code = RC_FAIL;
+ return rv;
+ }
+
+ padding = pd->nbits - pd->nboff;
+ if(padding > 7) {
+ ASN_DEBUG("Too large padding in open type %d", padding);
+ rv.code = RC_FAIL;
+ return rv;
+ }
+
+ ASN_DEBUG("nboff = %d, nbits %d, padding = %d, plus %d/%p", pd->nboff, pd->nbits, padding, pd->buffer - arg.oldpd.buffer, arg.oldpd.buffer);
+ pd->nboff += padding;
+ assert((ssize_t)pd->nboff <= (ssize_t)pd->nbits);
+ pd->refill = arg.oldpd.refill;
+ pd->refill_key = arg.oldpd.refill_key;
+
+ return rv;
+}
+
+static int
+uper_skip_open_type(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd) {
+ asn_dec_rval_t rv;
+ rv = uper_get_open_type(opt_codec_ctx, 0, 0, 0, pd);
+ if(rv.code != RC_OK)
+ return -1;
+ else
+ return 0;
+}
+
asn_dec_rval_t
SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics;
void *st = *sptr; /* Target structure. */
- int extpresent = 0; /* Extension additions are present */
+ int extpresent; /* Extension additions are present */
uint8_t *opres; /* Presence of optional root members */
asn_per_data_t opmd;
asn_dec_rval_t rv;
@@ -1053,6 +1209,8 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
if(specs->ext_before >= 0) {
extpresent = per_get_few_bits(pd, 1);
if(extpresent < 0) _ASN_DECODE_STARVED;
+ } else {
+ extpresent = 0;
}
/* Prepare a place and read-in the presence bitmap */
@@ -1077,12 +1235,14 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
/*
* Get the sequence ROOT elements.
*/
- for(edx = 0; edx < ((specs->ext_before < 0)
- ? td->elements_count : specs->ext_before - 1); edx++) {
+ for(edx = 0; edx < td->elements_count; edx++) {
asn_TYPE_member_t *elm = &td->elements[edx];
void *memb_ptr; /* Pointer to the member */
void **memb_ptr2; /* Pointer to that pointer */
+ if(IN_EXTENSION_GROUP(specs, edx))
+ continue;
+
/* Fetch the pointer to this member */
if(elm->flags & ATF_POINTER) {
memb_ptr2 = (void **)((char *)st + elm->memb_offset);
@@ -1124,71 +1284,108 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
}
}
+ /* Optionality map is not needed anymore */
+ FREEMEM(opres);
+
/*
* Deal with extensions.
*/
if(extpresent) {
- ASN_DEBUG("Extensibility for %s: NOT IMPLEMENTED", td->name);
- _ASN_DECODE_FAILED;
- } else {
- for(edx = specs->roms_count; edx < specs->roms_count
- + specs->aoms_count; edx++) {
- asn_TYPE_member_t *elm = &td->elements[edx];
- void *memb_ptr; /* Pointer to the member */
- void **memb_ptr2; /* Pointer to that pointer */
+ ssize_t bmlength;
+ uint8_t *epres; /* Presence of extension members */
+ asn_per_data_t epmd;
- if(!elm->default_value) continue;
+ bmlength = uper_get_nslength(pd);
+ if(bmlength < 0) _ASN_DECODE_STARVED;
- /* Fetch the pointer to this member */
- if(elm->flags & ATF_POINTER) {
- memb_ptr2 = (void **)((char *)st
- + elm->memb_offset);
- } else {
- memb_ptr = (char *)st + elm->memb_offset;
- memb_ptr2 = &memb_ptr;
- }
+ ASN_DEBUG("Extensions %d present in %s", bmlength, td->name);
- /* Set default value */
- if(elm->default_value(1, memb_ptr2)) {
- FREEMEM(opres);
- _ASN_DECODE_FAILED;
- }
+ epres = (uint8_t *)MALLOC((bmlength + 15) >> 3);
+ if(!epres) _ASN_DECODE_STARVED;
+
+ /* Get the extensions map */
+ if(per_get_many_bits(pd, epres, 0, bmlength))
+ _ASN_DECODE_STARVED;
+
+ epmd.buffer = epres;
+ epmd.nboff = 0;
+ epmd.nbits = bmlength;
+ ASN_DEBUG("Read in extensions bitmap for %s of %d bits (%x..)",
+ td->name, bmlength, *epres);
+
+ /* Go over extensions and read them in */
+ for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) {
+ asn_TYPE_member_t *elm = &td->elements[edx];
+ void *memb_ptr; /* Pointer to the member */
+ void **memb_ptr2; /* Pointer to that pointer */
+ int present;
+
+ if(!IN_EXTENSION_GROUP(specs, edx)) {
+ ASN_DEBUG("%d is not extension", edx);
+ continue;
}
- }
- rv.consumed = 0;
- rv.code = RC_OK;
- FREEMEM(opres);
- return rv;
-}
+ /* Fetch the pointer to this member */
+ if(elm->flags & ATF_POINTER) {
+ memb_ptr2 = (void **)((char *)st + elm->memb_offset);
+ } else {
+ memb_ptr = (void *)((char *)st + elm->memb_offset);
+ memb_ptr2 = &memb_ptr;
+ }
-/*
- * #10.1, #10.2
- */
-static int
-uper_put_open_type(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
- void *buf;
- ssize_t size;
+ present = per_get_few_bits(&epmd, 1);
+ if(present <= 0) {
+ if(present < 0) break; /* No more extensions */
+ continue;
+ }
- ASN_DEBUG("Encoding as open type %s", td->name);
- size = uper_encode_to_new_buffer(td, constraints, sptr, &buf);
- if(size <= 0) return -1;
+ ASN_DEBUG("Decoding member %s in %s %p", elm->name, td->name, *memb_ptr2);
+ rv = uper_get_open_type(opt_codec_ctx, elm->type,
+ elm->per_constraints, memb_ptr2, pd);
+ if(rv.code != RC_OK) {
+ FREEMEM(epres);
+ return rv;
+ }
+ }
+
+ /* Skip over overflow extensions which aren't present
+ * in this system's version of the protocol */
+ while(per_get_few_bits(&epmd, 1) >= 0) {
+ if(uper_skip_open_type(opt_codec_ctx, pd)) {
+ FREEMEM(epres);
+ _ASN_DECODE_STARVED;
+ }
+ }
- ASN_DEBUG("Putting %s of length %d", td->name, size);
- while(size) {
- ssize_t maySave = uper_put_length(po, size);
- if(maySave < 0) break;
- if(per_put_many_bits(po, buf, maySave * 8)) break;
- buf = (char *)buf + maySave;
- size -= maySave;
+ FREEMEM(epres);
}
- if(size) {
- FREEMEM(buf);
- return -1;
+ /* Fill DEFAULT members in extensions */
+ for(edx = specs->roms_count; edx < specs->roms_count
+ + specs->aoms_count; edx++) {
+ asn_TYPE_member_t *elm = &td->elements[edx];
+ void **memb_ptr2; /* Pointer to member pointer */
+
+ if(!elm->default_value) continue;
+
+ /* Fetch the pointer to this member */
+ if(elm->flags & ATF_POINTER) {
+ memb_ptr2 = (void **)((char *)st
+ + elm->memb_offset);
+ if(*memb_ptr2) continue;
+ } else {
+ continue; /* Extensions are all optionals */
+ }
+
+ /* Set default value */
+ if(elm->default_value(1, memb_ptr2)) {
+ _ASN_DECODE_FAILED;
+ }
}
- return 0;
+ rv.consumed = 0;
+ rv.code = RC_OK;
+ return rv;
}
static int
@@ -1336,7 +1533,6 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td,
if(elm->default_value && elm->default_value(0, memb_ptr2) == 1)
continue;
- ASN_DEBUG("encoding root %d", edx);
er = elm->type->uper_encoder(elm->type, elm->per_constraints,
*memb_ptr2, po);
if(er.encoded == -1)
diff --git a/skeletons/per_decoder.c b/skeletons/per_decoder.c
index 16dee369..2e460da2 100644
--- a/skeletons/per_decoder.c
+++ b/skeletons/per_decoder.c
@@ -30,6 +30,7 @@ uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sp
}
/* Fill in the position indicator */
+ memset(&pd, 0, sizeof(pd));
pd.buffer = (const uint8_t *)buffer;
pd.nboff = skip_bits;
pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from <limits.h> */
diff --git a/skeletons/per_support.c b/skeletons/per_support.c
index 73e2a8dc..228fd111 100644
--- a/skeletons/per_support.c
+++ b/skeletons/per_support.c
@@ -12,14 +12,33 @@
int32_t
per_get_few_bits(asn_per_data_t *pd, int nbits) {
size_t off; /* Next after last bit offset */
+ ssize_t nleft;
uint32_t accum;
const uint8_t *buf;
- if(nbits < 0 || pd->nboff + nbits > pd->nbits)
+ if(nbits < 0)
return -1;
- ASN_DEBUG("[PER get %d bits from %p+%d bits]",
- nbits, pd->buffer, pd->nboff);
+ nleft = pd->nbits - pd->nboff;
+ if(nbits > nleft) {
+ int32_t tailv, vhead;
+ if(!pd->refill || nbits > 31) return -1;
+ /* Accumulate unused bytes before refill */
+ ASN_DEBUG("Obtain the rest %d bits", nleft);
+ tailv = per_get_few_bits(pd, nleft);
+ if(tailv < 0) return -1;
+ /* Refill (replace pd contents with new data) */
+ if(pd->refill(pd))
+ return -1;
+ nbits -= nleft;
+ vhead = per_get_few_bits(pd, nbits);
+ /* Combine the rest of previous pd with the head of new one */
+ tailv = (tailv << nbits) | vhead; /* Could == -1 */
+ return tailv;
+ }
+
+ ASN_DEBUG("[PER get %d bits from %p+%d bits, %d available]",
+ nbits, pd->buffer, pd->nboff, nleft);
/*
* Normalize position indicator.
@@ -130,6 +149,29 @@ uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) {
}
/*
+ * Get the normally small length "n".
+ * This procedure used to decode length of extensions bit-maps
+ * for SET and SEQUENCE types.
+ */
+ssize_t
+uper_get_nslength(asn_per_data_t *pd) {
+ ssize_t length;
+
+ if(per_get_few_bits(pd, 1) == 0) {
+ ASN_DEBUG("l=?");
+ length = per_get_few_bits(pd, 6);
+ ASN_DEBUG("l=%d", length);
+ if(length < 0) return -1;
+ return length + 1;
+ } else {
+ int repeat;
+ length = uper_get_length(pd, -1, &repeat);
+ if(length >= 0 && !repeat) return length;
+ return -1; /* Error, or do not support >16K extensions */
+ }
+}
+
+/*
* Get the normally small non-negative whole number.
* X.691, #10.6
*/
diff --git a/skeletons/per_support.h b/skeletons/per_support.h
index 4e7e6bda..c22bc726 100644
--- a/skeletons/per_support.h
+++ b/skeletons/per_support.h
@@ -40,6 +40,8 @@ typedef struct asn_per_data_s {
const uint8_t *buffer; /* Pointer to the octet stream */
size_t nboff; /* Bit offset to the meaningful bit */
size_t nbits; /* Number of bits in the stream */
+ int (*refill)(struct asn_per_data_s *);
+ void *refill_key;
} asn_per_data_t;
/*
@@ -65,6 +67,11 @@ ssize_t uper_get_length(asn_per_data_t *pd,
int *repeat);
/*
+ * Get the normally small length "n".
+ */
+ssize_t uper_get_nslength(asn_per_data_t *pd);
+
+/*
* Get the normally small non-negative whole number.
*/
ssize_t uper_get_nsnnwn(asn_per_data_t *pd);