Initial revision
git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@2 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
new file mode 100644
index 0000000..bcbcdca
--- /dev/null
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -0,0 +1,356 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <OBJECT_IDENTIFIER.h>
+#include <assert.h>
+#include <errno.h>
+
+/*
+ * OBJECT IDENTIFIER basic type description.
+ */
+static ber_tlv_tag_t asn1_DEF_OBJECT_IDENTIFIER_tags[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
+};
+asn1_TYPE_descriptor_t asn1_DEF_OBJECT_IDENTIFIER = {
+ "OBJECT IDENTIFIER",
+ OBJECT_IDENTIFIER_constraint,
+ INTEGER_decode_ber, /* Implemented in terms of INTEGER type */
+ OBJECT_IDENTIFIER_encode_der,
+ OBJECT_IDENTIFIER_print,
+ INTEGER_free,
+ 0, /* Use generic outmost tag fetcher */
+ asn1_DEF_OBJECT_IDENTIFIER_tags,
+ sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags)
+ / sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags[0]),
+ 1, /* Single UNIVERSAL tag may be implicitly overriden */
+ 0 /* Always in primitive form */
+};
+
+
+/*
+ * Encode OBJECT IDENTIFIER type using DER.
+ */
+der_enc_rval_t
+OBJECT_IDENTIFIER_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+ int tag_mode, ber_tlv_tag_t tag,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ der_enc_rval_t erval;
+ OBJECT_IDENTIFIER_t *st = ptr;
+
+ ASN_DEBUG("%s %s as OBJECT IDENTIFIER (tm=%d)",
+ cb?"Encoding":"Estimating", sd->name, tag_mode);
+
+ erval.encoded = der_write_tags(sd, st->size, tag_mode, tag,
+ cb, app_key);
+ ASN_DEBUG("OBJECT IDENTIFIER %s wrote tags %d",
+ sd->name, (int)erval.encoded);
+ if(erval.encoded == -1) {
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+
+ if(cb && st->buf) {
+ ssize_t ret;
+
+ ret = cb(st->buf, st->size, app_key);
+ if(ret == -1) {
+ erval.encoded = -1;
+ erval.failed_type = sd;
+ erval.structure_ptr = ptr;
+ return erval;
+ }
+ } else {
+ assert(st->buf || st->size == 0);
+ }
+
+ erval.encoded += st->size;
+
+ return erval;
+}
+
+int
+OBJECT_IDENTIFIER_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_consume_bytes_f *app_errlog, void *app_key) {
+ const OBJECT_IDENTIFIER_t *st = sptr;
+
+ if(st && st->buf) {
+ if(st->size < 1) {
+ _ASN_ERRLOG("%s: at least one numerical value expected",
+ td->name);
+ return -1;
+ }
+ } else {
+ _ASN_ERRLOG("%s: value not given", td->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+OBJECT_IDENTIFIER_get_arc_l(uint8_t *arcbuf, int arclen, int add, unsigned long *rvalue) {
+ unsigned long accum;
+ uint8_t *arcend = arcbuf + arclen;
+
+ if(arclen * 7 > 8 * sizeof(accum)) {
+ if(arclen * 7 <= 8 * (sizeof(accum) + 1)) {
+ if((*arcbuf & ~0x8f)) {
+ errno = ERANGE; /* Overflow */
+ return -1;
+ }
+ } else {
+ errno = ERANGE; /* Overflow */
+ return -1;
+ }
+ }
+
+ /* Gather all bits into the accumulator */
+ for(accum = 0; arcbuf < arcend; arcbuf++)
+ accum = (accum << 7) | (*arcbuf & ~0x80);
+
+ accum += add; /* Actually, a negative value */
+ assert(accum >= 0);
+
+ *rvalue = accum;
+
+ return 0;
+}
+
+int
+OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ char scratch[64]; /* Conservative estimate */
+ unsigned long accum; /* Bits accumulator */
+ char *p; /* Position in the scratch buffer */
+
+ if(OBJECT_IDENTIFIER_get_arc_l(arcbuf, arclen, add, &accum))
+ return -1;
+
+ /* Fill the scratch buffer in reverse. */
+ p = scratch + sizeof(scratch);
+ for(; accum; accum /= 10)
+ *(--p) = (accum % 10) + 0x30;
+
+ return cb(p, sizeof(scratch) - (p - scratch), app_key);
+}
+
+int
+OBJECT_IDENTIFIER_print(asn1_TYPE_descriptor_t *td, const void *sptr,
+ int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
+ const OBJECT_IDENTIFIER_t *st = sptr;
+ int startn;
+ int add = 0;
+ int i;
+
+ if(!st || !st->buf)
+ return cb("<absent>", 8, app_key);
+
+ /* Dump preamble */
+ if(cb("{ ", 2, app_key))
+ return -1;
+
+ for(i = 0, startn = 0; i < st->size; i++) {
+ uint8_t b = st->buf[i];
+ if((b & 0x80)) /* Continuation expected */
+ continue;
+
+ if(startn == 0) {
+ /*
+ * First two arcs are encoded through the backdoor.
+ */
+ if(i) {
+ add = -80;
+ if(cb("2", 1, app_key)) return -1;
+ } else if(b <= 39) {
+ add = 0;
+ if(cb("0", 1, app_key)) return -1;
+ } else if(b < 79) {
+ add = -40;
+ if(cb("1", 1, app_key)) return -1;
+ } else {
+ add = -80;
+ if(cb("2", 1, app_key)) return -1;
+ }
+ }
+
+ if(cb(" ", 1, app_key)) /* Separate arcs */
+ return -1;
+
+ if(OBJECT_IDENTIFIER_print_arc(&st->buf[startn],
+ i - startn + 1, add,
+ cb, app_key))
+ return -1;
+ startn = i + 1;
+ add = 0;
+ }
+
+ return cb(" }", 2, app_key);
+}
+
+int
+OBJECT_IDENTIFIER_get_arcs_l(OBJECT_IDENTIFIER_t *oid,
+ unsigned long *arcs, int arcs_slots) {
+ unsigned long arc_value;
+ int cur_arc = 0;
+ int startn = 0;
+ int add = 0;
+ int i;
+
+ if(!oid || !oid->buf) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for(i = 0; i < oid->size; i++) {
+ uint8_t b = oid->buf[i];
+ if((b & 0x80)) /* Continuation expected */
+ continue;
+
+ if(startn == 0) {
+ /*
+ * First two arcs are encoded through the backdoor.
+ */
+ if(i) {
+ add = -80;
+ if(cur_arc < arcs_slots) arcs[cur_arc] = 2;
+ cur_arc++;
+ } else if(b <= 39) {
+ add = 0;
+ if(cur_arc < arcs_slots) arcs[cur_arc] = 0;
+ cur_arc++;
+ } else if(b < 79) {
+ add = -40;
+ if(cur_arc < arcs_slots) arcs[cur_arc] = 1;
+ cur_arc++;
+ } else {
+ add = -80;
+ if(cur_arc < arcs_slots) arcs[cur_arc] = 2;
+ cur_arc++;
+ }
+ }
+
+ /* Do not fill */
+ if(cur_arc >= arcs_slots) {
+ startn = i + 1;
+ continue;
+ }
+
+ if(OBJECT_IDENTIFIER_get_arc_l(&oid->buf[startn],
+ i - startn + 1,
+ add, &arc_value))
+ return -1;
+ arcs[cur_arc++] = arc_value;
+ startn = i + 1;
+ add = 0;
+ }
+
+ return cur_arc;
+}
+
+int
+OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, int arcs_slots) {
+ uint8_t *buf;
+ uint8_t *bp;
+ unsigned long long first_value;
+ int size;
+ int i;
+
+ if(oid == NULL || arcs == NULL || arcs_slots < 2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(arcs[0] <= 1) {
+ if(arcs[1] >= 39) {
+ /* 8.19.4: At most 39 subsequent values (including 0) */
+ errno = ERANGE;
+ return -1;
+ }
+ } else if(arcs[0] > 2) {
+ /* 8.19.4: Only three values are allocated from the root node */
+ errno = ERANGE;
+ return -1;
+ }
+
+ first_value = arcs[0] * 40 + arcs[1];
+
+ /*
+ * Roughly estimate the maximum size necessary to encode these arcs.
+ */
+ size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arcs_slots;
+ bp = buf = MALLOC(size + 1);
+ if(!buf) {
+ /* ENOMEM */
+ return -1;
+ }
+
+ /*
+ * Encode the arcs and refine the encoding size.
+ */
+ size = 0;
+
+ {
+ uint8_t tbuf[sizeof(first_value) * 2];
+ uint8_t *tp = tbuf;
+ int arc_len = 0;
+ int add = 0;
+
+ for(; first_value; first_value >>= 7) {
+ unsigned int b7 = first_value & 0x7f;
+ *tp++ = 0x80 | b7;
+ add++;
+ if(b7) { arc_len += add; add = 0; }
+ }
+
+ if(arc_len) {
+ tp = &tbuf[arc_len - 1];
+ /* The last octet does not have bit 8 set. */
+ *tbuf &= 0x7f;
+ for(; tp >= tbuf; tp--)
+ *bp++ = *tp;
+ size += arc_len;
+ } else {
+ *bp++ = 0;
+ size++;
+ }
+ }
+
+ for(i = 2; i < arcs_slots; i++) {
+ unsigned long value = arcs[i];
+ uint8_t tbuf[sizeof(value) * 2]; /* Conservatively sized */
+ uint8_t *tp = tbuf;
+ int arc_len = 0;
+ int add = 0;
+
+ for(; value; value >>= 7) {
+ unsigned int b7 = value & 0x7F;
+ *tp++ = 0x80 | b7;
+ add++;
+ if(b7) { arc_len += add; add = 0; }
+ }
+
+ if(arc_len) {
+ tp = &tbuf[arc_len - 1];
+ /* The last octet does not have bit 8 set. */
+ *tbuf &= 0x7f;
+ for(; tp >= tbuf; tp--)
+ *bp++ = *tp;
+ size += arc_len;
+ } else {
+ *bp++ = 0;
+ size++;
+ }
+ }
+
+ /*
+ * Replace buffer.
+ */
+ oid->size = size;
+ bp = oid->buf;
+ oid->buf = buf;
+ if(bp) FREEMEM(bp);
+
+ return 0;
+}