open5gs/lib/asn1c/common/OCTET_STRING_aper.c

413 lines
14 KiB
C

/*
* 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 */
#undef RETURN
#define RETURN(_code) do {\
asn_dec_rval_t tmprval;\
tmprval.code = _code;\
tmprval.consumed = consumed_myself;\
return tmprval;\
} while(0)
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
};
asn_dec_rval_t
OCTET_STRING_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *td,
const asn_per_constraints_t *constraints,
void **sptr, asn_per_data_t *pd) {
const asn_OCTET_STRING_specifics_t *specs = td->specifics
? (const asn_OCTET_STRING_specifics_t *)td->specifics
: &asn_SPC_OCTET_STRING_specs;
const asn_per_constraints_t *pc = constraints
? constraints
: td->encoding_constraints.per_constraints;
const asn_per_constraint_t *cval;
const asn_per_constraint_t *csiz;
asn_dec_rval_t rval = { RC_OK, 0 };
BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
ssize_t consumed_myself = 0;
int repeat;
enum {
OS__BPC_BIT = 0,
OS__BPC_CHAR = 1,
OS__BPC_U16 = 2,
OS__BPC_U32 = 4
} bpc; /* Bytes per character */
unsigned int unit_bits;
unsigned int canonical_unit_bits;
(void)opt_codec_ctx;
if(pc) {
cval = &pc->value;
csiz = &pc->size;
} else {
cval = &asn_DEF_OCTET_STRING_constraints.value;
csiz = &asn_DEF_OCTET_STRING_constraints.size;
}
switch(specs->subvariant) {
default:
/*
case ASN_OSUBV_ANY:
ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant);
RETURN(RC_FAIL);
*/
case ASN_OSUBV_BIT:
canonical_unit_bits = unit_bits = 1;
bpc = OS__BPC_BIT;
break;
case ASN_OSUBV_ANY:
case ASN_OSUBV_STR:
canonical_unit_bits = unit_bits = 8;
/*
if(cval->flags & APC_CONSTRAINED)
unit_bits = cval->range_bits;
*/
bpc = OS__BPC_CHAR;
break;
case ASN_OSUBV_U16:
canonical_unit_bits = unit_bits = 16;
if(cval->flags & APC_CONSTRAINED)
unit_bits = cval->range_bits;
bpc = OS__BPC_U16;
break;
case ASN_OSUBV_U32:
canonical_unit_bits = unit_bits = 32;
if(cval->flags & APC_CONSTRAINED)
unit_bits = cval->range_bits;
bpc = OS__BPC_U32;
break;
}
/*
* Allocate the string.
*/
if(!st) {
st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
if(!st) RETURN(RC_FAIL);
}
ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d",
csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible",
csiz->lower_bound, csiz->upper_bound, csiz->effective_bits);
if(csiz->flags & APC_EXTENSIBLE) {
int inext = per_get_few_bits(pd, 1);
if(inext < 0) RETURN(RC_WMORE);
if(inext) {
csiz = &asn_DEF_OCTET_STRING_constraints.size;
cval = &asn_DEF_OCTET_STRING_constraints.value;
unit_bits = canonical_unit_bits;
}
}
if(csiz->effective_bits >= 0) {
FREEMEM(st->buf);
if(bpc) {
st->size = csiz->upper_bound * bpc;
} else {
st->size = (csiz->upper_bound + 7) >> 3;
}
st->buf = (uint8_t *)MALLOC(st->size + 1);
if(!st->buf) { st->size = 0; RETURN(RC_FAIL); }
}
/* X.691, #16.5: zero-length encoding */
/* X.691, #16.6: short fixed length encoding (up to 2 octets) */
/* X.691, #16.7: long fixed length encoding (up to 64K octets) */
if(csiz->effective_bits == 0) {
int ret;
/* X.691 #16 NOTE 1 for fixed length (<= 16 bits) strings */
if (st->size > 2 || csiz->range_bits != 0) {
if (aper_get_align(pd) < 0)
RETURN(RC_FAIL);
}
if(bpc) {
ASN_DEBUG("Decoding OCTET STRING size %ld",
csiz->upper_bound);
ret = OCTET_STRING_per_get_characters(pd, st->buf,
csiz->upper_bound,
bpc, unit_bits,
cval->lower_bound,
cval->upper_bound,
pc);
if(ret > 0) RETURN(RC_FAIL);
} else {
ASN_DEBUG("Decoding BIT STRING size %ld",
csiz->upper_bound);
ret = per_get_many_bits(pd, st->buf, 0,
unit_bits * csiz->upper_bound);
}
if(ret < 0) RETURN(RC_WMORE);
consumed_myself += unit_bits * csiz->upper_bound;
st->buf[st->size] = 0;
if(bpc == 0) {
int ubs = (csiz->upper_bound & 0x7);
st->bits_unused = ubs ? 8 - ubs : 0;
}
RETURN(RC_OK);
}
st->size = 0;
do {
ssize_t raw_len;
ssize_t len_bytes;
ssize_t len_bits;
void *p;
int ret;
repeat = 0;
/* Get the PER length */
if (csiz->upper_bound - csiz->lower_bound == 0)
/* Indefinite length case */
raw_len = aper_get_length(pd, -1, -1, csiz->effective_bits, &repeat);
else
raw_len = aper_get_length(pd, csiz->lower_bound, csiz->upper_bound,
csiz->effective_bits, &repeat);
if(raw_len < 0) RETURN(RC_WMORE);
raw_len += csiz->lower_bound;
ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
(long)csiz->effective_bits, (long)raw_len,
repeat ? "repeat" : "once", td->name);
/* X.691 #16 NOTE 1 for fixed length (<=16 bits) strings */
if ((raw_len > 2) || (csiz->upper_bound > 2) || (csiz->range_bits != 0))
{
if (aper_get_align(pd) < 0)
RETURN(RC_FAIL);
}
if(bpc) {
len_bytes = raw_len * bpc;
len_bits = len_bytes * unit_bits;
} else {
len_bits = raw_len;
len_bytes = (len_bits + 7) >> 3;
if(len_bits & 0x7)
st->bits_unused = 8 - (len_bits & 0x7);
/* len_bits be multiple of 16K if repeat is set */
}
p = REALLOC(st->buf, st->size + len_bytes + 1);
if(!p) RETURN(RC_FAIL);
st->buf = (uint8_t *)p;
if(bpc) {
ret = OCTET_STRING_per_get_characters(pd,
&st->buf[st->size],
raw_len, bpc,
unit_bits,
cval->lower_bound,
cval->upper_bound,
pc);
if(ret > 0) RETURN(RC_FAIL);
} else {
ret = per_get_many_bits(pd, &st->buf[st->size],
0, len_bits);
}
if(ret < 0) RETURN(RC_WMORE);
st->size += len_bytes;
} while(repeat);
st->buf[st->size] = 0; /* nul-terminate */
return rval;
}
asn_enc_rval_t
OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,
const asn_per_constraints_t *constraints,
const void *sptr, asn_per_outp_t *po) {
const asn_OCTET_STRING_specifics_t *specs = td->specifics
? (const asn_OCTET_STRING_specifics_t *)td->specifics
: &asn_SPC_OCTET_STRING_specs;
const asn_per_constraints_t *pc = constraints
? constraints
: td->encoding_constraints.per_constraints;
const asn_per_constraint_t *cval;
const asn_per_constraint_t *csiz;
const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
asn_enc_rval_t er = { 0, 0, 0 };
int inext = 0; /* Lies not within extension root */
unsigned int unit_bits;
unsigned int canonical_unit_bits;
unsigned int sizeinunits;
const uint8_t *buf;
int ret;
enum {
OS__BPC_BIT = 0,
OS__BPC_CHAR = 1,
OS__BPC_U16 = 2,
OS__BPC_U32 = 4
} bpc; /* Bytes per character */
int ct_extensible;
if(!st || (!st->buf && st->size))
ASN__ENCODE_FAILED;
if(pc) {
cval = &pc->value;
csiz = &pc->size;
} else {
cval = &asn_DEF_OCTET_STRING_constraints.value;
csiz = &asn_DEF_OCTET_STRING_constraints.size;
}
ct_extensible = csiz->flags & APC_EXTENSIBLE;
switch(specs->subvariant) {
default:
/*
case ASN_OSUBV_ANY:
ASN__ENCODE_FAILED;
*/
case ASN_OSUBV_BIT:
canonical_unit_bits = unit_bits = 1;
bpc = OS__BPC_BIT;
sizeinunits = st->size * 8 - (st->bits_unused & 0x07);
ASN_DEBUG("BIT STRING of %d bytes",
sizeinunits);
break;
case ASN_OSUBV_ANY:
case ASN_OSUBV_STR:
canonical_unit_bits = unit_bits = 8;
/*
if(cval->flags & APC_CONSTRAINED)
unit_bits = 8;
*/
bpc = OS__BPC_CHAR;
sizeinunits = st->size;
break;
case ASN_OSUBV_U16:
canonical_unit_bits = unit_bits = 16;
if(cval->flags & APC_CONSTRAINED)
unit_bits = cval->range_bits;
bpc = OS__BPC_U16;
sizeinunits = st->size / 2;
break;
case ASN_OSUBV_U32:
canonical_unit_bits = unit_bits = 32;
if(cval->flags & APC_CONSTRAINED)
unit_bits = cval->range_bits;
bpc = OS__BPC_U32;
sizeinunits = st->size / 4;
break;
}
ASN_DEBUG("Encoding %s into %d units of %d bits"
" (%ld..%ld, effective %d)%s",
td->name, sizeinunits, unit_bits,
csiz->lower_bound, csiz->upper_bound,
csiz->effective_bits, ct_extensible ? " EXT" : "");
/* Figure out wheter size lies within PER visible constraint */
if(csiz->effective_bits >= 0) {
if((int)sizeinunits < csiz->lower_bound
|| (int)sizeinunits > csiz->upper_bound) {
if(ct_extensible) {
cval = &asn_DEF_OCTET_STRING_constraints.value;
csiz = &asn_DEF_OCTET_STRING_constraints.size;
unit_bits = canonical_unit_bits;
inext = 1;
} else
ASN__ENCODE_FAILED;
}
} else {
inext = 0;
}
if(ct_extensible) {
/* Declare whether length is [not] within extension root */
if(per_put_few_bits(po, inext, 1))
ASN__ENCODE_FAILED;
}
/* X.691, #16.5: zero-length encoding */
/* X.691, #16.6: short fixed length encoding (up to 2 octets) */
/* X.691, #16.7: long fixed length encoding (up to 64K octets) */
if(csiz->effective_bits >= 0) {
ASN_DEBUG("Encoding %lu bytes (%ld), length in %d bits",
st->size, sizeinunits - csiz->lower_bound,
csiz->effective_bits);
if (csiz->effective_bits > 0) {
ret = aper_put_length(po, csiz->lower_bound, csiz->upper_bound,
sizeinunits - csiz->lower_bound, NULL);
if(ret < 0) ASN__ENCODE_FAILED;
}
if (csiz->effective_bits > 0 || (st->size > 2)
|| (csiz->upper_bound > (2 * 8 / unit_bits))
|| (csiz->range_bits != 0))
{ /* X.691 #16 NOTE 1 for fixed length (<=16 bits) strings*/
if (aper_put_align(po) < 0)
ASN__ENCODE_FAILED;
}
if(bpc) {
ret = OCTET_STRING_per_put_characters(po, st->buf,
sizeinunits,
bpc, unit_bits,
cval->lower_bound,
cval->upper_bound,
pc);
} else {
ret = per_put_many_bits(po, st->buf,
sizeinunits * unit_bits);
}
if(ret) ASN__ENCODE_FAILED;
ASN__ENCODED_OK(er);
}
ASN_DEBUG("Encoding %lu bytes", st->size);
if(sizeinunits == 0) {
if(aper_put_length(po, -1, -1, 0, NULL) < 0)
ASN__ENCODE_FAILED;
ASN__ENCODED_OK(er);
}
buf = st->buf;
while(sizeinunits) {
int need_eom = 0;
ssize_t maySave = aper_put_length(po, -1, -1, sizeinunits, &need_eom);
if(maySave < 0) ASN__ENCODE_FAILED;
ASN_DEBUG("Encoding %ld of %ld",
(long)maySave, (long)sizeinunits);
if(bpc) {
ret = OCTET_STRING_per_put_characters(po, buf, maySave,
bpc, unit_bits,
cval->lower_bound,
cval->upper_bound,
pc);
} else {
ret = per_put_many_bits(po, buf, maySave * unit_bits);
}
if(ret) ASN__ENCODE_FAILED;
if(bpc)
buf += maySave * bpc;
else
buf += maySave >> 3;
sizeinunits -= maySave;
assert(!(maySave & 0x07) || !sizeinunits);
if(need_eom && (aper_put_length(po, -1, -1, 0, NULL) < 0))
ASN__ENCODE_FAILED; /* End of Message length */
}
ASN__ENCODED_OK(er);
}