xref: /freebsd/lib/libiconv_modules/UES/citrus_ues.c (revision 2a63c3be158216222d89a073dcbd6a72ee4aab5a)
19ca40936STijl Coosemans /* $NetBSD: citrus_ues.c,v 1.3 2012/02/12 13:51:29 wiz Exp $ */
2ad30f8e7SGabor Kovesdan 
3ad30f8e7SGabor Kovesdan /*-
4*5e53a4f9SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause
5*5e53a4f9SPedro F. Giffuni  *
6ad30f8e7SGabor Kovesdan  * Copyright (c)2006 Citrus Project,
7ad30f8e7SGabor Kovesdan  * All rights reserved.
8ad30f8e7SGabor Kovesdan  *
9ad30f8e7SGabor Kovesdan  * Redistribution and use in source and binary forms, with or without
10ad30f8e7SGabor Kovesdan  * modification, are permitted provided that the following conditions
11ad30f8e7SGabor Kovesdan  * are met:
12ad30f8e7SGabor Kovesdan  * 1. Redistributions of source code must retain the above copyright
13ad30f8e7SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer.
14ad30f8e7SGabor Kovesdan  * 2. Redistributions in binary form must reproduce the above copyright
15ad30f8e7SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer in the
16ad30f8e7SGabor Kovesdan  *    documentation and/or other materials provided with the distribution.
17ad30f8e7SGabor Kovesdan  *
18ad30f8e7SGabor Kovesdan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19ad30f8e7SGabor Kovesdan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20ad30f8e7SGabor Kovesdan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21ad30f8e7SGabor Kovesdan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22ad30f8e7SGabor Kovesdan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23ad30f8e7SGabor Kovesdan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24ad30f8e7SGabor Kovesdan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25ad30f8e7SGabor Kovesdan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26ad30f8e7SGabor Kovesdan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27ad30f8e7SGabor Kovesdan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28ad30f8e7SGabor Kovesdan  * SUCH DAMAGE.
29ad30f8e7SGabor Kovesdan  */
30ad30f8e7SGabor Kovesdan 
31ad30f8e7SGabor Kovesdan #include <sys/cdefs.h>
32ad30f8e7SGabor Kovesdan 
33ad30f8e7SGabor Kovesdan #include <assert.h>
34ad30f8e7SGabor Kovesdan #include <errno.h>
35ad30f8e7SGabor Kovesdan #include <limits.h>
36ad30f8e7SGabor Kovesdan #include <stdio.h>
37ad30f8e7SGabor Kovesdan #include <stdint.h>
38ad30f8e7SGabor Kovesdan #include <stdlib.h>
39ad30f8e7SGabor Kovesdan #include <string.h>
40ad30f8e7SGabor Kovesdan #include <wchar.h>
41ad30f8e7SGabor Kovesdan 
42ad30f8e7SGabor Kovesdan #include "citrus_namespace.h"
43ad30f8e7SGabor Kovesdan #include "citrus_types.h"
44ad30f8e7SGabor Kovesdan #include "citrus_bcs.h"
45ad30f8e7SGabor Kovesdan #include "citrus_module.h"
46ad30f8e7SGabor Kovesdan #include "citrus_stdenc.h"
47ad30f8e7SGabor Kovesdan #include "citrus_ues.h"
48ad30f8e7SGabor Kovesdan 
49ad30f8e7SGabor Kovesdan typedef struct {
50ad30f8e7SGabor Kovesdan 	size_t	 mb_cur_max;
51ad30f8e7SGabor Kovesdan 	int	 mode;
52ad30f8e7SGabor Kovesdan #define MODE_C99	1
53ad30f8e7SGabor Kovesdan } _UESEncodingInfo;
54ad30f8e7SGabor Kovesdan 
55ad30f8e7SGabor Kovesdan typedef struct {
56ad30f8e7SGabor Kovesdan 	int	 chlen;
57ad30f8e7SGabor Kovesdan 	char	 ch[12];
58ad30f8e7SGabor Kovesdan } _UESState;
59ad30f8e7SGabor Kovesdan 
60ad30f8e7SGabor Kovesdan #define _CEI_TO_EI(_cei_)               (&(_cei_)->ei)
61ad30f8e7SGabor Kovesdan #define _CEI_TO_STATE(_cei_, _func_)    (_cei_)->states.s_##_func_
62ad30f8e7SGabor Kovesdan 
63ad30f8e7SGabor Kovesdan #define _FUNCNAME(m)			_citrus_UES_##m
64ad30f8e7SGabor Kovesdan #define _ENCODING_INFO			_UESEncodingInfo
65ad30f8e7SGabor Kovesdan #define _ENCODING_STATE			_UESState
66ad30f8e7SGabor Kovesdan #define _ENCODING_MB_CUR_MAX(_ei_)	(_ei_)->mb_cur_max
67ad30f8e7SGabor Kovesdan #define _ENCODING_IS_STATE_DEPENDENT		0
68ad30f8e7SGabor Kovesdan #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)	0
69ad30f8e7SGabor Kovesdan 
70ad30f8e7SGabor Kovesdan static __inline void
71ad30f8e7SGabor Kovesdan /*ARGSUSED*/
_citrus_UES_init_state(_UESEncodingInfo * __restrict ei __unused,_UESState * __restrict psenc)72ad30f8e7SGabor Kovesdan _citrus_UES_init_state(_UESEncodingInfo * __restrict ei __unused,
73ad30f8e7SGabor Kovesdan     _UESState * __restrict psenc)
74ad30f8e7SGabor Kovesdan {
75ad30f8e7SGabor Kovesdan 
76ad30f8e7SGabor Kovesdan 	psenc->chlen = 0;
77ad30f8e7SGabor Kovesdan }
78ad30f8e7SGabor Kovesdan 
79b61949ddSDimitry Andric #if 0
80ad30f8e7SGabor Kovesdan static __inline void
81ad30f8e7SGabor Kovesdan /*ARGSUSED*/
82ad30f8e7SGabor Kovesdan _citrus_UES_pack_state(_UESEncodingInfo * __restrict ei __unused,
83ad30f8e7SGabor Kovesdan     void *__restrict pspriv, const _UESState * __restrict psenc)
84ad30f8e7SGabor Kovesdan {
85ad30f8e7SGabor Kovesdan 
86ad30f8e7SGabor Kovesdan 	memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
87ad30f8e7SGabor Kovesdan }
88ad30f8e7SGabor Kovesdan 
89ad30f8e7SGabor Kovesdan static __inline void
90ad30f8e7SGabor Kovesdan /*ARGSUSED*/
91ad30f8e7SGabor Kovesdan _citrus_UES_unpack_state(_UESEncodingInfo * __restrict ei __unused,
92ad30f8e7SGabor Kovesdan     _UESState * __restrict psenc, const void * __restrict pspriv)
93ad30f8e7SGabor Kovesdan {
94ad30f8e7SGabor Kovesdan 
95ad30f8e7SGabor Kovesdan 	memcpy((void *)psenc, pspriv, sizeof(*psenc));
96ad30f8e7SGabor Kovesdan }
97b61949ddSDimitry Andric #endif
98ad30f8e7SGabor Kovesdan 
99ad30f8e7SGabor Kovesdan static __inline int
to_int(int ch)100ad30f8e7SGabor Kovesdan to_int(int ch)
101ad30f8e7SGabor Kovesdan {
102ad30f8e7SGabor Kovesdan 
103ad30f8e7SGabor Kovesdan 	if (ch >= '0' && ch <= '9')
104ad30f8e7SGabor Kovesdan 		return (ch - '0');
105ad30f8e7SGabor Kovesdan 	else if (ch >= 'A' && ch <= 'F')
106ad30f8e7SGabor Kovesdan 		return ((ch - 'A') + 10);
107ad30f8e7SGabor Kovesdan 	else if (ch >= 'a' && ch <= 'f')
108ad30f8e7SGabor Kovesdan 		return ((ch - 'a') + 10);
109ad30f8e7SGabor Kovesdan 	return (-1);
110ad30f8e7SGabor Kovesdan }
111ad30f8e7SGabor Kovesdan 
112ad30f8e7SGabor Kovesdan #define ESCAPE		'\\'
113ad30f8e7SGabor Kovesdan #define UCS2_ESC	'u'
114ad30f8e7SGabor Kovesdan #define UCS4_ESC	'U'
115ad30f8e7SGabor Kovesdan 
116ad30f8e7SGabor Kovesdan #define UCS2_BIT	16
117ad30f8e7SGabor Kovesdan #define UCS4_BIT	32
118ad30f8e7SGabor Kovesdan #define BMP_MAX		UINT32_C(0xFFFF)
119ad30f8e7SGabor Kovesdan #define UCS2_MAX	UINT32_C(0x10FFFF)
120ad30f8e7SGabor Kovesdan #define UCS4_MAX	UINT32_C(0x7FFFFFFF)
121ad30f8e7SGabor Kovesdan 
122ad30f8e7SGabor Kovesdan static const char *xdig = "0123456789abcdef";
123ad30f8e7SGabor Kovesdan 
124ad30f8e7SGabor Kovesdan static __inline int
to_str(char * s,wchar_t wc,int bit)125ad30f8e7SGabor Kovesdan to_str(char *s, wchar_t wc, int bit)
126ad30f8e7SGabor Kovesdan {
127ad30f8e7SGabor Kovesdan 	char *p;
128ad30f8e7SGabor Kovesdan 
129ad30f8e7SGabor Kovesdan 	p = s;
130ad30f8e7SGabor Kovesdan 	*p++ = ESCAPE;
131ad30f8e7SGabor Kovesdan 	switch (bit) {
132ad30f8e7SGabor Kovesdan 	case UCS2_BIT:
133ad30f8e7SGabor Kovesdan 		*p++ = UCS2_ESC;
134ad30f8e7SGabor Kovesdan 		break;
135ad30f8e7SGabor Kovesdan 	case UCS4_BIT:
136ad30f8e7SGabor Kovesdan 		*p++ = UCS4_ESC;
137ad30f8e7SGabor Kovesdan 		break;
138ad30f8e7SGabor Kovesdan 	default:
139ad30f8e7SGabor Kovesdan 		abort();
140ad30f8e7SGabor Kovesdan 	}
141ad30f8e7SGabor Kovesdan 	do {
142ad30f8e7SGabor Kovesdan 		*p++ = xdig[(wc >> (bit -= 4)) & 0xF];
143ad30f8e7SGabor Kovesdan 	} while (bit > 0);
144ad30f8e7SGabor Kovesdan 	return (p - s);
145ad30f8e7SGabor Kovesdan }
146ad30f8e7SGabor Kovesdan 
147ad30f8e7SGabor Kovesdan static __inline bool
is_hi_surrogate(wchar_t wc)148ad30f8e7SGabor Kovesdan is_hi_surrogate(wchar_t wc)
149ad30f8e7SGabor Kovesdan {
150ad30f8e7SGabor Kovesdan 
151ad30f8e7SGabor Kovesdan 	return (wc >= 0xD800 && wc <= 0xDBFF);
152ad30f8e7SGabor Kovesdan }
153ad30f8e7SGabor Kovesdan 
154ad30f8e7SGabor Kovesdan static __inline bool
is_lo_surrogate(wchar_t wc)155ad30f8e7SGabor Kovesdan is_lo_surrogate(wchar_t wc)
156ad30f8e7SGabor Kovesdan {
157ad30f8e7SGabor Kovesdan 
158ad30f8e7SGabor Kovesdan 	return (wc >= 0xDC00 && wc <= 0xDFFF);
159ad30f8e7SGabor Kovesdan }
160ad30f8e7SGabor Kovesdan 
161ad30f8e7SGabor Kovesdan static __inline wchar_t
surrogate_to_ucs(wchar_t hi,wchar_t lo)162ad30f8e7SGabor Kovesdan surrogate_to_ucs(wchar_t hi, wchar_t lo)
163ad30f8e7SGabor Kovesdan {
164ad30f8e7SGabor Kovesdan 
165ad30f8e7SGabor Kovesdan 	hi -= 0xD800;
166ad30f8e7SGabor Kovesdan 	lo -= 0xDC00;
167ad30f8e7SGabor Kovesdan 	return ((hi << 10 | lo) + 0x10000);
168ad30f8e7SGabor Kovesdan }
169ad30f8e7SGabor Kovesdan 
170ad30f8e7SGabor Kovesdan static __inline void
ucs_to_surrogate(wchar_t wc,wchar_t * __restrict hi,wchar_t * __restrict lo)171ad30f8e7SGabor Kovesdan ucs_to_surrogate(wchar_t wc, wchar_t * __restrict hi, wchar_t * __restrict lo)
172ad30f8e7SGabor Kovesdan {
173ad30f8e7SGabor Kovesdan 
174ad30f8e7SGabor Kovesdan 	wc -= 0x10000;
175ad30f8e7SGabor Kovesdan 	*hi = (wc >> 10) + 0xD800;
176ad30f8e7SGabor Kovesdan 	*lo = (wc & 0x3FF) + 0xDC00;
177ad30f8e7SGabor Kovesdan }
178ad30f8e7SGabor Kovesdan 
179ad30f8e7SGabor Kovesdan static __inline bool
is_basic(wchar_t wc)180ad30f8e7SGabor Kovesdan is_basic(wchar_t wc)
181ad30f8e7SGabor Kovesdan {
182ad30f8e7SGabor Kovesdan 
183ad30f8e7SGabor Kovesdan 	return ((uint32_t)wc <= 0x9F && wc != 0x24 && wc != 0x40 &&
184ad30f8e7SGabor Kovesdan 	    wc != 0x60);
185ad30f8e7SGabor Kovesdan }
186ad30f8e7SGabor Kovesdan 
187ad30f8e7SGabor Kovesdan static int
_citrus_UES_mbrtowc_priv(_UESEncodingInfo * __restrict ei,wchar_t * __restrict pwc,char ** __restrict s,size_t n,_UESState * __restrict psenc,size_t * __restrict nresult)188ad30f8e7SGabor Kovesdan _citrus_UES_mbrtowc_priv(_UESEncodingInfo * __restrict ei,
1891243a98eSTijl Coosemans     wchar_t * __restrict pwc, char ** __restrict s, size_t n,
190ad30f8e7SGabor Kovesdan     _UESState * __restrict psenc, size_t * __restrict nresult)
191ad30f8e7SGabor Kovesdan {
1921243a98eSTijl Coosemans 	char *s0;
193ad30f8e7SGabor Kovesdan 	int ch, head, num, tail;
194ad30f8e7SGabor Kovesdan 	wchar_t hi, wc;
195ad30f8e7SGabor Kovesdan 
196ad30f8e7SGabor Kovesdan 	if (*s == NULL) {
197ad30f8e7SGabor Kovesdan 		_citrus_UES_init_state(ei, psenc);
198ad30f8e7SGabor Kovesdan 		*nresult = 0;
199ad30f8e7SGabor Kovesdan 		return (0);
200ad30f8e7SGabor Kovesdan 	}
201ad30f8e7SGabor Kovesdan 	s0 = *s;
202ad30f8e7SGabor Kovesdan 
203ad30f8e7SGabor Kovesdan 	hi = (wchar_t)0;
204ad30f8e7SGabor Kovesdan 	tail = 0;
205ad30f8e7SGabor Kovesdan 
206ad30f8e7SGabor Kovesdan surrogate:
207ad30f8e7SGabor Kovesdan 	wc = (wchar_t)0;
208ad30f8e7SGabor Kovesdan 	head = tail;
209ad30f8e7SGabor Kovesdan 	if (psenc->chlen == head) {
210ad30f8e7SGabor Kovesdan 		if (n-- < 1)
211ad30f8e7SGabor Kovesdan 			goto restart;
212ad30f8e7SGabor Kovesdan 		psenc->ch[psenc->chlen++] = *s0++;
213ad30f8e7SGabor Kovesdan 	}
214ad30f8e7SGabor Kovesdan 	ch = (unsigned char)psenc->ch[head++];
215ad30f8e7SGabor Kovesdan 	if (ch == ESCAPE) {
216ad30f8e7SGabor Kovesdan 		if (psenc->chlen == head) {
217ad30f8e7SGabor Kovesdan 			if (n-- < 1)
218ad30f8e7SGabor Kovesdan 				goto restart;
219ad30f8e7SGabor Kovesdan 			psenc->ch[psenc->chlen++] = *s0++;
220ad30f8e7SGabor Kovesdan 		}
221ad30f8e7SGabor Kovesdan 		switch (psenc->ch[head]) {
222ad30f8e7SGabor Kovesdan 		case UCS2_ESC:
223ad30f8e7SGabor Kovesdan 			tail += 6;
224ad30f8e7SGabor Kovesdan 			break;
225ad30f8e7SGabor Kovesdan 		case UCS4_ESC:
226ad30f8e7SGabor Kovesdan 			if (ei->mode & MODE_C99) {
227ad30f8e7SGabor Kovesdan 				tail = 10;
228ad30f8e7SGabor Kovesdan 				break;
229ad30f8e7SGabor Kovesdan 			}
230ad30f8e7SGabor Kovesdan 		/*FALLTHROUGH*/
231ad30f8e7SGabor Kovesdan 		default:
232ad30f8e7SGabor Kovesdan 			tail = 0;
233ad30f8e7SGabor Kovesdan 		}
234ad30f8e7SGabor Kovesdan 		++head;
235ad30f8e7SGabor Kovesdan 	}
236ad30f8e7SGabor Kovesdan 	for (; head < tail; ++head) {
237ad30f8e7SGabor Kovesdan 		if (psenc->chlen == head) {
238ad30f8e7SGabor Kovesdan 			if (n-- < 1) {
239ad30f8e7SGabor Kovesdan restart:
240ad30f8e7SGabor Kovesdan 				*s = s0;
241ad30f8e7SGabor Kovesdan 				*nresult = (size_t)-2;
242ad30f8e7SGabor Kovesdan 				return (0);
243ad30f8e7SGabor Kovesdan 			}
244ad30f8e7SGabor Kovesdan 			psenc->ch[psenc->chlen++] = *s0++;
245ad30f8e7SGabor Kovesdan 		}
246ad30f8e7SGabor Kovesdan 		num = to_int((int)(unsigned char)psenc->ch[head]);
247ad30f8e7SGabor Kovesdan 		if (num < 0) {
248ad30f8e7SGabor Kovesdan 			tail = 0;
249ad30f8e7SGabor Kovesdan 			break;
250ad30f8e7SGabor Kovesdan 		}
251ad30f8e7SGabor Kovesdan 		wc = (wc << 4) | num;
252ad30f8e7SGabor Kovesdan 	}
253ad30f8e7SGabor Kovesdan 	head = 0;
254ad30f8e7SGabor Kovesdan 	switch (tail) {
255ad30f8e7SGabor Kovesdan 	case 0:
256ad30f8e7SGabor Kovesdan 		break;
257ad30f8e7SGabor Kovesdan 	case 6:
258ad30f8e7SGabor Kovesdan 		if (hi != (wchar_t)0)
259ad30f8e7SGabor Kovesdan 			break;
260ad30f8e7SGabor Kovesdan 		if ((ei->mode & MODE_C99) == 0) {
261ad30f8e7SGabor Kovesdan 			if (is_hi_surrogate(wc) != 0) {
262ad30f8e7SGabor Kovesdan 				hi = wc;
263ad30f8e7SGabor Kovesdan 				goto surrogate;
264ad30f8e7SGabor Kovesdan 			}
265ad30f8e7SGabor Kovesdan 			if ((uint32_t)wc <= 0x7F /* XXX */ ||
266ad30f8e7SGabor Kovesdan 			    is_lo_surrogate(wc) != 0)
267ad30f8e7SGabor Kovesdan 				break;
268ad30f8e7SGabor Kovesdan 			goto done;
269ad30f8e7SGabor Kovesdan 		}
270ad30f8e7SGabor Kovesdan 	/*FALLTHROUGH*/
271ad30f8e7SGabor Kovesdan 	case 10:
272ad30f8e7SGabor Kovesdan 		if (is_basic(wc) == 0 && (uint32_t)wc <= UCS4_MAX &&
273ad30f8e7SGabor Kovesdan 		    is_hi_surrogate(wc) == 0 && is_lo_surrogate(wc) == 0)
274ad30f8e7SGabor Kovesdan 			goto done;
275ad30f8e7SGabor Kovesdan 		*nresult = (size_t)-1;
276ad30f8e7SGabor Kovesdan 		return (EILSEQ);
277ad30f8e7SGabor Kovesdan 	case 12:
278ad30f8e7SGabor Kovesdan 		if (is_lo_surrogate(wc) == 0)
279ad30f8e7SGabor Kovesdan 			break;
280ad30f8e7SGabor Kovesdan 		wc = surrogate_to_ucs(hi, wc);
281ad30f8e7SGabor Kovesdan 		goto done;
282ad30f8e7SGabor Kovesdan 	}
283ad30f8e7SGabor Kovesdan 	ch = (unsigned char)psenc->ch[0];
284ad30f8e7SGabor Kovesdan 	head = psenc->chlen;
285ad30f8e7SGabor Kovesdan 	if (--head > 0)
286ad30f8e7SGabor Kovesdan 		memmove(&psenc->ch[0], &psenc->ch[1], head);
287ad30f8e7SGabor Kovesdan 	wc = (wchar_t)ch;
288ad30f8e7SGabor Kovesdan done:
289ad30f8e7SGabor Kovesdan 	psenc->chlen = head;
290ad30f8e7SGabor Kovesdan 	if (pwc != NULL)
291ad30f8e7SGabor Kovesdan 		*pwc = wc;
292ad30f8e7SGabor Kovesdan 	*nresult = (size_t)((wc == 0) ? 0 : (s0 - *s));
293ad30f8e7SGabor Kovesdan 	*s = s0;
294ad30f8e7SGabor Kovesdan 
295ad30f8e7SGabor Kovesdan 	return (0);
296ad30f8e7SGabor Kovesdan }
297ad30f8e7SGabor Kovesdan 
298ad30f8e7SGabor Kovesdan static int
_citrus_UES_wcrtomb_priv(_UESEncodingInfo * __restrict ei,char * __restrict s,size_t n,wchar_t wc,_UESState * __restrict psenc,size_t * __restrict nresult)299ad30f8e7SGabor Kovesdan _citrus_UES_wcrtomb_priv(_UESEncodingInfo * __restrict ei,
300ad30f8e7SGabor Kovesdan     char * __restrict s, size_t n, wchar_t wc,
301ad30f8e7SGabor Kovesdan     _UESState * __restrict psenc, size_t * __restrict nresult)
302ad30f8e7SGabor Kovesdan {
303ad30f8e7SGabor Kovesdan 	wchar_t hi, lo;
304ad30f8e7SGabor Kovesdan 
305ad30f8e7SGabor Kovesdan 	if (psenc->chlen != 0)
306ad30f8e7SGabor Kovesdan 		return (EINVAL);
307ad30f8e7SGabor Kovesdan 
308ad30f8e7SGabor Kovesdan 	if ((ei->mode & MODE_C99) ? is_basic(wc) : (uint32_t)wc <= 0x7F) {
309ad30f8e7SGabor Kovesdan 		if (n-- < 1)
310ad30f8e7SGabor Kovesdan 			goto e2big;
311ad30f8e7SGabor Kovesdan 		psenc->ch[psenc->chlen++] = (char)wc;
312ad30f8e7SGabor Kovesdan 	} else if ((uint32_t)wc <= BMP_MAX) {
313ad30f8e7SGabor Kovesdan 		if (n < 6)
314ad30f8e7SGabor Kovesdan 			goto e2big;
315ad30f8e7SGabor Kovesdan 		psenc->chlen = to_str(&psenc->ch[0], wc, UCS2_BIT);
316ad30f8e7SGabor Kovesdan 	} else if ((ei->mode & MODE_C99) == 0 && (uint32_t)wc <= UCS2_MAX) {
317ad30f8e7SGabor Kovesdan 		if (n < 12)
318ad30f8e7SGabor Kovesdan 			goto e2big;
319ad30f8e7SGabor Kovesdan 		ucs_to_surrogate(wc, &hi, &lo);
320ad30f8e7SGabor Kovesdan 		psenc->chlen += to_str(&psenc->ch[0], hi, UCS2_BIT);
321ad30f8e7SGabor Kovesdan 		psenc->chlen += to_str(&psenc->ch[6], lo, UCS2_BIT);
322ad30f8e7SGabor Kovesdan 	} else if ((ei->mode & MODE_C99) && (uint32_t)wc <= UCS4_MAX) {
323ad30f8e7SGabor Kovesdan 		if (n < 10)
324ad30f8e7SGabor Kovesdan 			goto e2big;
325ad30f8e7SGabor Kovesdan 		psenc->chlen = to_str(&psenc->ch[0], wc, UCS4_BIT);
326ad30f8e7SGabor Kovesdan 	} else {
327ad30f8e7SGabor Kovesdan 		*nresult = (size_t)-1;
328ad30f8e7SGabor Kovesdan 		return (EILSEQ);
329ad30f8e7SGabor Kovesdan 	}
330ad30f8e7SGabor Kovesdan 	memcpy(s, psenc->ch, psenc->chlen);
331ad30f8e7SGabor Kovesdan 	*nresult = psenc->chlen;
332ad30f8e7SGabor Kovesdan 	psenc->chlen = 0;
333ad30f8e7SGabor Kovesdan 
334ad30f8e7SGabor Kovesdan 	return (0);
335ad30f8e7SGabor Kovesdan 
336ad30f8e7SGabor Kovesdan e2big:
337ad30f8e7SGabor Kovesdan 	*nresult = (size_t)-1;
338ad30f8e7SGabor Kovesdan 	return (E2BIG);
339ad30f8e7SGabor Kovesdan }
340ad30f8e7SGabor Kovesdan 
341ad30f8e7SGabor Kovesdan /*ARGSUSED*/
342ad30f8e7SGabor Kovesdan static int
_citrus_UES_stdenc_wctocs(_UESEncodingInfo * __restrict ei __unused,_csid_t * __restrict csid,_index_t * __restrict idx,wchar_t wc)343ad30f8e7SGabor Kovesdan _citrus_UES_stdenc_wctocs(_UESEncodingInfo * __restrict ei __unused,
344ad30f8e7SGabor Kovesdan     _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
345ad30f8e7SGabor Kovesdan {
346ad30f8e7SGabor Kovesdan 
347ad30f8e7SGabor Kovesdan 	*csid = 0;
348ad30f8e7SGabor Kovesdan 	*idx = (_index_t)wc;
349ad30f8e7SGabor Kovesdan 
350ad30f8e7SGabor Kovesdan 	return (0);
351ad30f8e7SGabor Kovesdan }
352ad30f8e7SGabor Kovesdan 
353ad30f8e7SGabor Kovesdan static __inline int
354ad30f8e7SGabor Kovesdan /*ARGSUSED*/
_citrus_UES_stdenc_cstowc(_UESEncodingInfo * __restrict ei __unused,wchar_t * __restrict wc,_csid_t csid,_index_t idx)355ad30f8e7SGabor Kovesdan _citrus_UES_stdenc_cstowc(_UESEncodingInfo * __restrict ei __unused,
356ad30f8e7SGabor Kovesdan     wchar_t * __restrict wc, _csid_t csid, _index_t idx)
357ad30f8e7SGabor Kovesdan {
358ad30f8e7SGabor Kovesdan 
359ad30f8e7SGabor Kovesdan 	if (csid != 0)
360ad30f8e7SGabor Kovesdan 		return (EILSEQ);
361ad30f8e7SGabor Kovesdan 	*wc = (wchar_t)idx;
362ad30f8e7SGabor Kovesdan 
363ad30f8e7SGabor Kovesdan 	return (0);
364ad30f8e7SGabor Kovesdan }
365ad30f8e7SGabor Kovesdan 
366ad30f8e7SGabor Kovesdan static __inline int
367ad30f8e7SGabor Kovesdan /*ARGSUSED*/
_citrus_UES_stdenc_get_state_desc_generic(_UESEncodingInfo * __restrict ei __unused,_UESState * __restrict psenc,int * __restrict rstate)368ad30f8e7SGabor Kovesdan _citrus_UES_stdenc_get_state_desc_generic(_UESEncodingInfo * __restrict ei __unused,
369ad30f8e7SGabor Kovesdan     _UESState * __restrict psenc, int * __restrict rstate)
370ad30f8e7SGabor Kovesdan {
371ad30f8e7SGabor Kovesdan 
372ad30f8e7SGabor Kovesdan 	*rstate = (psenc->chlen == 0) ? _STDENC_SDGEN_INITIAL :
373ad30f8e7SGabor Kovesdan 	    _STDENC_SDGEN_INCOMPLETE_CHAR;
374ad30f8e7SGabor Kovesdan 	return (0);
375ad30f8e7SGabor Kovesdan }
376ad30f8e7SGabor Kovesdan 
377ad30f8e7SGabor Kovesdan static void
378ad30f8e7SGabor Kovesdan /*ARGSUSED*/
_citrus_UES_encoding_module_uninit(_UESEncodingInfo * ei __unused)379ad30f8e7SGabor Kovesdan _citrus_UES_encoding_module_uninit(_UESEncodingInfo *ei __unused)
380ad30f8e7SGabor Kovesdan {
381ad30f8e7SGabor Kovesdan 
382ad30f8e7SGabor Kovesdan 	/* ei seems to be unused */
383ad30f8e7SGabor Kovesdan }
384ad30f8e7SGabor Kovesdan 
385ad30f8e7SGabor Kovesdan static int
386ad30f8e7SGabor Kovesdan /*ARGSUSED*/
_citrus_UES_encoding_module_init(_UESEncodingInfo * __restrict ei,const void * __restrict var,size_t lenvar)387ad30f8e7SGabor Kovesdan _citrus_UES_encoding_module_init(_UESEncodingInfo * __restrict ei,
388ad30f8e7SGabor Kovesdan     const void * __restrict var, size_t lenvar)
389ad30f8e7SGabor Kovesdan {
390ad30f8e7SGabor Kovesdan 	const char *p;
391ad30f8e7SGabor Kovesdan 
392ad30f8e7SGabor Kovesdan 	p = var;
393ad30f8e7SGabor Kovesdan 	memset((void *)ei, 0, sizeof(*ei));
394ad30f8e7SGabor Kovesdan 	while (lenvar > 0) {
395ad30f8e7SGabor Kovesdan 		switch (_bcs_toupper(*p)) {
396ad30f8e7SGabor Kovesdan 		case 'C':
397ad30f8e7SGabor Kovesdan 			MATCH(C99, ei->mode |= MODE_C99);
398ad30f8e7SGabor Kovesdan 			break;
399ad30f8e7SGabor Kovesdan 		}
400ad30f8e7SGabor Kovesdan 		++p;
401ad30f8e7SGabor Kovesdan 		--lenvar;
402ad30f8e7SGabor Kovesdan 	}
403ad30f8e7SGabor Kovesdan 	ei->mb_cur_max = (ei->mode & MODE_C99) ? 10 : 12;
404ad30f8e7SGabor Kovesdan 
405ad30f8e7SGabor Kovesdan 	return (0);
406ad30f8e7SGabor Kovesdan }
407ad30f8e7SGabor Kovesdan 
408ad30f8e7SGabor Kovesdan /* ----------------------------------------------------------------------
409ad30f8e7SGabor Kovesdan  * public interface for stdenc
410ad30f8e7SGabor Kovesdan  */
411ad30f8e7SGabor Kovesdan 
412ad30f8e7SGabor Kovesdan _CITRUS_STDENC_DECLS(UES);
413ad30f8e7SGabor Kovesdan _CITRUS_STDENC_DEF_OPS(UES);
414ad30f8e7SGabor Kovesdan 
415ad30f8e7SGabor Kovesdan #include "citrus_stdenc_template.h"
416