open5gs/lib/asn1c/common/OCTET_STRING.c

384 lines
11 KiB
C

/*-
* Copyright (c) 2003-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 <errno.h>
/*
* OCTET STRING basic type description.
*/
static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = {
(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
};
asn_OCTET_STRING_specifics_t asn_SPC_OCTET_STRING_specs = {
sizeof(OCTET_STRING_t),
offsetof(OCTET_STRING_t, _asn_ctx),
ASN_OSUBV_STR
};
asn_TYPE_operation_t asn_OP_OCTET_STRING = {
OCTET_STRING_free,
#if !defined(ASN_DISABLE_PRINT_SUPPORT)
OCTET_STRING_print, /* OCTET STRING generally means a non-ascii sequence */
#else
0,
#endif /* !defined(ASN_DISABLE_PRINT_SUPPORT) */
OCTET_STRING_compare,
#if !defined(ASN_DISABLE_BER_SUPPORT)
OCTET_STRING_decode_ber,
OCTET_STRING_encode_der,
#else
0,
0,
#endif /* !defined(ASN_DISABLE_BER_SUPPORT) */
#if !defined(ASN_DISABLE_XER_SUPPORT)
OCTET_STRING_decode_xer_hex,
OCTET_STRING_encode_xer,
#else
0,
0,
#endif /* !defined(ASN_DISABLE_XER_SUPPORT) */
#if !defined(ASN_DISABLE_JER_SUPPORT)
OCTET_STRING_encode_jer,
#else
0,
#endif /* !defined(ASN_DISABLE_JER_SUPPORT) */
#if !defined(ASN_DISABLE_OER_SUPPORT)
OCTET_STRING_decode_oer,
OCTET_STRING_encode_oer,
#else
0,
0,
#endif /* !defined(ASN_DISABLE_OER_SUPPORT) */
#if !defined(ASN_DISABLE_UPER_SUPPORT)
OCTET_STRING_decode_uper, /* Unaligned PER decoder */
OCTET_STRING_encode_uper, /* Unaligned PER encoder */
#else
0,
0,
#endif /* !defined(ASN_DISABLE_UPER_SUPPORT) */
#if !defined(ASN_DISABLE_APER_SUPPORT)
OCTET_STRING_decode_aper, /* Aligned PER decoder */
OCTET_STRING_encode_aper, /* Aligned PER encoder */
#else
0,
0,
#endif /* !defined(ASN_DISABLE_APER_SUPPORT) */
#if !defined(ASN_DISABLE_RFILL_SUPPORT)
OCTET_STRING_random_fill,
#else
0,
#endif /* !defined(ASN_DISABLE_RFILL_SUPPORT) */
0 /* Use generic outmost tag fetcher */
};
asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = {
"OCTET STRING", /* Canonical name */
"OCTET_STRING", /* XML tag name */
&asn_OP_OCTET_STRING,
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]),
{
#if !defined(ASN_DISABLE_OER_SUPPORT)
0,
#endif /* !defined(ASN_DISABLE_OER_SUPPORT) */
#if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT)
0,
#endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */
asn_generic_no_constraint
},
0, 0, /* No members */
&asn_SPC_OCTET_STRING_specs
};
void
OCTET_STRING_free(const asn_TYPE_descriptor_t *td, void *sptr,
enum asn_struct_free_method method) {
OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
if(!td || !st)
return;
ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
if(st->buf) {
FREEMEM(st->buf);
st->buf = 0;
}
#if !defined(ASN_DISABLE_BER_SUPPORT)
const asn_OCTET_STRING_specifics_t *specs;
asn_struct_ctx_t *ctx;
specs = td->specifics
? (const asn_OCTET_STRING_specifics_t *)td->specifics
: &asn_SPC_OCTET_STRING_specs;
ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
/*
* Remove decode-time stack.
*/
struct _stack *stck;
stck = (struct _stack *)ctx->ptr;
if(stck) {
while(stck->tail) {
struct _stack_el *sel = stck->tail;
stck->tail = sel->prev;
FREEMEM(sel);
}
FREEMEM(stck);
}
#endif /* !defined(ASN_DISABLE_BER_SUPPORT) */
switch(method) {
case ASFM_FREE_EVERYTHING:
FREEMEM(sptr);
break;
case ASFM_FREE_UNDERLYING:
break;
case ASFM_FREE_UNDERLYING_AND_RESET:
memset(sptr, 0,
td->specifics
? ((const asn_OCTET_STRING_specifics_t *)(td->specifics))
->struct_size
: sizeof(OCTET_STRING_t));
break;
}
}
/*
* Conversion routines.
*/
int
OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
void *buf;
if(st == 0 || (str == 0 && len)) {
errno = EINVAL;
return -1;
}
/*
* Clear the OCTET STRING.
*/
if(str == NULL) {
FREEMEM(st->buf);
st->buf = 0;
st->size = 0;
return 0;
}
/* Determine the original string size, if not explicitly given */
if(len < 0)
len = strlen(str);
/* Allocate and fill the memory */
buf = MALLOC(len + 1);
if(buf == NULL)
return -1;
memcpy(buf, str, len);
((uint8_t *)buf)[len] = '\0'; /* Couldn't use memcpy(len+1)! */
FREEMEM(st->buf);
st->buf = (uint8_t *)buf;
st->size = len;
return 0;
}
OCTET_STRING_t *
OCTET_STRING_new_fromBuf(const asn_TYPE_descriptor_t *td, const char *str,
int len) {
const asn_OCTET_STRING_specifics_t *specs =
td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics
: &asn_SPC_OCTET_STRING_specs;
OCTET_STRING_t *st;
st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);
if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
FREEMEM(st);
st = NULL;
}
return st;
}
/*
* Lexicographically compare the common prefix of both strings,
* and if it is the same return -1 for the smallest string.
*/
int
OCTET_STRING_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
const void *bptr) {
const asn_OCTET_STRING_specifics_t *specs = td->specifics;
const OCTET_STRING_t *a = aptr;
const OCTET_STRING_t *b = bptr;
(void)specs;
assert(!specs || specs->subvariant != ASN_OSUBV_BIT);
if(a && b) {
size_t common_prefix_size = a->size <= b->size ? a->size : b->size;
int ret = memcmp(a->buf, b->buf, common_prefix_size);
if(ret == 0) {
/* Figure out which string with equal prefixes is longer. */
if(a->size < b->size) {
return -1;
} else if(a->size > b->size) {
return 1;
} else {
return 0;
}
} else {
return ret < 0 ? -1 : 1;
}
} else if(!a && !b) {
return 0;
} else if(!a) {
return -1;
} else {
return 1;
}
}
#if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT)
int
OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf,
size_t units, unsigned int bpc, unsigned int unit_bits,
long lb, long ub, const asn_per_constraints_t *pc) {
uint8_t *end = buf + units * bpc;
ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d",
(int)units, lb, ub, unit_bits);
/* X.691: 27.5.4 */
if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) {
/* Decode without translation */
lb = 0;
} else if(pc && pc->code2value) {
if(unit_bits > 16)
return 1; /* FATAL: can't have constrained
* UniversalString with more than
* 16 million code points */
for(; buf < end; buf += bpc) {
int value;
int code = per_get_few_bits(po, unit_bits);
if(code < 0) return -1; /* WMORE */
value = pc->code2value(code);
if(value < 0) {
ASN_DEBUG("Code %d (0x%02x) is"
" not in map (%ld..%ld)",
code, code, lb, ub);
return 1; /* FATAL */
}
switch(bpc) {
case 1: *buf = value; break;
case 2: buf[0] = value >> 8; buf[1] = value; break;
case 4: buf[0] = value >> 24; buf[1] = value >> 16;
buf[2] = value >> 8; buf[3] = value; break;
}
}
return 0;
}
/* Shortcut the no-op copying to the aligned structure */
if(lb == 0 && (unit_bits == 8 * bpc)) {
return per_get_many_bits(po, buf, 0, unit_bits * units);
}
for(; buf < end; buf += bpc) {
int32_t code = per_get_few_bits(po, unit_bits);
int32_t ch = code + lb;
if(code < 0) return -1; /* WMORE */
if(ch > ub) {
ASN_DEBUG("Code %d is out of range (%ld..%ld)",
ch, lb, ub);
return 1; /* FATAL */
}
switch(bpc) {
case 1: *buf = ch; break;
case 2: buf[0] = ch >> 8; buf[1] = ch; break;
case 4: buf[0] = ch >> 24; buf[1] = ch >> 16;
buf[2] = ch >> 8; buf[3] = ch; break;
}
}
return 0;
}
int
OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf,
size_t units, unsigned int bpc, unsigned int unit_bits,
long lb, long ub, const asn_per_constraints_t *pc) {
const uint8_t *end = buf + units * bpc;
ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)",
(int)units, lb, ub, unit_bits, bpc);
/* X.691: 27.5.4 */
if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) {
/* Encode as is */
lb = 0;
} else if(pc && pc->value2code) {
for(; buf < end; buf += bpc) {
int code;
uint32_t value;
switch(bpc) {
case 1: value = *(const uint8_t *)buf; break;
case 2: value = (buf[0] << 8) | buf[1]; break;
case 4: value = (buf[0] << 24) | (buf[1] << 16)
| (buf[2] << 8) | buf[3]; break;
default: return -1;
}
code = pc->value2code(value);
if(code < 0) {
ASN_DEBUG("Character %d (0x%02x) is"
" not in map (%ld..%ld)",
*buf, *buf, lb, ub);
return -1;
}
if(per_put_few_bits(po, code, unit_bits))
return -1;
}
}
/* Shortcut the no-op copying to the aligned structure */
if(lb == 0 && (unit_bits == 8 * bpc)) {
return per_put_many_bits(po, buf, unit_bits * units);
}
for(ub -= lb; buf < end; buf += bpc) {
int ch;
uint32_t value;
switch(bpc) {
case 1:
value = *(const uint8_t *)buf;
break;
case 2:
value = (buf[0] << 8) | buf[1];
break;
case 4:
value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
break;
default:
return -1;
}
ch = value - lb;
if(ch < 0 || ch > ub) {
ASN_DEBUG("Character %d (0x%02x) is out of range (%ld..%ld)", *buf,
value, lb, ub + lb);
return -1;
}
if(per_put_few_bits(po, ch, unit_bits)) return -1;
}
return 0;
}
#endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */