asn1c/skeletons/OCTET_STRING.c

1806 lines
46 KiB
C
Raw Normal View History

2004-06-03 03:38:44 +00:00
/*-
2006-09-18 20:05:55 +00:00
* Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
2004-06-03 03:38:44 +00:00
* Redistribution and modifications are permitted subject to BSD license.
*/
2004-09-22 16:06:28 +00:00
#include <asn_internal.h>
2004-06-03 03:38:44 +00:00
#include <OCTET_STRING.h>
#include <BIT_STRING.h> /* for .bits_unused member */
2004-06-03 03:38:44 +00:00
#include <errno.h>
/*
* OCTET STRING basic type description.
*/
static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = {
2004-06-03 03:38:44 +00:00
(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
};
static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = {
sizeof(OCTET_STRING_t),
offsetof(OCTET_STRING_t, _asn_ctx),
2006-11-24 11:20:27 +00:00
ASN_OSUBV_STR
};
2006-11-24 11:20:27 +00:00
static asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = {
{ APC_CONSTRAINED, 8, 8, 0, 255 },
{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },
0, 0
2005-11-26 11:25:14 +00:00
};
asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = {
2004-10-20 15:50:55 +00:00
"OCTET STRING", /* Canonical name */
"OCTET_STRING", /* XML tag name */
2004-09-22 16:06:28 +00:00
OCTET_STRING_free,
OCTET_STRING_print, /* non-ascii stuff, generally */
2004-06-03 03:38:44 +00:00
asn_generic_no_constraint,
OCTET_STRING_decode_ber,
OCTET_STRING_encode_der,
2004-10-20 15:50:55 +00:00
OCTET_STRING_decode_xer_hex,
2004-09-22 16:06:28 +00:00
OCTET_STRING_encode_xer,
2005-11-26 11:25:14 +00:00
OCTET_STRING_decode_uper, /* Unaligned PER decoder */
2006-08-18 01:34:18 +00:00
OCTET_STRING_encode_uper, /* Unaligned PER encoder */
2004-06-03 03:38:44 +00:00
0, /* Use generic outmost tag fetcher */
asn_DEF_OCTET_STRING_tags,
sizeof(asn_DEF_OCTET_STRING_tags)
/ sizeof(asn_DEF_OCTET_STRING_tags[0]),
asn_DEF_OCTET_STRING_tags, /* Same as above */
sizeof(asn_DEF_OCTET_STRING_tags)
/ sizeof(asn_DEF_OCTET_STRING_tags[0]),
2005-11-26 11:25:14 +00:00
0, /* No PER visible constraints */
2004-08-20 13:23:42 +00:00
0, 0, /* No members */
&asn_DEF_OCTET_STRING_specs
2004-06-03 03:38:44 +00:00
};
2004-09-23 22:06:26 +00:00
#undef _CH_PHASE
#undef NEXT_PHASE
#undef PREV_PHASE
#define _CH_PHASE(ctx, inc) do { \
if(ctx->phase == 0) \
ctx->context = 0; \
ctx->phase += inc; \
2004-06-03 03:38:44 +00:00
} while(0)
#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1)
#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1)
2004-09-23 22:06:26 +00:00
#undef ADVANCE
#define ADVANCE(num_bytes) do { \
size_t num = (num_bytes); \
buf_ptr = ((const char *)buf_ptr) + num; \
size -= num; \
consumed_myself += num; \
2004-06-03 03:38:44 +00:00
} while(0)
2004-09-23 22:06:26 +00:00
#undef RETURN
#define RETURN(_code) do { \
2005-11-26 11:25:14 +00:00
asn_dec_rval_t tmprval; \
tmprval.code = _code; \
tmprval.consumed = consumed_myself; \
return tmprval; \
2004-06-03 03:38:44 +00:00
} while(0)
2004-09-23 22:06:26 +00:00
#undef APPEND
2004-06-05 08:17:50 +00:00
#define APPEND(bufptr, bufsize) do { \
size_t _bs = (bufsize); /* Append size */ \
size_t _ns = ctx->context; /* Allocated now */ \
size_t _es = st->size + _bs; /* Expected size */ \
/* int is really a typeof(st->size): */ \
if((int)_es < 0) RETURN(RC_FAIL); \
if(_ns <= _es) { \
2004-06-05 08:17:50 +00:00
void *ptr; \
/* Be nice and round to the memory allocator */ \
do { _ns = _ns ? _ns << 1 : 16; } \
while(_ns <= _es); \
/* int is really a typeof(st->size): */ \
if((int)_ns < 0) RETURN(RC_FAIL); \
2004-06-05 08:17:50 +00:00
ptr = REALLOC(st->buf, _ns); \
if(ptr) { \
2004-08-11 09:07:36 +00:00
st->buf = (uint8_t *)ptr; \
ctx->context = _ns; \
2004-06-05 08:17:50 +00:00
} else { \
RETURN(RC_FAIL); \
} \
2005-07-02 20:24:27 +00:00
ASN_DEBUG("Reallocating into %ld", (long)_ns); \
2004-06-05 08:17:50 +00:00
} \
2004-09-04 04:44:50 +00:00
memcpy(st->buf + st->size, bufptr, _bs); \
2004-06-05 08:17:50 +00:00
/* Convenient nul-termination */ \
st->buf[_es] = '\0'; \
st->size = _es; \
2004-06-03 03:38:44 +00:00
} while(0)
/*
* The main reason why ASN.1 is still alive is that too much time and effort
* is necessary for learning it more or less adequately, thus creating a gut
* necessity to demonstrate that aquired skill everywhere afterwards.
* No, I am not going to explain what the following stuff is.
*/
struct _stack_el {
2004-09-24 20:57:41 +00:00
ber_tlv_len_t left; /* What's left to read (or -1) */
2004-09-27 20:54:06 +00:00
ber_tlv_len_t got; /* What was actually processed */
int cont_level; /* Depth of subcontainment */
2004-06-03 03:38:44 +00:00
int want_nulls; /* Want null "end of content" octets? */
int bits_chopped; /* Flag in BIT STRING mode */
2004-09-27 20:54:06 +00:00
ber_tlv_tag_t tag; /* For debugging purposes */
2004-06-03 03:38:44 +00:00
struct _stack_el *prev;
struct _stack_el *next;
};
struct _stack {
struct _stack_el *tail;
struct _stack_el *cur_ptr;
};
static struct _stack_el *
2004-09-24 20:57:41 +00:00
OS__add_stack_el(struct _stack *st) {
2004-06-03 03:38:44 +00:00
struct _stack_el *nel;
/*
* Reuse the old stack frame or allocate a new one.
*/
2004-06-03 03:38:44 +00:00
if(st->cur_ptr && st->cur_ptr->next) {
nel = st->cur_ptr->next;
nel->bits_chopped = 0;
2004-09-27 20:54:06 +00:00
nel->got = 0;
/* Retain the nel->cont_level, it's correct. */
2004-06-03 03:38:44 +00:00
} else {
2004-12-15 23:23:53 +00:00
nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el));
2004-06-03 03:38:44 +00:00
if(nel == NULL)
return NULL;
if(st->tail) {
/* Increase a subcontainment depth */
nel->cont_level = st->tail->cont_level + 1;
2004-06-03 03:38:44 +00:00
st->tail->next = nel;
}
nel->prev = st->tail;
st->tail = nel;
}
st->cur_ptr = nel;
return nel;
}
static struct _stack *
_new_stack() {
return (struct _stack *)CALLOC(1, sizeof(struct _stack));
2004-06-03 03:38:44 +00:00
}
/*
* Decode OCTET STRING type.
*/
2004-10-20 15:50:55 +00:00
asn_dec_rval_t
OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
asn_TYPE_descriptor_t *td,
2005-11-26 11:25:14 +00:00
void **sptr, const void *buf_ptr, size_t size, int tag_mode) {
asn_OCTET_STRING_specifics_t *specs = td->specifics
2004-10-20 15:50:55 +00:00
? (asn_OCTET_STRING_specifics_t *)td->specifics
: &asn_DEF_OCTET_STRING_specs;
2005-11-26 11:25:14 +00:00
BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
2004-10-20 15:50:55 +00:00
asn_dec_rval_t rval;
asn_struct_ctx_t *ctx;
2004-06-03 03:38:44 +00:00
ssize_t consumed_myself = 0;
struct _stack *stck; /* Expectations stack structure */
2004-09-27 20:54:06 +00:00
struct _stack_el *sel = 0; /* Stack element */
2004-06-03 03:38:44 +00:00
int tlv_constr;
2006-11-24 11:20:27 +00:00
enum asn_OS_Subvariant type_variant = specs->subvariant;
2004-06-03 03:38:44 +00:00
2004-09-23 22:06:26 +00:00
ASN_DEBUG("Decoding %s as %s (frame %ld)",
td->name,
2006-11-24 11:20:27 +00:00
(type_variant == ASN_OSUBV_STR) ?
"OCTET STRING" : "OS-SpecialCase",
2004-09-23 22:06:26 +00:00
(long)size);
2004-06-03 03:38:44 +00:00
/*
* Create the string if does not exist.
*/
if(st == NULL) {
2005-11-26 11:25:14 +00:00
st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
if(st == NULL) RETURN(RC_FAIL);
2004-06-03 03:38:44 +00:00
}
/* Restore parsing context */
2014-01-14 07:08:47 +00:00
ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
2004-06-03 03:38:44 +00:00
switch(ctx->phase) {
case 0:
/*
* Check tags.
*/
rval = ber_check_tags(opt_codec_ctx, td, ctx,
buf_ptr, size, tag_mode, -1,
2004-06-03 03:38:44 +00:00
&ctx->left, &tlv_constr);
2004-10-05 06:35:31 +00:00
if(rval.code != RC_OK)
return rval;
2004-06-03 03:38:44 +00:00
if(tlv_constr) {
/*
* Complex operation, requires stack of expectations.
*/
ctx->ptr = _new_stack();
if(ctx->ptr) {
2004-12-15 23:23:53 +00:00
stck = (struct _stack *)ctx->ptr;
2004-06-03 03:38:44 +00:00
} else {
RETURN(RC_FAIL);
}
} else {
/*
* Jump into stackless primitive decoding.
*/
_CH_PHASE(ctx, 3);
2006-11-24 11:20:27 +00:00
if(type_variant == ASN_OSUBV_ANY && tag_mode != 1)
APPEND(buf_ptr, rval.consumed);
2004-06-03 03:38:44 +00:00
ADVANCE(rval.consumed);
goto phase3;
}
NEXT_PHASE(ctx);
/* Fall through */
case 1:
phase1:
/*
* Fill the stack with expectations.
*/
2004-12-15 23:23:53 +00:00
stck = (struct _stack *)ctx->ptr;
2004-06-03 03:38:44 +00:00
sel = stck->cur_ptr;
do {
ber_tlv_tag_t tlv_tag;
ber_tlv_len_t tlv_len;
ber_tlv_tag_t expected_tag;
2004-09-27 20:54:06 +00:00
ssize_t tl, ll, tlvl;
/* This one works even if (sel->left == -1) */
ssize_t Left = ((!sel||(size_t)sel->left >= size)
2004-09-27 20:54:06 +00:00
?(ssize_t)size:sel->left);
2004-09-24 20:57:41 +00:00
2004-06-03 03:38:44 +00:00
2004-10-26 10:12:14 +00:00
ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", sel,
2004-10-26 10:56:10 +00:00
(long)(sel?sel->left:0),
(long)(sel?sel->want_nulls:0),
(long)(sel?sel->got:0)
2004-09-27 20:54:06 +00:00
);
if(sel && sel->left <= 0 && sel->want_nulls == 0) {
if(sel->prev) {
struct _stack_el *prev = sel->prev;
if(prev->left != -1) {
if(prev->left < sel->got)
RETURN(RC_FAIL);
prev->left -= sel->got;
}
prev->got += sel->got;
sel = stck->cur_ptr = prev;
if(!sel) break;
tlv_constr = 1;
continue;
} else {
sel = stck->cur_ptr = 0;
break; /* Nothing to wait */
}
}
2004-09-24 20:57:41 +00:00
tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag);
2004-10-26 10:12:14 +00:00
ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld",
(long)size, (long)Left, sel?"":"!",
2004-10-26 10:56:10 +00:00
(long)(sel?sel->left:0),
(long)(sel?sel->want_nulls:0),
2004-10-26 10:12:14 +00:00
(long)tl);
2004-06-03 03:38:44 +00:00
switch(tl) {
case -1: RETURN(RC_FAIL);
case 0: RETURN(RC_WMORE);
}
tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);
ll = ber_fetch_length(tlv_constr,
2005-03-10 18:52:02 +00:00
(const char *)buf_ptr + tl,Left - tl,&tlv_len);
2005-03-02 01:54:28 +00:00
ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld",
2004-09-04 04:44:50 +00:00
ber_tlv_tag_string(tlv_tag), tlv_constr,
2005-03-02 01:54:28 +00:00
(long)Left, (long)tl, (long)tlv_len, (long)ll);
2004-06-03 03:38:44 +00:00
switch(ll) {
case -1: RETURN(RC_FAIL);
case 0: RETURN(RC_WMORE);
}
2004-09-04 04:44:50 +00:00
if(sel && sel->want_nulls
2005-03-10 18:52:02 +00:00
&& ((const uint8_t *)buf_ptr)[0] == 0
&& ((const uint8_t *)buf_ptr)[1] == 0)
2004-06-03 03:38:44 +00:00
{
2004-09-04 04:44:50 +00:00
ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls);
2006-11-24 11:20:27 +00:00
if(type_variant == ASN_OSUBV_ANY
&& (tag_mode != 1 || sel->cont_level))
APPEND("\0\0", 2);
2004-09-27 20:54:06 +00:00
ADVANCE(2);
sel->got += 2;
if(sel->left != -1) {
sel->left -= 2; /* assert(sel->left >= 2) */
}
2004-06-03 03:38:44 +00:00
sel->want_nulls--;
if(sel->want_nulls == 0) {
/* Move to the next expectation */
2004-09-27 20:54:06 +00:00
sel->left = 0;
2004-06-03 03:38:44 +00:00
tlv_constr = 1;
}
2004-09-04 04:44:50 +00:00
continue;
}
/*
* Set up expected tags,
* depending on ASN.1 type being decoded.
*/
switch(type_variant) {
2006-11-24 11:20:27 +00:00
case ASN_OSUBV_BIT:
/* X.690: 8.6.4.1, NOTE 2 */
/* Fall through */
2006-11-24 11:20:27 +00:00
case ASN_OSUBV_STR:
default:
if(sel) {
int level = sel->cont_level;
if(level < td->all_tags_count) {
expected_tag = td->all_tags[level];
break;
} else if(td->all_tags_count) {
expected_tag = td->all_tags
[td->all_tags_count - 1];
break;
}
/* else, Fall through */
}
/* Fall through */
2006-11-24 11:20:27 +00:00
case ASN_OSUBV_ANY:
expected_tag = tlv_tag;
break;
}
if(tlv_tag != expected_tag) {
2004-06-03 03:38:44 +00:00
char buf[2][32];
ber_tlv_tag_snprint(tlv_tag,
buf[0], sizeof(buf[0]));
ber_tlv_tag_snprint(td->tags[td->tags_count-1],
buf[1], sizeof(buf[1]));
ASN_DEBUG("Tag does not match expectation: %s != %s",
buf[0], buf[1]);
RETURN(RC_FAIL);
}
tlvl = tl + ll; /* Combined length of T and L encoding */
if((tlv_len + tlvl) < 0) {
/* tlv_len value is too big */
ASN_DEBUG("TLV encoding + length (%ld) is too big",
(long)tlv_len);
RETURN(RC_FAIL);
}
2004-06-03 03:38:44 +00:00
/*
* Append a new expectation.
*/
2004-09-24 20:57:41 +00:00
sel = OS__add_stack_el(stck);
2004-09-27 20:54:06 +00:00
if(!sel) RETURN(RC_FAIL);
sel->tag = tlv_tag;
sel->want_nulls = (tlv_len==-1);
if(sel->prev && sel->prev->left != -1) {
/* Check that the parent frame is big enough */
if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len))
RETURN(RC_FAIL);
if(tlv_len == -1)
sel->left = sel->prev->left - tlvl;
else
sel->left = tlv_len;
2004-06-03 03:38:44 +00:00
} else {
2004-09-27 20:54:06 +00:00
sel->left = tlv_len;
2004-06-03 03:38:44 +00:00
}
2006-11-24 11:20:27 +00:00
if(type_variant == ASN_OSUBV_ANY
&& (tag_mode != 1 || sel->cont_level))
APPEND(buf_ptr, tlvl);
2004-09-27 20:54:06 +00:00
sel->got += tlvl;
ADVANCE(tlvl);
2004-10-26 10:12:14 +00:00
ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%d",
(long)sel->got, (long)sel->left,
sel->want_nulls, sel->cont_level);
2004-06-03 03:38:44 +00:00
} while(tlv_constr);
if(sel == NULL) {
/* Finished operation, "phase out" */
ASN_DEBUG("Phase out");
2004-06-03 03:38:44 +00:00
_CH_PHASE(ctx, +3);
break;
}
NEXT_PHASE(ctx);
/* Fall through */
case 2:
2004-12-15 23:23:53 +00:00
stck = (struct _stack *)ctx->ptr;
2004-06-03 03:38:44 +00:00
sel = stck->cur_ptr;
2004-09-27 20:54:06 +00:00
ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d",
(long)sel->left, (long)size, (long)sel->got,
sel->want_nulls);
2004-06-03 03:38:44 +00:00
{
ber_tlv_len_t len;
assert(sel->left >= 0);
2004-08-18 04:53:32 +00:00
len = ((ber_tlv_len_t)size < sel->left)
? (ber_tlv_len_t)size : sel->left;
2004-06-03 03:38:44 +00:00
if(len > 0) {
2006-11-24 11:20:27 +00:00
if(type_variant == ASN_OSUBV_BIT
&& sel->bits_chopped == 0) {
/* Put the unused-bits-octet away */
2005-03-10 18:52:02 +00:00
st->bits_unused = *(const uint8_t *)buf_ptr;
APPEND(((const char *)buf_ptr+1), (len - 1));
2004-06-03 03:38:44 +00:00
sel->bits_chopped = 1;
} else {
APPEND(buf_ptr, len);
}
ADVANCE(len);
sel->left -= len;
2004-09-27 20:54:06 +00:00
sel->got += len;
2004-06-03 03:38:44 +00:00
}
2004-09-27 20:54:06 +00:00
if(sel->left) {
ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n",
(long)sel->left, (long)size, sel->want_nulls);
2004-06-03 03:38:44 +00:00
RETURN(RC_WMORE);
}
2004-09-27 20:54:06 +00:00
PREV_PHASE(ctx);
goto phase1;
2004-06-03 03:38:44 +00:00
}
break;
case 3:
phase3:
/*
* Primitive form, no stack required.
*/
assert(ctx->left >= 0);
2004-06-05 08:17:50 +00:00
if(size < (size_t)ctx->left) {
if(!size) RETURN(RC_WMORE);
2006-11-24 11:20:27 +00:00
if(type_variant == ASN_OSUBV_BIT && !ctx->context) {
2005-03-10 18:52:02 +00:00
st->bits_unused = *(const uint8_t *)buf_ptr;
ctx->left--;
ADVANCE(1);
}
2004-06-03 03:38:44 +00:00
APPEND(buf_ptr, size);
assert(ctx->context > 0);
2004-06-03 03:38:44 +00:00
ctx->left -= size;
ADVANCE(size);
RETURN(RC_WMORE);
} else {
2006-11-24 11:20:27 +00:00
if(type_variant == ASN_OSUBV_BIT
&& !ctx->context && ctx->left) {
2005-03-10 18:52:02 +00:00
st->bits_unused = *(const uint8_t *)buf_ptr;
ctx->left--;
ADVANCE(1);
}
2004-06-03 03:38:44 +00:00
APPEND(buf_ptr, ctx->left);
ADVANCE(ctx->left);
ctx->left = 0;
NEXT_PHASE(ctx);
}
break;
}
2004-09-27 20:54:06 +00:00
if(sel) {
ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld",
sel->prev, sel->want_nulls,
(long)sel->left, (long)sel->got, (long)size);
if(sel->prev || sel->want_nulls > 1 || sel->left > 0) {
RETURN(RC_WMORE);
}
}
2004-06-03 03:38:44 +00:00
/*
* BIT STRING-specific processing.
*/
2006-11-24 11:20:27 +00:00
if(type_variant == ASN_OSUBV_BIT && st->size) {
2004-06-03 03:38:44 +00:00
/* Finalize BIT STRING: zero out unused bits. */
st->buf[st->size-1] &= 0xff << st->bits_unused;
2004-06-03 03:38:44 +00:00
}
2004-10-26 10:12:14 +00:00
ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld",
(long)consumed_myself, td->name,
2006-11-24 11:20:27 +00:00
(type_variant == ASN_OSUBV_STR) ? (char *)st->buf : "<data>",
2004-10-26 10:12:14 +00:00
(long)st->size);
2004-06-03 03:38:44 +00:00
2004-09-27 20:54:06 +00:00
RETURN(RC_OK);
2004-06-03 03:38:44 +00:00
}
/*
* Encode OCTET STRING type using DER.
*/
2004-09-22 16:06:28 +00:00
asn_enc_rval_t
OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
2004-06-03 03:38:44 +00:00
int tag_mode, ber_tlv_tag_t tag,
asn_app_consume_bytes_f *cb, void *app_key) {
asn_enc_rval_t er;
asn_OCTET_STRING_specifics_t *specs = td->specifics
2004-10-20 15:50:55 +00:00
? (asn_OCTET_STRING_specifics_t *)td->specifics
: &asn_DEF_OCTET_STRING_specs;
BIT_STRING_t *st = (BIT_STRING_t *)sptr;
2006-11-24 11:20:27 +00:00
enum asn_OS_Subvariant type_variant = specs->subvariant;
int fix_last_byte = 0;
2004-06-03 03:38:44 +00:00
ASN_DEBUG("%s %s as OCTET STRING",
2004-09-02 12:57:25 +00:00
cb?"Estimating":"Encoding", td->name);
2004-06-03 03:38:44 +00:00
/*
* Write tags.
2004-06-03 03:38:44 +00:00
*/
2006-11-24 11:20:27 +00:00
if(type_variant != ASN_OSUBV_ANY || tag_mode == 1) {
er.encoded = der_write_tags(td,
2006-11-24 11:20:27 +00:00
(type_variant == ASN_OSUBV_BIT) + st->size,
tag_mode, type_variant == ASN_OSUBV_ANY, tag,
cb, app_key);
if(er.encoded == -1) {
er.failed_type = td;
er.structure_ptr = sptr;
return er;
2004-06-03 03:38:44 +00:00
}
} else {
/* Disallow: [<tag>] IMPLICIT ANY */
2006-11-24 11:20:27 +00:00
assert(type_variant != ASN_OSUBV_ANY || tag_mode != -1);
er.encoded = 0;
}
if(!cb) {
2006-11-24 11:20:27 +00:00
er.encoded += (type_variant == ASN_OSUBV_BIT) + st->size;
2005-11-26 11:25:14 +00:00
_ASN_ENCODED_OK(er);
2004-06-03 03:38:44 +00:00
}
/*
* Prepare to deal with the last octet of BIT STRING.
*/
2006-11-24 11:20:27 +00:00
if(type_variant == ASN_OSUBV_BIT) {
uint8_t b = st->bits_unused & 0x07;
if(b && st->size) fix_last_byte = 1;
_ASN_CALLBACK(&b, 1);
er.encoded++;
2004-06-03 03:38:44 +00:00
}
/* Invoke callback for the main part of the buffer */
_ASN_CALLBACK(st->buf, st->size - fix_last_byte);
2004-06-03 03:38:44 +00:00
/* The last octet should be stripped off the unused bits */
if(fix_last_byte) {
uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused);
_ASN_CALLBACK(&b, 1);
2004-06-03 03:38:44 +00:00
}
er.encoded += st->size;
2005-11-26 11:25:14 +00:00
_ASN_ENCODED_OK(er);
cb_failed:
_ASN_ENCODE_FAILED;
2004-06-03 03:38:44 +00:00
}
2004-09-22 16:06:28 +00:00
asn_enc_rval_t
OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
2004-09-22 16:06:28 +00:00
int ilevel, enum xer_encoder_flags_e flags,
asn_app_consume_bytes_f *cb, void *app_key) {
static const char *h2c = "0123456789ABCDEF";
const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
asn_enc_rval_t er;
char scratch[16 * 3 + 4];
char *p = scratch;
uint8_t *buf;
uint8_t *end;
size_t i;
2006-10-16 12:32:14 +00:00
if(!st || (!st->buf && st->size))
2004-10-03 09:13:02 +00:00
_ASN_ENCODE_FAILED;
2004-09-22 16:06:28 +00:00
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);
er.encoded += p - scratch;
p = scratch;
}
*p++ = h2c[(*buf >> 4) & 0x0F];
*p++ = h2c[*buf & 0x0F];
}
2004-09-23 22:06:26 +00:00
_ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
er.encoded += p - scratch;
2004-09-22 16:06:28 +00:00
} else {
for(i = 0; buf < end; buf++, i++) {
if(!(i % 16) && (i || st->size > 16)) {
_ASN_CALLBACK(scratch, p-scratch);
er.encoded += (p-scratch);
p = scratch;
_i_ASN_TEXT_INDENT(1, ilevel);
}
*p++ = h2c[(*buf >> 4) & 0x0F];
*p++ = h2c[*buf & 0x0F];
*p++ = 0x20;
}
2004-09-23 22:06:26 +00:00
if(p - scratch) {
p--; /* Remove the tail space */
_ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
er.encoded += p - scratch;
if(st->size > 16)
_i_ASN_TEXT_INDENT(1, ilevel-1);
}
2004-09-22 16:06:28 +00:00
}
2005-11-26 11:25:14 +00:00
_ASN_ENCODED_OK(er);
2004-10-03 09:13:02 +00:00
cb_failed:
_ASN_ENCODE_FAILED;
2004-09-22 16:06:28 +00:00
}
2004-10-03 10:54:25 +00:00
static struct OCTET_STRING__xer_escape_table_s {
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; */
};
2004-10-20 15:50:55 +00:00
static int
OS__check_escaped_control_char(const void *buf, int size) {
2004-10-20 15:50:55 +00:00
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++) {
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) {
2004-10-20 15:50:55 +00:00
/*
* 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 */
}
2004-09-22 16:06:28 +00:00
asn_enc_rval_t
2004-10-20 15:50:55 +00:00
OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr,
2004-09-22 16:06:28 +00:00
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;
2004-10-03 10:54:25 +00:00
uint8_t *buf, *end;
uint8_t *ss; /* Sequence start */
ssize_t encoded_len = 0;
2004-09-22 16:06:28 +00:00
(void)ilevel; /* Unused argument */
(void)flags; /* Unused argument */
2006-10-16 12:32:14 +00:00
if(!st || (!st->buf && st->size))
2004-09-22 16:06:28 +00:00
_ASN_ENCODE_FAILED;
2004-10-03 10:54:25 +00:00
buf = st->buf;
end = buf + st->size;
for(ss = buf; buf < end; buf++) {
2004-10-05 06:35:31 +00:00
unsigned int ch = *buf;
2004-10-03 10:54:25 +00:00
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)
2004-10-03 09:13:02 +00:00
_ASN_ENCODE_FAILED;
2004-09-22 16:06:28 +00:00
2004-10-03 10:54:25 +00:00
er.encoded = encoded_len;
2005-11-26 11:25:14 +00:00
_ASN_ENCODED_OK(er);
2004-09-22 16:06:28 +00:00
}
2004-10-20 15:50:55 +00:00
/*
* 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) {
2004-10-20 15:50:55 +00:00
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;
2004-10-20 15:50:55 +00:00
unsigned int clv = 0;
int half = 0; /* Half bit */
uint8_t *buf;
/* Reallocate buffer according to high cap estimation */
ssize_t _ns = st->size + (chunk_size + 1) / 2;
void *nptr = REALLOC(st->buf, _ns + 1);
if(!nptr) return -1;
st->buf = (uint8_t *)nptr;
buf = st->buf + st->size;
/* <