BMPString.c 5.66 KB
Newer Older
Lev Walkin's avatar
Lev Walkin committed
1
/*-
Lev Walkin's avatar
Lev Walkin committed
2
 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
Lev Walkin's avatar
Lev Walkin committed
3 4
 * Redistribution and modifications are permitted subject to BSD license.
 */
Lev Walkin's avatar
Lev Walkin committed
5
#include <asn_internal.h>
Lev Walkin's avatar
Lev Walkin committed
6
#include <BMPString.h>
Lev Walkin's avatar
Lev Walkin committed
7
#include <UTF8String.h>
Lev Walkin's avatar
Lev Walkin committed
8 9 10 11

/*
 * BMPString basic type description.
 */
12
static const ber_tlv_tag_t asn_DEF_BMPString_tags[] = {
13 14
	(ASN_TAG_CLASS_UNIVERSAL | (30 << 2)),	/* [UNIVERSAL 30] IMPLICIT ...*/
	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))	/* ... OCTET STRING */
Lev Walkin's avatar
Lev Walkin committed
15
};
16
asn_OCTET_STRING_specifics_t asn_SPC_BMPString_specs = {
17 18 19 20
	sizeof(BMPString_t),
	offsetof(BMPString_t, _asn_ctx),
	ASN_OSUBV_U16	/* 16-bits character */
};
Lev Walkin's avatar
Lev Walkin committed
21
static asn_per_constraints_t asn_DEF_BMPString_per_constraints = {
22 23 24 25
	{ APC_CONSTRAINED, 16, 16, 0, 65535 },
	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },
	0, 0
};
26
asn_TYPE_operation_t asn_OP_BMPString = {
Lev Walkin's avatar
Lev Walkin committed
27 28
	OCTET_STRING_free,          /* Implemented in terms of OCTET STRING */
	BMPString_print,
29
	OCTET_STRING_compare,
Lev Walkin's avatar
Lev Walkin committed
30 31 32 33
	OCTET_STRING_decode_ber,
	OCTET_STRING_encode_der,
	BMPString_decode_xer,		/* Convert from UTF-8 */
	BMPString_encode_xer,		/* Convert to UTF-8 */
Lev Walkin's avatar
Lev Walkin committed
34 35 36 37
#ifdef	ASN_DISABLE_OER_SUPPORT
	0,
	0,
#else
38 39
	OCTET_STRING_decode_oer,
	OCTET_STRING_encode_oer,
Lev Walkin's avatar
Lev Walkin committed
40
#endif  /* ASN_DISABLE_OER_SUPPORT */
Lev Walkin's avatar
Lev Walkin committed
41 42 43 44 45 46 47
#ifdef	ASN_DISABLE_PER_SUPPORT
	0,
	0,
#else
	OCTET_STRING_decode_uper,
	OCTET_STRING_encode_uper,
#endif	/* ASN_DISABLE_PER_SUPPORT */
48 49 50 51 52 53
	0	/* Use generic outmost tag fetcher */
};
asn_TYPE_descriptor_t asn_DEF_BMPString = {
	"BMPString",
	"BMPString",
	&asn_OP_BMPString,
54
	BMPString_constraint,
Lev Walkin's avatar
Lev Walkin committed
55 56 57 58 59 60
	asn_DEF_BMPString_tags,
	sizeof(asn_DEF_BMPString_tags)
	  / sizeof(asn_DEF_BMPString_tags[0]) - 1,
	asn_DEF_BMPString_tags,
	sizeof(asn_DEF_BMPString_tags)
	  / sizeof(asn_DEF_BMPString_tags[0]),
Lev Walkin's avatar
Lev Walkin committed
61 62
	0,	/* No OER visible constraints */
	&asn_DEF_BMPString_per_constraints,
Lev Walkin's avatar
Lev Walkin committed
63
	0, 0,	/* No members */
64
	&asn_SPC_BMPString_specs
Lev Walkin's avatar
Lev Walkin committed
65 66
};

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
int
BMPString_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
                           asn_app_constraint_failed_f *ctfailcb,
                           void *app_key) {
    const BMPString_t *st = (const BMPString_t *)sptr;

    if(st && st->buf) {
        if(st->size & 1) {
            ASN__CTFAIL(app_key, td, sptr,
                        "%s: invalid size %zu not divisible by 2 (%s:%d)",
                        td->name, st->size, __FILE__, __LINE__);
            return -1;
        }
    } else {
        ASN__CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name,
                    __FILE__, __LINE__);
        return -1;
    }

    return 0;
}

Lev Walkin's avatar
Lev Walkin committed
89 90 91
/*
 * BMPString specific contents printer.
 */
