]> git.stg.codes - stg.git/blobdiff - libs/smux/OBJECT_IDENTIFIER.c
Start replacing notifiers with subscriptions.
[stg.git] / libs / smux / OBJECT_IDENTIFIER.c
index d0367f0f2abee4384c2bcbb4fe8053712bd81654..d0f8b31171213247e3551c608152c66ef4b39209 100644 (file)
@@ -3,14 +3,16 @@
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
+#include <INTEGER.h>
 #include <OBJECT_IDENTIFIER.h>
+#include <OCTET_STRING.h>
 #include <limits.h>    /* for CHAR_BIT */
 #include <errno.h>
 
 /*
  * OBJECT IDENTIFIER basic type description.
  */
-static ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = {
+static const ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = {
        (ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
 };
 asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = {
@@ -23,7 +25,8 @@ asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = {
        der_encode_primitive,
        OBJECT_IDENTIFIER_decode_xer,
        OBJECT_IDENTIFIER_encode_xer,
-       0, 0,
+       OCTET_STRING_decode_uper,
+       OCTET_STRING_encode_uper,
        0, /* Use generic outmost tag fetcher */
        asn_DEF_OBJECT_IDENTIFIER_tags,
        sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
@@ -44,14 +47,14 @@ OBJECT_IDENTIFIER_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 
        if(st && st->buf) {
                if(st->size < 1) {
-                       _ASN_CTFAIL(app_key, td,
+                       ASN__CTFAIL(app_key, td, sptr,
                                "%s: at least one numerical value "
                                "expected (%s:%d)",
                                td->name, __FILE__, __LINE__);
                        return -1;
                }
        } else {
-               _ASN_CTFAIL(app_key, td,
+               ASN__CTFAIL(app_key, td, sptr,
                        "%s: value not given (%s:%d)",
                        td->name, __FILE__, __LINE__);
                return -1;
@@ -62,9 +65,9 @@ OBJECT_IDENTIFIER_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
 
 
 int
-OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbufp, unsigned int rvsize) {
-       unsigned LE __attribute__ ((unused)) = 1; /* Little endian (x86) */
-       uint8_t *arcend = arcbuf + arclen;      /* End of arc */
+OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbufp, unsigned int rvsize) {
+       unsigned LE GCC_NOTUSED = 1; /* Little endian (x86) */
+       const uint8_t *arcend = arcbuf + arclen;        /* End of arc */
        unsigned int cache = 0; /* No more than 14 significant bits */
        unsigned char *rvbuf = (unsigned char *)rvbufp;
        unsigned char *rvstart = rvbuf; /* Original start of the value buffer */
@@ -117,7 +120,7 @@ OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed in
                        errno = ERANGE; /* Overflow */
                        return -1;
                }
-               *(unsigned long *)rvbuf = accum + add;  /* alignment OK! */
+               *(unsigned long *)(void *)rvbuf = accum + add;  /* alignment OK! */
                return 0;
        }
 
@@ -159,7 +162,7 @@ OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed in
        if(add) {
                for(rvbuf -= inc; rvbuf != rvstart; rvbuf -= inc) {
                        int v = add + *rvbuf;
-                       if(v & (-1 << CHAR_BIT)) {
+                       if(v & ((unsigned)~0 << CHAR_BIT)) {
                                *rvbuf = (unsigned char)(v + (1 << CHAR_BIT));
                                add = -1;
                        } else {
@@ -178,10 +181,11 @@ OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed in
 }
 
 ssize_t
-OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf, int arclen, int add,
+OBJECT_IDENTIFIER__dump_arc(const 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_single_arc(arcbuf, arclen, add,
                        &accum, sizeof(accum)))
@@ -189,8 +193,9 @@ OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf, int arclen, int add,
 
        if(accum) {
                ssize_t len;
-               char *p = scratch + sizeof(scratch);            /* Position in the scratch buffer */
 
+               /* Fill the scratch buffer in reverse. */
+               p = scratch + sizeof(scratch);
                for(; accum; accum /= 10)
                        *(--p) = (char)(accum % 10) + 0x30; /* Put a digit */
 
@@ -207,7 +212,7 @@ OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf, int arclen, int add,
 }
 
 int
-OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
+OBJECT_IDENTIFIER_print_arc(const uint8_t *arcbuf, int arclen, int add,
                asn_app_consume_bytes_f *cb, void *app_key) {
 
        if(OBJECT_IDENTIFIER__dump_arc(arcbuf, arclen, add, cb, app_key) < 0)
@@ -277,15 +282,13 @@ OBJECT_IDENTIFIER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const
        arcs_count = OBJECT_IDENTIFIER_parse_arcs(
                (const char *)chunk_buf, chunk_size, arcs,
                        sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr);
-       if(arcs_count <= 0) {
+       if(arcs_count < 0) {
                /* Expecting more than zero arcs */
                return XPBD_BROKEN_ENCODING;
+       } else if(arcs_count == 0) {
+               return XPBD_NOT_BODY_IGNORE;
        }
-       if(endptr < chunk_end) {
-               /* We have a tail of unrecognized data. Check its safety. */
-               if(!xer_is_whitespace(endptr, chunk_end - endptr))
-                       return XPBD_BROKEN_ENCODING;
-       }
+       assert(endptr == chunk_end);
 
        if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) {
                arcs = (long *)MALLOC(arcs_count * sizeof(long));
@@ -327,12 +330,12 @@ OBJECT_IDENTIFIER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
        (void)flags;
 
        if(!st || !st->buf)
-               _ASN_ENCODE_FAILED;
+               ASN__ENCODE_FAILED;
 
        er.encoded = OBJECT_IDENTIFIER__dump_body(st, cb, app_key);
-       if(er.encoded < 0) _ASN_ENCODE_FAILED;
+       if(er.encoded < 0) ASN__ENCODE_FAILED;
 
-       _ASN_ENCODED_OK(er);
+       ASN__ENCODED_OK(er);
 }
 
 int
@@ -357,7 +360,7 @@ OBJECT_IDENTIFIER_print(asn_TYPE_descriptor_t *td, const void *sptr,
 }
 
 int
-OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t *oid, void *arcs,
+OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *oid, void *arcs,
                unsigned int arc_type_size, unsigned int arc_slots) {
        void *arcs_end = (char *)arcs + (arc_type_size * arc_slots);
        int num_arcs = 0;
@@ -645,12 +648,12 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
        long *arcs, unsigned int arcs_slots, const char **opt_oid_text_end) {
        unsigned int arcs_count = 0;
        const char *oid_end;
-       long value = 0;
        enum {
-               ST_SKIPSPACE,
-               ST_WAITDIGITS,  /* Next character is expected to be a digit */
-               ST_DIGITS
-       } state = ST_SKIPSPACE;
+               ST_LEADSPACE,
+               ST_TAILSPACE,
+               ST_AFTERVALUE,  /* Next character ought to be '.' or a space */
+               ST_WAITDIGITS   /* Next character is expected to be a digit */
+       } state = ST_LEADSPACE;
 
        if(!oid_text || oid_txt_length < -1 || (arcs_slots && !arcs)) {
                if(opt_oid_text_end) *opt_oid_text_end = oid_text;
@@ -661,41 +664,76 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
        if(oid_txt_length == -1)
                oid_txt_length = strlen(oid_text);
 
+#define        _OID_CAPTURE_ARC(oid_text, oid_end)             do {    \
+       const char *endp = oid_end;                             \
+       long value;                                             \
+       switch(asn_strtol_lim(oid_text, &endp, &value)) {       \
+       case ASN_STRTOL_EXTRA_DATA:                             \
+       case ASN_STRTOL_OK:                                     \
+               if(arcs_count < arcs_slots)                     \
+                       arcs[arcs_count] = value;               \
+               arcs_count++;                                   \
+               oid_text = endp - 1;                            \
+               break;                                          \
+       case ASN_STRTOL_ERROR_RANGE:                            \
+               if(opt_oid_text_end)                            \
+                       *opt_oid_text_end = oid_text;           \
+               errno = ERANGE;                                 \
+               return -1;                                      \
+       case ASN_STRTOL_ERROR_INVAL:                            \
+       case ASN_STRTOL_EXPECT_MORE:                            \
+               if(opt_oid_text_end)                            \
+                       *opt_oid_text_end = oid_text;           \
+               errno = EINVAL;                                 \
+               return -1;                                      \
+       }                                                       \
+  } while(0)
+
        for(oid_end = oid_text + oid_txt_length; oid_text<oid_end; oid_text++) {
            switch(*oid_text) {
            case 0x09: case 0x0a: case 0x0d: case 0x20: /* whitespace */
-               if(state == ST_SKIPSPACE) {
+               switch(state) {
+               case ST_LEADSPACE:
+               case ST_TAILSPACE:
                        continue;
-               } else {
-                       break;  /* Finish */
+               case ST_AFTERVALUE:
+                       state = ST_TAILSPACE;
+                       continue;
+               case ST_WAITDIGITS:
+                       break;  /* Digits expected after ".", got whitespace */
                }
+               break;
            case 0x2e:  /* '.' */
-               if(state != ST_DIGITS
-               || (oid_text + 1) == oid_end) {
-                       state = ST_WAITDIGITS;
+               switch(state) {
+               case ST_LEADSPACE:
+               case ST_TAILSPACE:
+               case ST_WAITDIGITS:
+                       if(opt_oid_text_end)
+                               *opt_oid_text_end = oid_text;
+                       errno = EINVAL; /* Broken OID */
+                       return -1;
                        break;
+               case ST_AFTERVALUE:
+                       state = ST_WAITDIGITS;
+                       continue;
                }
-               if(arcs_count < arcs_slots)
-                       arcs[arcs_count] = value;
-               arcs_count++;
-               state = ST_WAITDIGITS;
-               continue;
+               break;
            case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
            case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
-               if(state != ST_DIGITS) {
-                       state = ST_DIGITS;
-                       value = 0;
-               }
-               if(1) {
-                       long new_value = value * 10;
-                       if(new_value / 10 != value
-                       || (value = new_value + (*oid_text - 0x30)) < 0) {
-                               /* Overflow */
-                               state = ST_WAITDIGITS;
-                               break;
-                       }
+               switch(state) {
+               case ST_TAILSPACE:
+               case ST_AFTERVALUE:
+                       if(opt_oid_text_end)
+                               *opt_oid_text_end = oid_text;
+                       errno = EINVAL; /* "1. 1" => broken OID */
+                       return -1;
+               case ST_LEADSPACE:
+               case ST_WAITDIGITS:
+                       _OID_CAPTURE_ARC(oid_text, oid_end);
+                       state = ST_AFTERVALUE;
                        continue;
                }
+               break;
            default:
                /* Unexpected symbols */
                state = ST_WAITDIGITS;
@@ -709,17 +747,18 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
 
        /* Finalize last arc */
        switch(state) {
+       case ST_LEADSPACE:
+               return 0; /* No OID found in input data */
        case ST_WAITDIGITS:
-               errno = EINVAL;
+               errno = EINVAL; /* Broken OID */
                return -1;
-       case ST_DIGITS:
-               if(arcs_count < arcs_slots)
-                       arcs[arcs_count] = value;
-               arcs_count++;
-               /* Fall through */
-       default:
+       case ST_AFTERVALUE:
+       case ST_TAILSPACE:
                return arcs_count;
        }
+
+       errno = EINVAL; /* Broken OID */
+       return -1;
 }