1*eda3ef2dSRobert Mustacchi /*
2*eda3ef2dSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*eda3ef2dSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*eda3ef2dSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*eda3ef2dSRobert Mustacchi  * 1.0 of the CDDL.
6*eda3ef2dSRobert Mustacchi  *
7*eda3ef2dSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*eda3ef2dSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*eda3ef2dSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*eda3ef2dSRobert Mustacchi  */
11*eda3ef2dSRobert Mustacchi 
12*eda3ef2dSRobert Mustacchi /*
13*eda3ef2dSRobert Mustacchi  * Copyright 2020 Robert Mustacchi
14*eda3ef2dSRobert Mustacchi  */
15*eda3ef2dSRobert Mustacchi 
16*eda3ef2dSRobert Mustacchi /*
17*eda3ef2dSRobert Mustacchi  * C11 c16rtomb(3C) support.
18*eda3ef2dSRobert Mustacchi  *
19*eda3ef2dSRobert Mustacchi  * Convert a series of char16_t values into a series of multi-byte characters.
20*eda3ef2dSRobert Mustacchi  * We may be given a surrogate value, so we need to potentially store that in
21*eda3ef2dSRobert Mustacchi  * the interim.
22*eda3ef2dSRobert Mustacchi  */
23*eda3ef2dSRobert Mustacchi 
24*eda3ef2dSRobert Mustacchi #include <uchar.h>
25*eda3ef2dSRobert Mustacchi #include <errno.h>
26*eda3ef2dSRobert Mustacchi #include "mblocal.h"
27*eda3ef2dSRobert Mustacchi #include "unicode.h"
28*eda3ef2dSRobert Mustacchi 
29*eda3ef2dSRobert Mustacchi static mbstate_t c16rtomb_state;
30*eda3ef2dSRobert Mustacchi 
31*eda3ef2dSRobert Mustacchi size_t
c16rtomb(char * restrict str,char16_t c16,mbstate_t * restrict ps)32*eda3ef2dSRobert Mustacchi c16rtomb(char *restrict str, char16_t c16, mbstate_t *restrict ps)
33*eda3ef2dSRobert Mustacchi {
34*eda3ef2dSRobert Mustacchi 	char32_t c32;
35*eda3ef2dSRobert Mustacchi 	_CHAR16State *c16s;
36*eda3ef2dSRobert Mustacchi 
37*eda3ef2dSRobert Mustacchi 	if (ps == NULL) {
38*eda3ef2dSRobert Mustacchi 		ps = &c16rtomb_state;
39*eda3ef2dSRobert Mustacchi 	}
40*eda3ef2dSRobert Mustacchi 
41*eda3ef2dSRobert Mustacchi 	if (str == NULL) {
42*eda3ef2dSRobert Mustacchi 		c16 = L'\0';
43*eda3ef2dSRobert Mustacchi 	}
44*eda3ef2dSRobert Mustacchi 
45*eda3ef2dSRobert Mustacchi 	c16s = (_CHAR16State *)ps;
46*eda3ef2dSRobert Mustacchi 	if (c16s->c16_surrogate != 0) {
47*eda3ef2dSRobert Mustacchi 		if (c16 > UNICODE_SUR_MAX || c16 < UNICODE_SUR_MIN ||
48*eda3ef2dSRobert Mustacchi 		    (c16 & UNICODE_SUR_LOWER) != UNICODE_SUR_LOWER) {
49*eda3ef2dSRobert Mustacchi 			errno = EILSEQ;
50*eda3ef2dSRobert Mustacchi 			return ((size_t)-1);
51*eda3ef2dSRobert Mustacchi 		}
52*eda3ef2dSRobert Mustacchi 
53*eda3ef2dSRobert Mustacchi 		c32 = UNICODE_SUR_UVALUE(c16s->c16_surrogate) |
54*eda3ef2dSRobert Mustacchi 		    UNICODE_SUR_LVALUE(c16);
55*eda3ef2dSRobert Mustacchi 		c32 += UNICODE_SUP_START;
56*eda3ef2dSRobert Mustacchi 		c16s->c16_surrogate = 0;
57*eda3ef2dSRobert Mustacchi 	} else if (c16 >= UNICODE_SUR_MIN && c16 <= UNICODE_SUR_MAX) {
58*eda3ef2dSRobert Mustacchi 		/*
59*eda3ef2dSRobert Mustacchi 		 * The lower surrogate pair mask (dc00) overlaps the upper mask
60*eda3ef2dSRobert Mustacchi 		 * (d800), hence why we do a binary and with the upper mask.
61*eda3ef2dSRobert Mustacchi 		 */
62*eda3ef2dSRobert Mustacchi 		if ((c16 & UNICODE_SUR_LOWER) != UNICODE_SUR_UPPER) {
63*eda3ef2dSRobert Mustacchi 			errno = EILSEQ;
64*eda3ef2dSRobert Mustacchi 			return ((size_t)-1);
65*eda3ef2dSRobert Mustacchi 		}
66*eda3ef2dSRobert Mustacchi 
67*eda3ef2dSRobert Mustacchi 		c16s->c16_surrogate = c16;
68*eda3ef2dSRobert Mustacchi 		return (0);
69*eda3ef2dSRobert Mustacchi 	} else {
70*eda3ef2dSRobert Mustacchi 		c32 = c16;
71*eda3ef2dSRobert Mustacchi 	}
72*eda3ef2dSRobert Mustacchi 
73*eda3ef2dSRobert Mustacchi 	/*
74*eda3ef2dSRobert Mustacchi 	 * Call c32rtomb() and not wcrtomb() so that way all of the unicode code
75*eda3ef2dSRobert Mustacchi 	 * point validation is performed.
76*eda3ef2dSRobert Mustacchi 	 */
77*eda3ef2dSRobert Mustacchi 	return (c32rtomb(str, c32, ps));
78*eda3ef2dSRobert Mustacchi }
79