blob: 7d7cd8b39db4f3e748de15cb1bc693b6f877dce0 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
Lev Walkinc7549b12006-09-17 01:27:44 +00002 * Copyright (c) 2003, 2004, 2006 Lev Walkin <vlm@lionet.info>.
3 * All rights reserved.
Lev Walkinf15320b2004-06-03 03:38:44 +00004 * Redistribution and modifications are permitted subject to BSD license.
5 */
Lev Walkina9cc46e2004-09-22 16:06:28 +00006#include <asn_internal.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00007#include <UTF8String.h>
8
9/*
10 * UTF8String basic type description.
11 */
Wim Lewis18c2ec92014-07-29 11:30:10 -070012static const ber_tlv_tag_t asn_DEF_UTF8String_tags[] = {
Lev Walkin188ed2c2004-09-13 08:31:01 +000013 (ASN_TAG_CLASS_UNIVERSAL | (12 << 2)), /* [UNIVERSAL 12] IMPLICIT ...*/
14 (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)), /* ... OCTET STRING */
Lev Walkinf15320b2004-06-03 03:38:44 +000015};
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +080016asn_TYPE_operation_t asn_OP_UTF8String = {
Lev Walkina9cc46e2004-09-22 16:06:28 +000017 OCTET_STRING_free,
18 UTF8String_print,
Lev Walkincd2f48e2017-08-10 02:14:59 -070019 OCTET_STRING_compare,
Lev Walkinf15320b2004-06-03 03:38:44 +000020 OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */
Lev Walkindc06f6b2004-10-20 15:50:55 +000021 OCTET_STRING_encode_der,
22 OCTET_STRING_decode_xer_utf8,
23 OCTET_STRING_encode_xer_utf8,
Lev Walkincc159472017-07-06 08:26:36 -070024#ifdef ASN_DISABLE_OER_SUPPORT
25 0,
26 0,
27#else
Lev Walkin1d76f3c2017-07-25 07:58:05 -070028 OCTET_STRING_decode_oer,
29 OCTET_STRING_encode_oer,
Lev Walkincc159472017-07-06 08:26:36 -070030#endif /* ASN_DISABLE_OER_SUPPORT */
Lev Walkinb33425f2017-07-14 14:59:52 +040031#ifdef ASN_DISABLE_PER_SUPPORT
32 0,
33 0,
34#else
35 OCTET_STRING_decode_uper,
36 OCTET_STRING_encode_uper,
37#endif /* ASN_DISABLE_PER_SUPPORT */
Lev Walkina5972be2017-09-29 23:15:58 -070038 UTF8String_random_fill,
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +080039 0 /* Use generic outmost tag fetcher */
40};
41asn_TYPE_descriptor_t asn_DEF_UTF8String = {
42 "UTF8String",
43 "UTF8String",
44 &asn_OP_UTF8String,
Lev Walkin5e033762004-09-29 13:26:15 +000045 asn_DEF_UTF8String_tags,
46 sizeof(asn_DEF_UTF8String_tags)
47 / sizeof(asn_DEF_UTF8String_tags[0]) - 1,
48 asn_DEF_UTF8String_tags,
49 sizeof(asn_DEF_UTF8String_tags)
50 / sizeof(asn_DEF_UTF8String_tags[0]),
Lev Walkina5972be2017-09-29 23:15:58 -070051 { 0, 0, UTF8String_constraint },
Lev Walkin449f8322004-08-20 13:23:42 +000052 0, 0, /* No members */
Lev Walkind9bd7752004-06-05 08:17:50 +000053 0 /* No specifics */
Lev Walkinf15320b2004-06-03 03:38:44 +000054};
55
Lev Walkine18ca712004-10-02 11:37:38 +000056/*
57 * This is the table of length expectations.
Lev Walkin6cf9f712005-03-02 13:30:25 +000058 * The second half of this table is only applicable to the long sequences.
Lev Walkine18ca712004-10-02 11:37:38 +000059 */
Wim Lewis18c2ec92014-07-29 11:30:10 -070060static const int UTF8String_ht[2][16] = {
Lev Walkine18ca712004-10-02 11:37:38 +000061 { /* 0x0 ... 0x7 */
62 /* 0000..0111 */
63 1, 1, 1, 1, 1, 1, 1, 1,
64 /* 1000..1011(0), 1100..1101(2), 1110(3), 1111(-1) */
65 0, 0, 0, 0, 2, 2, 3, -1 },
66 { /* 0xF0 .. 0xF7 */
67 /* 11110000..11110111 */
68 4, 4, 4, 4, 4, 4, 4, 4,
69 5, 5, 5, 5, 6, 6, -1, -1 }
Lev Walkinf15320b2004-06-03 03:38:44 +000070};
Wim Lewis18c2ec92014-07-29 11:30:10 -070071static const int32_t UTF8String_mv[7] = { 0, 0,
Lev Walkinedc7d592004-10-02 15:55:07 +000072 0x00000080,
73 0x00000800,
74 0x00010000,
75 0x00200000,
76 0x04000000
77};
78
79/* Internal aliases for return codes */
80#define U8E_TRUNC -1 /* UTF-8 sequence truncated */
81#define U8E_ILLSTART -2 /* Illegal UTF-8 sequence start */
82#define U8E_NOTCONT -3 /* Continuation expectation failed */
83#define U8E_NOTMIN -4 /* Not minimal length encoding */
84#define U8E_EINVAL -5 /* Invalid arguments */
Lev Walkinf15320b2004-06-03 03:38:44 +000085
86int
Lev Walkin5e033762004-09-29 13:26:15 +000087UTF8String_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
Lev Walkin1eded352006-07-13 11:19:01 +000088 asn_app_constraint_failed_f *ctfailcb, void *app_key) {
Lev Walkinedc7d592004-10-02 15:55:07 +000089 ssize_t len = UTF8String_length((const UTF8String_t *)sptr);
90 switch(len) {
91 case U8E_EINVAL:
Lev Walkin7c1dc052016-03-14 03:08:15 -070092 ASN__CTFAIL(app_key, td, sptr,
Lev Walkinedc7d592004-10-02 15:55:07 +000093 "%s: value not given", td->name);
94 break;
95 case U8E_TRUNC:
Lev Walkin7c1dc052016-03-14 03:08:15 -070096 ASN__CTFAIL(app_key, td, sptr,
Lev Walkinedc7d592004-10-02 15:55:07 +000097 "%s: truncated UTF-8 sequence (%s:%d)",
98 td->name, __FILE__, __LINE__);
99 break;
100 case U8E_ILLSTART:
Lev Walkin7c1dc052016-03-14 03:08:15 -0700101 ASN__CTFAIL(app_key, td, sptr,
Lev Walkinedc7d592004-10-02 15:55:07 +0000102 "%s: UTF-8 illegal start of encoding (%s:%d)",
103 td->name, __FILE__, __LINE__);
104 break;
105 case U8E_NOTCONT:
Lev Walkin7c1dc052016-03-14 03:08:15 -0700106 ASN__CTFAIL(app_key, td, sptr,
Lev Walkinedc7d592004-10-02 15:55:07 +0000107 "%s: UTF-8 not continuation (%s:%d)",
108 td->name, __FILE__, __LINE__);
109 break;
110 case U8E_NOTMIN:
Lev Walkin7c1dc052016-03-14 03:08:15 -0700111 ASN__CTFAIL(app_key, td, sptr,
Lev Walkinedc7d592004-10-02 15:55:07 +0000112 "%s: UTF-8 not minimal sequence (%s:%d)",
113 td->name, __FILE__, __LINE__);
114 break;
115 }
116 return (len < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000117}
118
Lev Walkin9a6f65b2004-10-23 11:20:06 +0000119static ssize_t
120UTF8String__process(const UTF8String_t *st, uint32_t *dst, size_t dstlen) {
121 size_t length;
122 uint8_t *buf = st->buf;
123 uint8_t *end = buf + st->size;
Lev Walkinc7549b12006-09-17 01:27:44 +0000124 uint32_t *dstend = dst + dstlen;
Lev Walkinf15320b2004-06-03 03:38:44 +0000125
Lev Walkin9a6f65b2004-10-23 11:20:06 +0000126 for(length = 0; buf < end; length++) {
127 int ch = *buf;
128 uint8_t *cend;
129 int32_t value;
130 int want;
Lev Walkinf15320b2004-06-03 03:38:44 +0000131
Lev Walkin9a6f65b2004-10-23 11:20:06 +0000132 /* Compute the sequence length */
133 want = UTF8String_ht[0][ch >> 4];
134 switch(want) {
135 case -1:
136 /* Second half of the table, long sequence */
137 want = UTF8String_ht[1][ch & 0x0F];
138 if(want != -1) break;
139 /* Fall through */
140 case 0:
141 return U8E_ILLSTART;
Lev Walkinf15320b2004-06-03 03:38:44 +0000142 }
143
Lev Walkin9a6f65b2004-10-23 11:20:06 +0000144 /* assert(want >= 1 && want <= 6) */
145
146 /* Check character sequence length */
147 if(buf + want > end) return U8E_TRUNC;
148
Lev Walkinc7549b12006-09-17 01:27:44 +0000149 value = ch & (0xff >> want);
Lev Walkin9a6f65b2004-10-23 11:20:06 +0000150 cend = buf + want;
151 for(buf++; buf < cend; buf++) {
152 ch = *buf;
153 if(ch < 0x80 || ch > 0xbf) return U8E_NOTCONT;
154 value = (value << 6) | (ch & 0x3F);
155 }
156 if(value < UTF8String_mv[want])
157 return U8E_NOTMIN;
Lev Walkinc7549b12006-09-17 01:27:44 +0000158 if(dst < dstend)
159 *dst++ = value; /* Record value */
Lev Walkin9a6f65b2004-10-23 11:20:06 +0000160 }
161
Lev Walkinc7549b12006-09-17 01:27:44 +0000162 if(dst < dstend) *dst = 0; /* zero-terminate */
Lev Walkin9a6f65b2004-10-23 11:20:06 +0000163
164 return length;
165}
166
167
168ssize_t
169UTF8String_length(const UTF8String_t *st) {
170 if(st && st->buf) {
171 return UTF8String__process(st, 0, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000172 } else {
Lev Walkinedc7d592004-10-02 15:55:07 +0000173 return U8E_EINVAL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000174 }
175}
176
Lev Walkin9a6f65b2004-10-23 11:20:06 +0000177size_t
178UTF8String_to_wcs(const UTF8String_t *st, uint32_t *dst, size_t dstlen) {
179 if(st && st->buf) {
180 ssize_t ret = UTF8String__process(st, dst, dstlen);
181 return (ret < 0) ? 0 : ret;
182 } else {
183 return 0;
184 }
185}
186
Lev Walkinf15320b2004-06-03 03:38:44 +0000187int
Lev Walkin5e033762004-09-29 13:26:15 +0000188UTF8String_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
Lev Walkinf15320b2004-06-03 03:38:44 +0000189 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000190 const UTF8String_t *st = (const UTF8String_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000191
Lev Walkind9bd7752004-06-05 08:17:50 +0000192 (void)td; /* Unused argument */
193 (void)ilevel; /* Unused argument */
194
Lev Walkinf15320b2004-06-03 03:38:44 +0000195 if(st && st->buf) {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000196 return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000197 } else {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000198 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000199 }
200}
Lev Walkina5972be2017-09-29 23:15:58 -0700201
202
203/*
204 * Biased function for randomizing UTF-8 sequences.
205 */
206static uint32_t
207UTF8String__random_char(uint8_t *b, size_t size) {
208 struct rnd_value {
209 const char *value;
210 size_t size;
211 };
212 static const struct rnd_value values[] = {{"\0", 1},
213 {"\x01", 1},
214 {"\x7f", 1},
215 {"\xc2\xa2", 2},
216 {"\xe2\x82\xac", 3},
217 {"\xf0\x90\x8d\x88", 4},
218 {"\xf4\x8f\xbf\xbf", 4}};
219
220 const struct rnd_value *v;
221 size_t max_idx;
222
223 switch(size) {
224 case 0:
225 assert(size != 0);
226 return 0;
227 case 1:
228 max_idx = 2;
229 break;
230 case 2:
231 max_idx = 3;
232 break;
233 case 4:
234 return sizeof(values) / sizeof(values[0]) - 1;
235 }
236
237 v = &values[asn_random_between(0, max_idx)];
238 memcpy(b, v->value, v->size);
239 return v->size;
240}
241
242asn_random_fill_result_t
243UTF8String_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
244 const asn_encoding_constraints_t *constraints,
245 size_t max_length) {
246 asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
247 asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
248 asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
249 static unsigned lengths[] = {0, 1, 2, 3, 4, 8,
250 126, 127, 128, 16383, 16384, 16385,
251 65534, 65535, 65536, 65537};
252 uint8_t *buf;
253 uint8_t *bend;
254 uint8_t *b;
255 size_t rnd_len;
256 size_t idx;
257 UTF8String_t *st;
258
259 (void)td;
260 (void)constraints;
261
262 if(max_length == 0) return result_skipped;
263
264 /* Figure out how far we should go */
265 rnd_len = lengths[asn_random_between(
266 0, sizeof(lengths) / sizeof(lengths[0]) - 1)];
267 if(4 * rnd_len >= max_length) {
268 rnd_len = asn_random_between(0, (max_length - 1) / 4);
269 }
270
271 buf = CALLOC(4, rnd_len + 1);
272 if(!buf) return result_failed;
273
274 bend = &buf[4 * rnd_len];
275
276 for(b = buf, idx = 0; idx < rnd_len; idx++) {
277 b += UTF8String__random_char(b, (bend - b));
278 }
279 *(uint8_t *)b = 0;
280
281 if(*sptr) {
282 st = *sptr;
283 FREEMEM(st->buf);
284 } else {
285 st = (OCTET_STRING_t *)(*sptr = CALLOC(1, sizeof(UTF8String_t)));
286 if(!st) {
287 FREEMEM(buf);
288 return result_failed;
289 }
290 }
291 assert(UTF8String_length(st) == (ssize_t)rnd_len);
292
293 st->buf = buf;
294 st->size = b - buf;
295
296 return result_ok;
297}