BMPString.c 5.68 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,
30
	BMPString_constraint,
Lev Walkin's avatar
Lev Walkin committed
31 32 33 34
	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
35 36 37 38
#ifdef	ASN_DISABLE_OER_SUPPORT
	0,
	0,
#else
39 40
	OCTET_STRING_decode_oer,
	OCTET_STRING_encode_oer,
Lev Walkin's avatar
Lev Walkin committed
41
#endif  /* ASN_DISABLE_OER_SUPPORT */
Lev Walkin's avatar
Lev Walkin committed
42 43 44 45 46 47 48
#ifdef	ASN_DISABLE_PER_SUPPORT
	0,
	0,
#else
	OCTET_STRING_decode_uper,
	OCTET_STRING_encode_uper,
#endif	/* ASN_DISABLE_PER_SUPPORT */
49 50 51 52 53 54
	0	/* Use generic outmost tag fetcher */
};
asn_TYPE_descriptor_t asn_DEF_BMPString = {
	"BMPString",
	"BMPString",
	&asn_OP_BMPString,
55
	BMPString_constraint,
Lev Walkin's avatar
Lev Walkin committed
56 57 58 59 60 61
	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
62 63
	0,	/* No OER visible constraints */
	&asn_DEF_BMPString_per_constraints,
Lev Walkin's avatar
Lev Walkin committed
64
	0, 0,	/* No members */
65
	&asn_SPC_BMPString_specs
Lev Walkin's avatar
Lev Walkin committed
66 67
};

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
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
90 91 92
/*
 * BMPString specific contents printer.
 */
Lev Walkin's avatar
Lev Walkin committed
93 94
static ssize_t
BMPString__dump(const BMPString_t *st,
Lev Walkin's avatar
Lev Walkin committed
95 96
		asn_app_consume_bytes_f *cb, void *app_key) {
	char scratch[128];			/* Scratchpad buffer */
Lev Walkin's avatar
Lev Walkin committed
97 98 99 100
	char *p = scratch;
	ssize_t wrote = 0;
	uint8_t *ch;
	uint8_t *end;
Lev Walkin's avatar
Lev Walkin committed
101

Lev Walkin's avatar
Lev Walkin committed
102 103 104 105
	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
106
		if(sizeof(scratch) - (p - scratch) < 3) {
Lev Walkin's avatar
Lev Walkin committed
107 108
			wrote += p - scratch;
			if(cb(scratch, p - scratch, app_key) < 0)
Lev Walkin's avatar
Lev Walkin committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
				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
124 125 126 127 128
	wrote += p - scratch;
	if(cb(scratch, p - scratch, app_key) < 0)
		return -1;

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

Lev Walkin's avatar
Lev Walkin committed
131 132 133
asn_dec_rval_t
BMPString_decode_xer(asn_codec_ctx_t *opt_codec_ctx,
	asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkin's avatar
Lev Walkin committed
134
		const char *opt_mname, const void *buf_ptr, size_t size) {
Lev Walkin's avatar
Lev Walkin committed
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 164
	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
165
			uint32_t *wc_end = wcs + wcs_len;
Lev Walkin's avatar
Lev Walkin committed
166 167 168 169 170 171 172 173 174 175 176 177
			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
178
			dstwc = (uint16_t *)REALLOC(wcs, 2 * (wcs_len + 1));
Lev Walkin's avatar
Lev Walkin committed
179 180 181 182 183 184
			if(!dstwc) {
				FREEMEM(wcs);
				rc.code = RC_FAIL;
				rc.consumed = 0;
				return rc;
			} else {
185
				dstwc[wcs_len] = 0;	/* nul-terminate */
Lev Walkin's avatar
Lev Walkin committed
186
				wcs = (uint32_t *)(void *)dstwc; /* Alignment OK */
Lev Walkin's avatar
Lev Walkin committed
187 188 189 190 191 192 193 194 195 196
			}
		}

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

Lev Walkin's avatar
Lev Walkin committed
197
asn_enc_rval_t
Lev Walkin's avatar
Lev Walkin committed
198
BMPString_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkin's avatar
Lev Walkin committed
199 200 201 202 203 204 205 206 207
	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)
208
		ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
209 210

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

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

int
Lev Walkin's avatar
Lev Walkin committed
217
BMPString_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
Lev Walkin's avatar
Lev Walkin committed
218 219 220 221 222 223
		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 */

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

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

	return 0;
}