SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / OCTET_STRING_xer.c
diff --git a/e2sim/asn1c/OCTET_STRING_xer.c b/e2sim/asn1c/OCTET_STRING_xer.c
new file mode 100644 (file)
index 0000000..490f362
--- /dev/null
@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <OCTET_STRING.h>
+#include <BIT_STRING.h>  /* for .bits_unused member */
+
+asn_enc_rval_t
+OCTET_STRING_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
+                        int ilevel, enum xer_encoder_flags_e flags,
+                        asn_app_consume_bytes_f *cb, void *app_key) {
+    const char * const h2c = "0123456789ABCDEF";
+    const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
+    asn_enc_rval_t er = { 0, 0, 0 };
+    char scratch[16 * 3 + 4];
+    char *p = scratch;
+    uint8_t *buf;
+    uint8_t *end;
+    size_t i;
+
+    if(!st || (!st->buf && st->size))
+        ASN__ENCODE_FAILED;
+
+    er.encoded = 0;
+
+    /*
+     * Dump the contents of the buffer in hexadecimal.
+     */
+    buf = st->buf;
+    end = buf + st->size;
+    if(flags & XER_F_CANONICAL) {
+        char *scend = scratch + (sizeof(scratch) - 2);
+        for(; buf < end; buf++) {
+            if(p >= scend) {
+                ASN__CALLBACK(scratch, p - scratch);
+                p = scratch;
+            }
+            *p++ = h2c[(*buf >> 4) & 0x0F];
+            *p++ = h2c[*buf & 0x0F];
+        }
+
+        ASN__CALLBACK(scratch, p-scratch);  /* Dump the rest */
+    } else {
+        for(i = 0; buf < end; buf++, i++) {
+            if(!(i % 16) && (i || st->size > 16)) {
+                ASN__CALLBACK(scratch, p-scratch);
+                p = scratch;
+                ASN__TEXT_INDENT(1, ilevel);
+            }
+            *p++ = h2c[(*buf >> 4) & 0x0F];
+            *p++ = h2c[*buf & 0x0F];
+            *p++ = 0x20;
+        }
+        if(p - scratch) {
+            p--;  /* Remove the tail space */
+            ASN__CALLBACK(scratch, p-scratch);  /* Dump the rest */
+            if(st->size > 16)
+                ASN__TEXT_INDENT(1, ilevel-1);
+        }
+    }
+
+    ASN__ENCODED_OK(er);
+cb_failed:
+    ASN__ENCODE_FAILED;
+}
+
+static const struct OCTET_STRING__xer_escape_table_s {
+    const char *string;
+    int size;
+} OCTET_STRING__xer_escape_table[] = {
+#define        OSXET(s)        { s, sizeof(s) - 1 }
+    OSXET("\074\156\165\154\057\076"),  /* <nul/> */
+    OSXET("\074\163\157\150\057\076"),  /* <soh/> */
+    OSXET("\074\163\164\170\057\076"),  /* <stx/> */
+    OSXET("\074\145\164\170\057\076"),  /* <etx/> */
+    OSXET("\074\145\157\164\057\076"),  /* <eot/> */
+    OSXET("\074\145\156\161\057\076"),  /* <enq/> */
+    OSXET("\074\141\143\153\057\076"),  /* <ack/> */
+    OSXET("\074\142\145\154\057\076"),  /* <bel/> */
+    OSXET("\074\142\163\057\076"),      /* <bs/> */
+    OSXET("\011"),                      /* \t */
+    OSXET("\012"),                      /* \n */
+    OSXET("\074\166\164\057\076"),      /* <vt/> */
+    OSXET("\074\146\146\057\076"),      /* <ff/> */
+    OSXET("\015"),                      /* \r */
+    OSXET("\074\163\157\057\076"),      /* <so/> */
+    OSXET("\074\163\151\057\076"),      /* <si/> */
+    OSXET("\074\144\154\145\057\076"),  /* <dle/> */
+    OSXET("\074\144\143\061\057\076"),  /* <de1/> */
+    OSXET("\074\144\143\062\057\076"),  /* <de2/> */
+    OSXET("\074\144\143\063\057\076"),  /* <de3/> */
+    OSXET("\074\144\143\064\057\076"),  /* <de4/> */
+    OSXET("\074\156\141\153\057\076"),  /* <nak/> */
+    OSXET("\074\163\171\156\057\076"),  /* <syn/> */
+    OSXET("\074\145\164\142\057\076"),  /* <etb/> */
+    OSXET("\074\143\141\156\057\076"),  /* <can/> */
+    OSXET("\074\145\155\057\076"),      /* <em/> */
+    OSXET("\074\163\165\142\057\076"),  /* <sub/> */
+    OSXET("\074\145\163\143\057\076"),  /* <esc/> */
+    OSXET("\074\151\163\064\057\076"),  /* <is4/> */
+    OSXET("\074\151\163\063\057\076"),  /* <is3/> */
+    OSXET("\074\151\163\062\057\076"),  /* <is2/> */
+    OSXET("\074\151\163\061\057\076"),  /* <is1/> */
+    { 0, 0 },                           /* " " */
+    { 0, 0 },                           /* ! */
+    { 0, 0 },                           /* \" */
+    { 0, 0 },                           /* # */
+    { 0, 0 },                           /* $ */
+    { 0, 0 },                           /* % */
+    OSXET("\046\141\155\160\073"),      /* &amp; */
+    { 0, 0 },                           /* ' */
+    {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},  /* ()*+,-./ */
+    {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},  /* 01234567 */
+    {0,0},{0,0},{0,0},{0,0},            /* 89:; */
+    OSXET("\046\154\164\073"),          /* &lt; */
+    { 0, 0 },                           /* = */
+    OSXET("\046\147\164\073"),          /* &gt; */
+};
+
+static int
+OS__check_escaped_control_char(const void *buf, int size) {
+    size_t i;
+    /*
+     * Inefficient algorithm which translates the escape sequences
+     * defined above into characters. Returns -1 if not found.
+     * TODO: replace by a faster algorithm (bsearch(), hash or
+     * nested table lookups).
+     */
+    for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) {
+        const struct OCTET_STRING__xer_escape_table_s *el;
+        el = &OCTET_STRING__xer_escape_table[i];
+        if(el->size == size && memcmp(buf, el->string, size) == 0)
+            return i;
+    }
+    return -1;
+}
+
+static int
+OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) {
+    /*
+     * This might be one of the escape sequences
+     * for control characters. Check it out.
+     * #11.15.5
+     */
+    int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size);
+    if(control_char >= 0) {
+        OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr;
+        void *p = REALLOC(st->buf, st->size + 2);
+        if(p) {
+            st->buf = (uint8_t *)p;
+            st->buf[st->size++] = control_char;
+            st->buf[st->size] = '\0';  /* nul-termination */
+            return 0;
+        }
+    }
+
+    return -1;  /* No, it's not */
+}
+
+asn_enc_rval_t
+OCTET_STRING_encode_xer_utf8(const asn_TYPE_descriptor_t *td, const void *sptr,
+                             int ilevel, enum xer_encoder_flags_e flags,
+                             asn_app_consume_bytes_f *cb, void *app_key) {
+    const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
+    asn_enc_rval_t er = { 0, 0, 0 };
+    uint8_t *buf, *end;
+    uint8_t *ss;  /* Sequence start */
+    ssize_t encoded_len = 0;
+
+    (void)ilevel;  /* Unused argument */
+    (void)flags;  /* Unused argument */
+
+    if(!st || (!st->buf && st->size))
+        ASN__ENCODE_FAILED;
+
+    buf = st->buf;
+    end = buf + st->size;
+    for(ss = buf; buf < end; buf++) {
+        unsigned int ch = *buf;
+        int s_len;     /* Special encoding sequence length */
+
+        /*
+         * Escape certain characters: X.680/11.15
+         */
+        if(ch < sizeof(OCTET_STRING__xer_escape_table)
+            / sizeof(OCTET_STRING__xer_escape_table[0])
+        && (s_len = OCTET_STRING__xer_escape_table[ch].size)) {
+            if(((buf - ss) && cb(ss, buf - ss, app_key) < 0)
+            || cb(OCTET_STRING__xer_escape_table[ch].string, s_len, app_key) < 0)
+                ASN__ENCODE_FAILED;
+            encoded_len += (buf - ss) + s_len;
+            ss = buf + 1;
+        }
+    }
+
+    encoded_len += (buf - ss);
+    if((buf - ss) && cb(ss, buf - ss, app_key) < 0)
+        ASN__ENCODE_FAILED;
+
+    er.encoded = encoded_len;
+    ASN__ENCODED_OK(er);
+}
+
+/*
+ * Convert from hexadecimal format (cstring): "AB CD EF"
+ */
+static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
+    OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
+    const char *chunk_stop = (const char *)chunk_buf;
+    const char *p = chunk_stop;
+    const char *pend = p + chunk_size;
+    unsigned int clv = 0;
+    int half = 0;      /* Half bit */
+    uint8_t *buf;
+
+    /* Reallocate buffer according to high cap estimation */
+    size_t new_size = st->size + (chunk_size + 1) / 2;
+    void *nptr = REALLOC(st->buf, new_size + 1);
+    if(!nptr) return -1;
+    st->buf = (uint8_t *)nptr;
+    buf = st->buf + st->size;
+
+    /*
+     * If something like " a b c " appears here, the " a b":3 will be
+     * converted, and the rest skipped. That is, unless buf_size is greater
+     * than chunk_size, then it'll be equivalent to "ABC0".
+     */
+    for(; p < pend; p++) {
+        int ch = *(const unsigned char *)p;
+        switch(ch) {
+        case 0x09: case 0x0a: case 0x0c: case 0x0d:
+        case 0x20:
+            /* Ignore whitespace */
+            continue;
+        case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:  /*01234*/
+        case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:  /*56789*/
+            clv = (clv << 4) + (ch - 0x30);
+            break;
+        case 0x41: case 0x42: case 0x43:  /* ABC */
+        case 0x44: case 0x45: case 0x46:  /* DEF */
+            clv = (clv << 4) + (ch - 0x41 + 10);
+            break;
+        case 0x61: case 0x62: case 0x63:  /* abc */
+        case 0x64: case 0x65: case 0x66:  /* def */
+            clv = (clv << 4) + (ch - 0x61 + 10);
+            break;
+        default:
+            *buf = 0;  /* JIC */
+            return -1;
+        }
+        if(half++) {
+            half = 0;
+            *buf++ = clv;
+            chunk_stop = p + 1;
+        }
+    }
+
+    /*
+     * Check partial decoding.
+     */
+    if(half) {
+        if(have_more) {
+            /*
+             * Partial specification is fine,
+             * because no more more PXER_TEXT data is available.
+             */
+            *buf++ = clv << 4;
+            chunk_stop = p;
+        }
+    } else {
+        chunk_stop = p;
+    }
+
+    st->size = buf - st->buf;  /* Adjust the buffer size */
+    assert(st->size <= new_size);
+    st->buf[st->size] = 0;  /* Courtesy termination */
+
+    return (chunk_stop - (const char *)chunk_buf);  /* Converted size */
+}
+
+/*
+ * Convert from binary format: "00101011101"
+ */
+static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
+    BIT_STRING_t *st = (BIT_STRING_t *)sptr;
+    const char *p = (const char *)chunk_buf;
+    const char *pend = (p == NULL)? NULL : p + chunk_size;
+    int bits_unused = st->bits_unused & 0x7;
+    uint8_t *buf;
+
+    /* Reallocate buffer according to high cap estimation */
+    size_t new_size = st->size + (chunk_size + 7) / 8;
+    void *nptr = REALLOC(st->buf, new_size + 1);
+    if(!nptr) return -1;
+    st->buf = (uint8_t *)nptr;
+    buf = st->buf + st->size;
+
+    (void)have_more;
+
+    if(bits_unused == 0)
+        bits_unused = 8;
+    else if(st->size)
+        buf--;
+
+    /*
+     * Convert series of 0 and 1 into the octet string.
+     */
+    for(; p < pend; p++) {
+        int ch = *(const unsigned char *)p;
+        switch(ch) {
+        case 0x09: case 0x0a: case 0x0c: case 0x0d:
+        case 0x20:
+            /* Ignore whitespace */
+            break;
+        case 0x30:
+        case 0x31:
+            if(bits_unused-- <= 0) {
+                *++buf = 0;    /* Clean the cell */
+                bits_unused = 7;
+            }
+            *buf |= (ch&1) << bits_unused;
+            break;
+        default:
+            st->bits_unused = bits_unused;
+            return -1;
+        }
+    }
+
+    if(bits_unused == 8) {
+        st->size = buf - st->buf;
+        st->bits_unused = 0;
+    } else {
+        st->size = buf - st->buf + 1;
+        st->bits_unused = bits_unused;
+    }
+
+    assert(st->size <= new_size);
+    st->buf[st->size] = 0;  /* Courtesy termination */
+
+    return chunk_size;  /* Converted in full */
+}
+
+/*
+ * Something like strtod(), but with stricter rules.
+ */
+static int
+OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) {
+       const int32_t last_unicode_codepoint = 0x10ffff;
+       int32_t val = 0;
+       const char *p;
+
+       for(p = buf; p < end; p++) {
+               int ch = *p;
+
+        switch(ch) {
+        case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:  /*01234*/
+        case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:  /*56789*/
+            val = val * base + (ch - 0x30);
+            break;
+        case 0x41: case 0x42: case 0x43:  /* ABC */
+        case 0x44: case 0x45: case 0x46:  /* DEF */
+            val = val * base + (ch - 0x41 + 10);
+            break;
+        case 0x61: case 0x62: case 0x63:  /* abc */
+        case 0x64: case 0x65: case 0x66:  /* def */
+            val = val * base + (ch - 0x61 + 10);
+            break;
+        case 0x3b:  /* ';' */
+            *ret_value = val;
+            return (p - buf) + 1;
+        default:
+            return -1;  /* Character set error */
+        }
+
+        /* Value exceeds the Unicode range. */
+        if(val > last_unicode_codepoint) {
+            return -1;
+        }
+    }
+
+    *ret_value = -1;
+    return (p - buf);
+}
+
+/*
+ * Convert from the plain UTF-8 format, expanding entity references: "2 &lt; 3"
+ */
+static ssize_t
+OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf,
+                              size_t chunk_size, int have_more) {
+    OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
+    const char *p = (const char *)chunk_buf;
+    const char *pend = p + chunk_size;
+    uint8_t *buf;
+
+    /* Reallocate buffer */
+    size_t new_size = st->size + chunk_size;
+    void *nptr = REALLOC(st->buf, new_size + 1);
+    if(!nptr) return -1;
+    st->buf = (uint8_t *)nptr;
+    buf = st->buf + st->size;
+
+    /*
+     * Convert series of 0 and 1 into the octet string.
+     */
+    for(; p < pend; p++) {
+        int ch = *(const unsigned char *)p;
+        int len;  /* Length of the rest of the chunk */
+
+        if(ch != 0x26 /* '&' */) {
+            *buf++ = ch;
+            continue;  /* That was easy... */
+        }
+
+        /*
+         * Process entity reference.
+         */
+        len = chunk_size - (p - (const char *)chunk_buf);
+        if(len == 1 /* "&" */) goto want_more;
+        if(p[1] == 0x23 /* '#' */) {
+            const char *pval;  /* Pointer to start of digits */
+            int32_t val = 0;  /* Entity reference value */
+            int base;
+
+            if(len == 2 /* "&#" */) goto want_more;
+            if(p[2] == 0x78 /* 'x' */)
+                pval = p + 3, base = 16;
+            else
+                pval = p + 2, base = 10;
+            len = OS__strtoent(base, pval, p + len, &val);
+            if(len == -1) {
+                /* Invalid charset. Just copy verbatim. */
+                *buf++ = ch;
+                continue;
+            }
+            if(!len || pval[len-1] != 0x3b) goto want_more;
+            assert(val > 0);
+            p += (pval - p) + len - 1;  /* Advance past entref */
+
+            if(val < 0x80) {
+                *buf++ = (char)val;
+            } else if(val < 0x800) {
+                *buf++ = 0xc0 | ((val >> 6));
+                *buf++ = 0x80 | ((val & 0x3f));
+            } else if(val < 0x10000) {
+                *buf++ = 0xe0 | ((val >> 12));
+                *buf++ = 0x80 | ((val >> 6) & 0x3f);
+                *buf++ = 0x80 | ((val & 0x3f));
+            } else if(val < 0x200000) {
+                *buf++ = 0xf0 | ((val >> 18));
+                *buf++ = 0x80 | ((val >> 12) & 0x3f);
+                *buf++ = 0x80 | ((val >> 6) & 0x3f);
+                *buf++ = 0x80 | ((val & 0x3f));
+            } else if(val < 0x4000000) {
+                *buf++ = 0xf8 | ((val >> 24));
+                *buf++ = 0x80 | ((val >> 18) & 0x3f);
+                *buf++ = 0x80 | ((val >> 12) & 0x3f);
+                *buf++ = 0x80 | ((val >> 6) & 0x3f);
+                *buf++ = 0x80 | ((val & 0x3f));
+            } else {
+                *buf++ = 0xfc | ((val >> 30) & 0x1);
+                *buf++ = 0x80 | ((val >> 24) & 0x3f);
+                *buf++ = 0x80 | ((val >> 18) & 0x3f);
+                *buf++ = 0x80 | ((val >> 12) & 0x3f);
+                *buf++ = 0x80 | ((val >> 6) & 0x3f);
+                *buf++ = 0x80 | ((val & 0x3f));
+            }
+        } else {
+            /*
+             * Ugly, limited parsing of &amp; &gt; &lt;
+             */
+            char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len);
+            if(!sc) goto want_more;
+            if((sc - p) == 4
+                && p[1] == 0x61  /* 'a' */
+                && p[2] == 0x6d  /* 'm' */
+                && p[3] == 0x70  /* 'p' */) {
+                *buf++ = 0x26;
+                p = sc;
+                continue;
+            }
+            if((sc - p) == 3) {
+                if(p[1] == 0x6c) {
+                    *buf = 0x3c;  /* '<' */
+                } else if(p[1] == 0x67) {
+                    *buf = 0x3e;  /* '>' */
+                } else {
+                    /* Unsupported entity reference */
+                    *buf++ = ch;
+                    continue;
+                }
+                if(p[2] != 0x74) {
+                    /* Unsupported entity reference */
+                    *buf++ = ch;
+                    continue;
+                }
+                buf++;
+                p = sc;
+                continue;
+            }
+            /* Unsupported entity reference */
+            *buf++ = ch;
+        }
+
+        continue;
+    want_more:
+        if(have_more) {
+            /*
+             * We know that no more data (of the same type)
+             * is coming. Copy the rest verbatim.
+             */
+            *buf++ = ch;
+            continue;
+        }
+        chunk_size = (p - (const char *)chunk_buf);
+        /* Processing stalled: need more data */
+        break;
+    }
+
+    st->size = buf - st->buf;
+    assert(st->size <= new_size);
+    st->buf[st->size] = 0;  /* Courtesy termination */
+
+    return chunk_size;  /* Converted in full */
+}
+
+/*
+ * Decode OCTET STRING from the XML element's body.
+ */
+static asn_dec_rval_t
+OCTET_STRING__decode_xer(
+    const asn_codec_ctx_t *opt_codec_ctx, const asn_TYPE_descriptor_t *td,
+    void **sptr, const char *opt_mname, const void *buf_ptr, size_t size,
+    int (*opt_unexpected_tag_decoder)(void *struct_ptr, const void *chunk_buf,
+                                      size_t chunk_size),
+    ssize_t (*body_receiver)(void *struct_ptr, const void *chunk_buf,
+                             size_t chunk_size, int have_more)) {
+    OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr;
+    const asn_OCTET_STRING_specifics_t *specs = td->specifics
+        ? (const asn_OCTET_STRING_specifics_t *)td->specifics
+        : &asn_SPC_OCTET_STRING_specs;
+    const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
+    asn_struct_ctx_t *ctx;  /* Per-structure parser context */
+    asn_dec_rval_t rval;  /* Return value from the decoder */
+    int st_allocated;
+
+    /*
+     * Create the string if does not exist.
+     */
+    if(!st) {
+        st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);
+        *sptr = (void *)st;
+        if(!st) goto sta_failed;
+        st_allocated = 1;
+    } else {
+        st_allocated = 0;
+    }
+    if(!st->buf) {
+        /* This is separate from above section */
+        st->buf = (uint8_t *)CALLOC(1, 1);
+        if(!st->buf) {
+            if(st_allocated) {
+                *sptr = 0;
+                goto stb_failed;
+            } else {
+                goto sta_failed;
+            }
+        }
+    }
+
+    /* Restore parsing context */
+    ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset);
+
+    return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag,
+                              buf_ptr, size,
+                              opt_unexpected_tag_decoder,
+                              body_receiver);
+
+stb_failed:
+    FREEMEM(st);
+sta_failed:
+    rval.code = RC_FAIL;
+    rval.consumed = 0;
+    return rval;
+}
+
+/*
+ * Decode OCTET STRING from the hexadecimal data.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_xer_hex(const asn_codec_ctx_t *opt_codec_ctx,
+                            const asn_TYPE_descriptor_t *td, void **sptr,
+                            const char *opt_mname, const void *buf_ptr,
+                            size_t size) {
+    return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
+                                    buf_ptr, size, 0,
+                                    OCTET_STRING__convert_hexadecimal);
+}
+
+/*
+ * Decode OCTET STRING from the binary (0/1) data.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_xer_binary(const asn_codec_ctx_t *opt_codec_ctx,
+                               const asn_TYPE_descriptor_t *td, void **sptr,
+                               const char *opt_mname, const void *buf_ptr,
+                               size_t size) {
+    return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
+                                    buf_ptr, size, 0,
+                                    OCTET_STRING__convert_binary);
+}
+
+/*
+ * Decode OCTET STRING from the string (ASCII/UTF-8) data.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_xer_utf8(const asn_codec_ctx_t *opt_codec_ctx,
+                             const asn_TYPE_descriptor_t *td, void **sptr,
+                             const char *opt_mname, const void *buf_ptr,
+                             size_t size) {
+    return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
+                                    buf_ptr, size,
+                                    OCTET_STRING__handle_control_chars,
+                                    OCTET_STRING__convert_entrefs);
+}