Lev Walkin's avatar
Lev Walkin committed
92 93
static ssize_t
BMPString__dump(const BMPString_t *st,
Lev Walkin's avatar
Lev Walkin committed
94 95
		asn_app_consume_bytes_f *cb, void *app_key) {
	char scratch[128];			/* Scratchpad buffer */
Lev Walkin's avatar
Lev Walkin committed
96 97 98 99
	char *p = scratch;
	ssize_t wrote = 0;
	uint8_t *ch;
	uint8_t *end;
Lev Walkin's avatar
Lev Walkin committed
100

Lev Walkin's avatar
Lev Walkin committed
101 102 103 104
	ch = st->buf;
	end = (st->buf + st->size);
	for(end--; ch < end; ch += 2) {
		uint16_t wc = (ch[0] << 8) | ch[1];	/* 2 bytes */
Lev Walkin's avatar
Lev Walkin committed
105
		if(sizeof(scratch) - (p - scratch) < 3) {
Lev Walkin's avatar
Lev Walkin committed
106 107
			wrote += p - scratch;
			if(cb(scratch, p - scratch, app_key) < 0)
Lev Walkin's avatar
Lev Walkin committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
				return -1;
			p = scratch;
		}
		if(wc < 0x80) {
			*p++ = (char)wc;
		} else if(wc < 0x800) {
			*p++ = 0xc0 | ((wc >> 6));
			*p++ = 0x80 | ((wc & 0x3f));
		} else {
			*p++ = 0xe0 | ((wc >> 12));
			*p++ = 0x80 | ((wc >> 6) & 0x3f);
			*p++ = 0x80 | ((wc & 0x3f));
		}
	}

Lev Walkin's avatar
Lev Walkin committed
123 124 125 126 127
	wrote += p - scratch;
	if(cb(scratch, p - scratch, app_key) < 0)
		return -1;

	return wrote;
Lev Walkin's avatar
Lev Walkin committed
128
}
Lev Walkin's avatar
Lev Walkin committed
129

Lev Walkin's avatar
Lev Walkin committed
130
asn_dec_rval_t
Lev Walkin's avatar
Lev Walkin committed
131
BMPString_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin's avatar
Lev Walkin committed
132
	asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkin's avatar
Lev Walkin committed
133
		const char *opt_mname, const void *buf_ptr, size_t size) {
Lev Walkin's avatar
Lev Walkin committed
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
	asn_dec_rval_t rc;

	rc = OCTET_STRING_decode_xer_utf8(opt_codec_ctx, td, sptr, opt_mname,
		buf_ptr, size);
	if(rc.code == RC_OK) {
		/*
		 * Now we have a whole string in UTF-8 format.
		 * Convert it into UCS-2.
		 */
		uint32_t *wcs;
		size_t wcs_len;
		UTF8String_t *st;

		assert(*sptr);
		st = (UTF8String_t *)*sptr;
		assert(st->buf);
		wcs_len = UTF8String_to_wcs(st, 0, 0);

		wcs = (uint32_t *)MALLOC(4 * (wcs_len + 1));
		if(wcs == 0 || UTF8String_to_wcs(st, wcs, wcs_len) != wcs_len) {
			rc.code = RC_FAIL;
			rc.consumed = 0;
			return rc;
		} else {
			wcs[wcs_len] = 0;	/* nul-terminate */
		}

		if(1) {
			/* Swap byte order and trim encoding to 2 bytes */
			uint32_t *wc = wcs;
Lev Walkin's avatar
Lev Walkin committed
164
			uint32_t *wc_end = wcs + wcs_len;
Lev Walkin's avatar
Lev Walkin committed
165 166 167 168 169 170 171 172 173 174 175 176
			uint16_t *dstwc = (uint16_t *)wcs;
			for(; wc < wc_end; wc++, dstwc++) {
				uint32_t wch = *wc;
				if(wch > 0xffff) {
					FREEMEM(wcs);
					rc.code = RC_FAIL;
					rc.consumed = 0;
					return rc;
				}
				*((uint8_t *)dstwc + 0) = wch >> 8;
				*((uint8_t *)dstwc + 1) = wch;
			}
Lev Walkin's avatar
typos  
Lev Walkin committed
177
			dstwc = (uint16_t *)REALLOC(wcs, 2 * (wcs_len + 1));
Lev Walkin's avatar
Lev Walkin committed
178 179 180 181 182 183
			if(!dstwc) {
				FREEMEM(wcs);
				rc.code = RC_FAIL;
				rc.consumed = 0;
				return rc;
			} else {
184
				dstwc[wcs_len] = 0;	/* nul-terminate */
Lev Walkin's avatar
Lev Walkin committed
185
				wcs = (uint32_t *)(void *)dstwc; /* Alignment OK */
Lev Walkin's avatar
Lev Walkin committed
186 187 188 189 190 191 192 193 194 195
			}
		}

		FREEMEM(st->buf);
		st->buf = (uint8_t *)wcs;
		st->size = 2 * wcs_len;
	}
	return rc;
}

Lev Walkin's avatar
Lev Walkin committed
196
asn_enc_rval_t
Lev Walkin's avatar
Lev Walkin committed
197
BMPString_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkin's avatar
Lev Walkin committed
198 199 200 201 202 203 204 205 206
	int ilevel, enum xer_encoder_flags_e flags,
		asn_app_consume_bytes_f *cb, void *app_key) {
	const BMPString_t *st = (const BMPString_t *)sptr;
	asn_enc_rval_t er;

	(void)ilevel;
	(void)flags;

	if(!st || !st->buf)
207
		ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
208 209

	er.encoded = BMPString__dump(st, cb, app_key);
210
	if(er.encoded < 0) ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
211

212
	ASN__ENCODED_OK(er);
Lev Walkin's avatar
Lev Walkin committed
213 214 215
}

int
Lev Walkin's avatar
Lev Walkin committed
216
BMPString_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
Lev Walkin's avatar
Lev Walkin committed
217 218 219 220 221 222
		asn_app_consume_bytes_f *cb, void *app_key) {
	const BMPString_t *st = (const BMPString_t *)sptr;

	(void)td;	/* Unused argument */
	(void)ilevel;	/* Unused argument */

223 224
	if(!st || !st->buf)
		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkin's avatar
Lev Walkin committed
225 226 227 228 229 230 231

	if(BMPString__dump(st, cb, app_key) < 0)
		return -1;

	return 0;
}