1185029Spjd/*
2185029Spjd * CDDL HEADER START
3185029Spjd *
4185029Spjd * The contents of this file are subject to the terms of the
5185029Spjd * Common Development and Distribution License (the "License").
6185029Spjd * You may not use this file except in compliance with the License.
7185029Spjd *
8185029Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9185029Spjd * or http://www.opensolaris.org/os/licensing.
10185029Spjd * See the License for the specific language governing permissions
11185029Spjd * and limitations under the License.
12185029Spjd *
13185029Spjd * When distributing Covered Code, include this CDDL HEADER in each
14185029Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15185029Spjd * If applicable, add the following below this CDDL HEADER, with the
16185029Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17185029Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18185029Spjd *
19185029Spjd * CDDL HEADER END
20185029Spjd */
21185029Spjd/*
22185029Spjd * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23185029Spjd * Use is subject to license terms.
24185029Spjd */
25185029Spjd
26185029Spjd#pragma ident	"%Z%%M%	%I%	%E% SMI"
27185029Spjd
28185029Spjd
29185029Spjd/*
30185029Spjd * UTF-8 text preparation functions (PSARC/2007/149, PSARC/2007/458).
31185029Spjd *
32185029Spjd * Man pages: u8_textprep_open(9F), u8_textprep_buf(9F), u8_textprep_close(9F),
33185029Spjd * u8_textprep_str(9F), u8_strcmp(9F), and u8_validate(9F). See also
34185029Spjd * the section 3C man pages.
35185029Spjd * Interface stability: Committed.
36185029Spjd */
37185029Spjd
38185029Spjd#include <sys/types.h>
39185029Spjd#ifdef	_KERNEL
40185029Spjd#include <sys/param.h>
41185029Spjd#include <sys/sysmacros.h>
42185029Spjd#include <sys/systm.h>
43185029Spjd#include <sys/debug.h>
44185029Spjd#include <sys/kmem.h>
45219089Spjd#include <sys/sunddi.h>
46185029Spjd#else
47185029Spjd#include <strings.h>
48185029Spjd#endif	/* _KERNEL */
49185029Spjd#include <sys/byteorder.h>
50185029Spjd#include <sys/errno.h>
51185029Spjd#include <sys/u8_textprep.h>
52185029Spjd#include <sys/u8_textprep_data.h>
53185029Spjd
54185029Spjd
55185029Spjd/* The maximum possible number of bytes in a UTF-8 character. */
56185029Spjd#define	U8_MB_CUR_MAX			(4)
57185029Spjd
58185029Spjd/*
59185029Spjd * The maximum number of bytes needed for a UTF-8 character to cover
60185029Spjd * U+0000 - U+FFFF, i.e., the coding space of now deprecated UCS-2.
61185029Spjd */
62185029Spjd#define	U8_MAX_BYTES_UCS2		(3)
63185029Spjd
64185029Spjd/* The maximum possible number of bytes in a Stream-Safe Text. */
65185029Spjd#define	U8_STREAM_SAFE_TEXT_MAX		(128)
66185029Spjd
67185029Spjd/*
68185029Spjd * The maximum number of characters in a combining/conjoining sequence and
69185029Spjd * the actual upperbound limit of a combining/conjoining sequence.
70185029Spjd */
71185029Spjd#define	U8_MAX_CHARS_A_SEQ		(32)
72185029Spjd#define	U8_UPPER_LIMIT_IN_A_SEQ		(31)
73185029Spjd
74185029Spjd/* The combining class value for Starter. */
75185029Spjd#define	U8_COMBINING_CLASS_STARTER	(0)
76185029Spjd
77185029Spjd/*
78185029Spjd * Some Hangul related macros at below.
79185029Spjd *
80185029Spjd * The first and the last of Hangul syllables, Hangul Jamo Leading consonants,
81185029Spjd * Vowels, and optional Trailing consonants in Unicode scalar values.
82185029Spjd *
83185029Spjd * Please be noted that the U8_HANGUL_JAMO_T_FIRST is 0x11A7 at below not
84185029Spjd * the actual U+11A8. This is due to that the trailing consonant is optional
85185029Spjd * and thus we are doing a pre-calculation of subtracting one.
86185029Spjd *
87185029Spjd * Each of 19 modern leading consonants has total 588 possible syllables since
88185029Spjd * Hangul has 21 modern vowels and 27 modern trailing consonants plus 1 for
89185029Spjd * no trailing consonant case, i.e., 21 x 28 = 588.
90185029Spjd *
91185029Spjd * We also have bunch of Hangul related macros at below. Please bear in mind
92185029Spjd * that the U8_HANGUL_JAMO_1ST_BYTE can be used to check whether it is
93185029Spjd * a Hangul Jamo or not but the value does not guarantee that it is a Hangul
94185029Spjd * Jamo; it just guarantee that it will be most likely.
95185029Spjd */
96185029Spjd#define	U8_HANGUL_SYL_FIRST		(0xAC00U)
97185029Spjd#define	U8_HANGUL_SYL_LAST		(0xD7A3U)
98185029Spjd
99185029Spjd#define	U8_HANGUL_JAMO_L_FIRST		(0x1100U)
100185029Spjd#define	U8_HANGUL_JAMO_L_LAST		(0x1112U)
101185029Spjd#define	U8_HANGUL_JAMO_V_FIRST		(0x1161U)
102185029Spjd#define	U8_HANGUL_JAMO_V_LAST		(0x1175U)
103185029Spjd#define	U8_HANGUL_JAMO_T_FIRST		(0x11A7U)
104185029Spjd#define	U8_HANGUL_JAMO_T_LAST		(0x11C2U)
105185029Spjd
106185029Spjd#define	U8_HANGUL_V_COUNT		(21)
107185029Spjd#define	U8_HANGUL_VT_COUNT		(588)
108185029Spjd#define	U8_HANGUL_T_COUNT		(28)
109185029Spjd
110185029Spjd#define	U8_HANGUL_JAMO_1ST_BYTE		(0xE1U)
111185029Spjd
112185029Spjd#define	U8_SAVE_HANGUL_AS_UTF8(s, i, j, k, b) \
113185029Spjd	(s)[(i)] = (uchar_t)(0xE0U | ((uint32_t)(b) & 0xF000U) >> 12); \
114185029Spjd	(s)[(j)] = (uchar_t)(0x80U | ((uint32_t)(b) & 0x0FC0U) >> 6); \
115185029Spjd	(s)[(k)] = (uchar_t)(0x80U | ((uint32_t)(b) & 0x003FU));
116185029Spjd
117185029Spjd#define	U8_HANGUL_JAMO_L(u) \
118185029Spjd	((u) >= U8_HANGUL_JAMO_L_FIRST && (u) <= U8_HANGUL_JAMO_L_LAST)
119185029Spjd
120185029Spjd#define	U8_HANGUL_JAMO_V(u) \
121185029Spjd	((u) >= U8_HANGUL_JAMO_V_FIRST && (u) <= U8_HANGUL_JAMO_V_LAST)
122185029Spjd
123185029Spjd#define	U8_HANGUL_JAMO_T(u) \
124185029Spjd	((u) > U8_HANGUL_JAMO_T_FIRST && (u) <= U8_HANGUL_JAMO_T_LAST)
125185029Spjd
126185029Spjd#define	U8_HANGUL_JAMO(u) \
127185029Spjd	((u) >= U8_HANGUL_JAMO_L_FIRST && (u) <= U8_HANGUL_JAMO_T_LAST)
128185029Spjd
129185029Spjd#define	U8_HANGUL_SYLLABLE(u) \
130185029Spjd	((u) >= U8_HANGUL_SYL_FIRST && (u) <= U8_HANGUL_SYL_LAST)
131185029Spjd
132185029Spjd#define	U8_HANGUL_COMPOSABLE_L_V(s, u) \
133185029Spjd	((s) == U8_STATE_HANGUL_L && U8_HANGUL_JAMO_V((u)))
134185029Spjd
135185029Spjd#define	U8_HANGUL_COMPOSABLE_LV_T(s, u) \
136185029Spjd	((s) == U8_STATE_HANGUL_LV && U8_HANGUL_JAMO_T((u)))
137185029Spjd
138185029Spjd/* The types of decomposition mappings. */
139185029Spjd#define	U8_DECOMP_BOTH			(0xF5U)
140185029Spjd#define	U8_DECOMP_CANONICAL		(0xF6U)
141185029Spjd
142185029Spjd/* The indicator for 16-bit table. */
143185029Spjd#define	U8_16BIT_TABLE_INDICATOR	(0x8000U)
144185029Spjd
145185029Spjd/* The following are some convenience macros. */
146185029Spjd#define	U8_PUT_3BYTES_INTO_UTF32(u, b1, b2, b3) \
147185029Spjd	(u) = ((uint32_t)(b1) & 0x0F) << 12 | ((uint32_t)(b2) & 0x3F) << 6 | \
148185029Spjd		(uint32_t)(b3) & 0x3F;
149185029Spjd
150185029Spjd#define	U8_SIMPLE_SWAP(a, b, t) \
151185029Spjd	(t) = (a); \
152185029Spjd	(a) = (b); \
153185029Spjd	(b) = (t);
154185029Spjd
155185029Spjd#define	U8_ASCII_TOUPPER(c) \
156185029Spjd	(((c) >= 'a' && (c) <= 'z') ? (c) - 'a' + 'A' : (c))
157185029Spjd
158185029Spjd#define	U8_ASCII_TOLOWER(c) \
159185029Spjd	(((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
160185029Spjd
161185029Spjd#define	U8_ISASCII(c)			(((uchar_t)(c)) < 0x80U)
162185029Spjd/*
163185029Spjd * The following macro assumes that the two characters that are to be
164185029Spjd * swapped are adjacent to each other and 'a' comes before 'b'.
165185029Spjd *
166185029Spjd * If the assumptions are not met, then, the macro will fail.
167185029Spjd */
168185029Spjd#define	U8_SWAP_COMB_MARKS(a, b) \
169185029Spjd	for (k = 0; k < disp[(a)]; k++) \
170185029Spjd		u8t[k] = u8s[start[(a)] + k]; \
171185029Spjd	for (k = 0; k < disp[(b)]; k++) \
172185029Spjd		u8s[start[(a)] + k] = u8s[start[(b)] + k]; \
173185029Spjd	start[(b)] = start[(a)] + disp[(b)]; \
174185029Spjd	for (k = 0; k < disp[(a)]; k++) \
175185029Spjd		u8s[start[(b)] + k] = u8t[k]; \
176185029Spjd	U8_SIMPLE_SWAP(comb_class[(a)], comb_class[(b)], tc); \
177185029Spjd	U8_SIMPLE_SWAP(disp[(a)], disp[(b)], tc);
178185029Spjd
179185029Spjd/* The possible states during normalization. */
180185029Spjdtypedef enum {
181185029Spjd	U8_STATE_START = 0,
182185029Spjd	U8_STATE_HANGUL_L = 1,
183185029Spjd	U8_STATE_HANGUL_LV = 2,
184185029Spjd	U8_STATE_HANGUL_LVT = 3,
185185029Spjd	U8_STATE_HANGUL_V = 4,
186185029Spjd	U8_STATE_HANGUL_T = 5,
187185029Spjd	U8_STATE_COMBINING_MARK = 6
188185029Spjd} u8_normalization_states_t;
189185029Spjd
190185029Spjd/*
191185029Spjd * The three vectors at below are used to check bytes of a given UTF-8
192185029Spjd * character are valid and not containing any malformed byte values.
193185029Spjd *
194185029Spjd * We used to have a quite relaxed UTF-8 binary representation but then there
195185029Spjd * was some security related issues and so the Unicode Consortium defined
196185029Spjd * and announced the UTF-8 Corrigendum at Unicode 3.1 and then refined it
197185029Spjd * one more time at the Unicode 3.2. The following three tables are based on
198185029Spjd * that.
199185029Spjd */
200185029Spjd
201185029Spjd#define	U8_ILLEGAL_NEXT_BYTE_COMMON(c)	((c) < 0x80 || (c) > 0xBF)
202185029Spjd
203185029Spjd#define	I_				U8_ILLEGAL_CHAR
204185029Spjd#define	O_				U8_OUT_OF_RANGE_CHAR
205185029Spjd
206185029Spjdconst int8_t u8_number_of_bytes[0x100] = {
207185029Spjd	1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
208185029Spjd	1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
209185029Spjd	1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
210185029Spjd	1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
211185029Spjd	1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
212185029Spjd	1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
213185029Spjd	1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
214185029Spjd	1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
215185029Spjd
216185029Spjd/*	80  81  82  83  84  85  86  87  88  89  8A  8B  8C  8D  8E  8F  */
217185029Spjd	I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_,
218185029Spjd
219185029Spjd/*  	90  91  92  93  94  95  96  97  98  99  9A  9B  9C  9D  9E  9F  */
220185029Spjd	I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_,
221185029Spjd
222185029Spjd/*  	A0  A1  A2  A3  A4  A5  A6  A7  A8  A9  AA  AB  AC  AD  AE  AF  */
223185029Spjd	I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_,
224185029Spjd
225185029Spjd/*	B0  B1  B2  B3  B4  B5  B6  B7  B8  B9  BA  BB  BC  BD  BE  BF  */
226185029Spjd	I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_,
227185029Spjd
228185029Spjd/*	C0  C1  C2  C3  C4  C5  C6  C7  C8  C9  CA  CB  CC  CD  CE  CF  */
229185029Spjd	I_, I_, 2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
230185029Spjd
231185029Spjd/*	D0  D1  D2  D3  D4  D5  D6  D7  D8  D9  DA  DB  DC  DD  DE  DF  */
232185029Spjd	2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
233185029Spjd
234185029Spjd/*	E0  E1  E2  E3  E4  E5  E6  E7  E8  E9  EA  EB  EC  ED  EE  EF  */
235185029Spjd	3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
236185029Spjd
237185029Spjd/*	F0  F1  F2  F3  F4  F5  F6  F7  F8  F9  FA  FB  FC  FD  FE  FF  */
238185029Spjd	4,  4,  4,  4,  4,  O_, O_, O_, O_, O_, O_, O_, O_, O_, O_, O_,
239185029Spjd};
240185029Spjd
241185029Spjd#undef	I_
242185029Spjd#undef	O_
243185029Spjd
244185029Spjdconst uint8_t u8_valid_min_2nd_byte[0x100] = {
245185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
246185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
247185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
248185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
249185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
250185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
251185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
252185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
253185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
254185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
255185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
256185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
257185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
258185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
259185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
260185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
261185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
262185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
263185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
264185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
265185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
266185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
267185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
268185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
269185029Spjd/*	C0    C1    C2    C3    C4    C5    C6    C7    */
270185029Spjd	0,    0,    0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
271185029Spjd/*	C8    C9    CA    CB    CC    CD    CE    CF    */
272185029Spjd	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
273185029Spjd/*	D0    D1    D2    D3    D4    D5    D6    D7    */
274185029Spjd	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
275185029Spjd/*	D8    D9    DA    DB    DC    DD    DE    DF    */
276185029Spjd	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
277185029Spjd/*	E0    E1    E2    E3    E4    E5    E6    E7    */
278185029Spjd	0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
279185029Spjd/*	E8    E9    EA    EB    EC    ED    EE    EF    */
280185029Spjd	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
281185029Spjd/*	F0    F1    F2    F3    F4    F5    F6    F7    */
282185029Spjd	0x90, 0x80, 0x80, 0x80, 0x80, 0,    0,    0,
283185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
284185029Spjd};
285185029Spjd
286185029Spjdconst uint8_t u8_valid_max_2nd_byte[0x100] = {
287185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
288185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
289185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
290185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
291185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
292185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
293185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
294185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
295185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
296185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
297185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
298185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
299185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
300185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
301185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
302185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
303185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
304185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
305185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
306185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
307185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
308185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
309185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
310185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
311185029Spjd/*	C0    C1    C2    C3    C4    C5    C6    C7    */
312185029Spjd	0,    0,    0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
313185029Spjd/*	C8    C9    CA    CB    CC    CD    CE    CF    */
314185029Spjd	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
315185029Spjd/*	D0    D1    D2    D3    D4    D5    D6    D7    */
316185029Spjd	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
317185029Spjd/*	D8    D9    DA    DB    DC    DD    DE    DF    */
318185029Spjd	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
319185029Spjd/*	E0    E1    E2    E3    E4    E5    E6    E7    */
320185029Spjd	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
321185029Spjd/*	E8    E9    EA    EB    EC    ED    EE    EF    */
322185029Spjd	0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0x9f, 0xbf, 0xbf,
323185029Spjd/*	F0    F1    F2    F3    F4    F5    F6    F7    */
324185029Spjd	0xbf, 0xbf, 0xbf, 0xbf, 0x8f, 0,    0,    0,
325185029Spjd	0,    0,    0,    0,    0,    0,    0,    0,
326185029Spjd};
327185029Spjd
328185029Spjd
329185029Spjd/*
330185029Spjd * The u8_validate() validates on the given UTF-8 character string and
331185029Spjd * calculate the byte length. It is quite similar to mblen(3C) except that
332185029Spjd * this will validate against the list of characters if required and
333185029Spjd * specific to UTF-8 and Unicode.
334185029Spjd */
335185029Spjdint
336185029Spjdu8_validate(char *u8str, size_t n, char **list, int flag, int *errnum)
337185029Spjd{
338185029Spjd	uchar_t *ib;
339185029Spjd	uchar_t *ibtail;
340185029Spjd	uchar_t **p;
341185029Spjd	uchar_t *s1;
342185029Spjd	uchar_t *s2;
343185029Spjd	uchar_t f;
344185029Spjd	int sz;
345185029Spjd	size_t i;
346185029Spjd	int ret_val;
347185029Spjd	boolean_t second;
348185029Spjd	boolean_t no_need_to_validate_entire;
349185029Spjd	boolean_t check_additional;
350185029Spjd	boolean_t validate_ucs2_range_only;
351185029Spjd
352185029Spjd	if (! u8str)
353185029Spjd		return (0);
354185029Spjd
355185029Spjd	ib = (uchar_t *)u8str;
356185029Spjd	ibtail = ib + n;
357185029Spjd
358185029Spjd	ret_val = 0;
359185029Spjd
360185029Spjd	no_need_to_validate_entire = ! (flag & U8_VALIDATE_ENTIRE);
361185029Spjd	check_additional = flag & U8_VALIDATE_CHECK_ADDITIONAL;
362185029Spjd	validate_ucs2_range_only = flag & U8_VALIDATE_UCS2_RANGE;
363185029Spjd
364185029Spjd	while (ib < ibtail) {
365185029Spjd		/*
366185029Spjd		 * The first byte of a UTF-8 character tells how many
367185029Spjd		 * bytes will follow for the character. If the first byte
368185029Spjd		 * is an illegal byte value or out of range value, we just
369185029Spjd		 * return -1 with an appropriate error number.
370185029Spjd		 */
371185029Spjd		sz = u8_number_of_bytes[*ib];
372185029Spjd		if (sz == U8_ILLEGAL_CHAR) {
373185029Spjd			*errnum = EILSEQ;
374185029Spjd			return (-1);
375185029Spjd		}
376185029Spjd
377185029Spjd		if (sz == U8_OUT_OF_RANGE_CHAR ||
378185029Spjd		    (validate_ucs2_range_only && sz > U8_MAX_BYTES_UCS2)) {
379185029Spjd			*errnum = ERANGE;
380185029Spjd			return (-1);
381185029Spjd		}
382185029Spjd
383185029Spjd		/*
384185029Spjd		 * If we don't have enough bytes to check on, that's also
385185029Spjd		 * an error. As you can see, we give illegal byte sequence
386185029Spjd		 * checking higher priority then EINVAL cases.
387185029Spjd		 */
388185029Spjd		if ((ibtail - ib) < sz) {
389185029Spjd			*errnum = EINVAL;
390185029Spjd			return (-1);
391185029Spjd		}
392185029Spjd
393185029Spjd		if (sz == 1) {
394185029Spjd			ib++;
395185029Spjd			ret_val++;
396185029Spjd		} else {
397185029Spjd			/*
398185029Spjd			 * Check on the multi-byte UTF-8 character. For more
399185029Spjd			 * details on this, see comment added for the used
400185029Spjd			 * data structures at the beginning of the file.
401185029Spjd			 */
402185029Spjd			f = *ib++;
403185029Spjd			ret_val++;
404185029Spjd			second = B_TRUE;
405185029Spjd			for (i = 1; i < sz; i++) {
406185029Spjd				if (second) {
407185029Spjd					if (*ib < u8_valid_min_2nd_byte[f] ||
408185029Spjd					    *ib > u8_valid_max_2nd_byte[f]) {
409185029Spjd						*errnum = EILSEQ;
410185029Spjd						return (-1);
411185029Spjd					}
412185029Spjd					second = B_FALSE;
413185029Spjd				} else if (U8_ILLEGAL_NEXT_BYTE_COMMON(*ib)) {
414185029Spjd					*errnum = EILSEQ;
415185029Spjd					return (-1);
416185029Spjd				}
417185029Spjd				ib++;
418185029Spjd				ret_val++;
419185029Spjd			}
420185029Spjd		}
421185029Spjd
422185029Spjd		if (check_additional) {
423185029Spjd			for (p = (uchar_t **)list, i = 0; p[i]; i++) {
424185029Spjd				s1 = ib - sz;
425185029Spjd				s2 = p[i];
426185029Spjd				while (s1 < ib) {
427185029Spjd					if (*s1 != *s2 || *s2 == '\0')
428185029Spjd						break;
429185029Spjd					s1++;
430185029Spjd					s2++;
431185029Spjd				}
432185029Spjd
433185029Spjd				if (s1 >= ib && *s2 == '\0') {
434185029Spjd					*errnum = EBADF;
435185029Spjd					return (-1);
436185029Spjd				}
437185029Spjd			}
438185029Spjd		}
439185029Spjd
440185029Spjd		if (no_need_to_validate_entire)
441185029Spjd			break;
442185029Spjd	}
443185029Spjd
444185029Spjd	return (ret_val);
445185029Spjd}
446185029Spjd
447185029Spjd/*
448185029Spjd * The do_case_conv() looks at the mapping tables and returns found
449185029Spjd * bytes if any. If not found, the input bytes are returned. The function
450185029Spjd * always terminate the return bytes with a null character assuming that
451185029Spjd * there are plenty of room to do so.
452185029Spjd *
453185029Spjd * The case conversions are simple case conversions mapping a character to
454185029Spjd * another character as specified in the Unicode data. The byte size of
455185029Spjd * the mapped character could be different from that of the input character.
456185029Spjd *
457185029Spjd * The return value is the byte length of the returned character excluding
458185029Spjd * the terminating null byte.
459185029Spjd */
460185029Spjdstatic size_t
461185029Spjddo_case_conv(int uv, uchar_t *u8s, uchar_t *s, int sz, boolean_t is_it_toupper)
462185029Spjd{
463185029Spjd	size_t i;
464185029Spjd	uint16_t b1 = 0;
465185029Spjd	uint16_t b2 = 0;
466185029Spjd	uint16_t b3 = 0;
467185029Spjd	uint16_t b3_tbl;
468185029Spjd	uint16_t b3_base;
469185029Spjd	uint16_t b4 = 0;
470185029Spjd	size_t start_id;
471185029Spjd	size_t end_id;
472185029Spjd
473185029Spjd	/*
474185029Spjd	 * At this point, the only possible values for sz are 2, 3, and 4.
475185029Spjd	 * The u8s should point to a vector that is well beyond the size of
476185029Spjd	 * 5 bytes.
477185029Spjd	 */
478185029Spjd	if (sz == 2) {
479185029Spjd		b3 = u8s[0] = s[0];
480185029Spjd		b4 = u8s[1] = s[1];
481185029Spjd	} else if (sz == 3) {
482185029Spjd		b2 = u8s[0] = s[0];
483185029Spjd		b3 = u8s[1] = s[1];
484185029Spjd		b4 = u8s[2] = s[2];
485185029Spjd	} else if (sz == 4) {
486185029Spjd		b1 = u8s[0] = s[0];
487185029Spjd		b2 = u8s[1] = s[1];
488185029Spjd		b3 = u8s[2] = s[2];
489185029Spjd		b4 = u8s[3] = s[3];
490185029Spjd	} else {
491185029Spjd		/* This is not possible but just in case as a fallback. */
492185029Spjd		if (is_it_toupper)
493185029Spjd			*u8s = U8_ASCII_TOUPPER(*s);
494185029Spjd		else
495185029Spjd			*u8s = U8_ASCII_TOLOWER(*s);
496185029Spjd		u8s[1] = '\0';
497185029Spjd
498185029Spjd		return (1);
499185029Spjd	}
500185029Spjd	u8s[sz] = '\0';
501185029Spjd
502185029Spjd	/*
503185029Spjd	 * Let's find out if we have a corresponding character.
504185029Spjd	 */
505185029Spjd	b1 = u8_common_b1_tbl[uv][b1];
506185029Spjd	if (b1 == U8_TBL_ELEMENT_NOT_DEF)
507185029Spjd		return ((size_t)sz);
508185029Spjd
509185029Spjd	b2 = u8_case_common_b2_tbl[uv][b1][b2];
510185029Spjd	if (b2 == U8_TBL_ELEMENT_NOT_DEF)
511185029Spjd		return ((size_t)sz);
512185029Spjd
513185029Spjd	if (is_it_toupper) {
514185029Spjd		b3_tbl = u8_toupper_b3_tbl[uv][b2][b3].tbl_id;
515185029Spjd		if (b3_tbl == U8_TBL_ELEMENT_NOT_DEF)
516185029Spjd			return ((size_t)sz);
517185029Spjd
518185029Spjd		start_id = u8_toupper_b4_tbl[uv][b3_tbl][b4];
519185029Spjd		end_id = u8_toupper_b4_tbl[uv][b3_tbl][b4 + 1];
520185029Spjd
521185029Spjd		/* Either there is no match or an error at the table. */
522185029Spjd		if (start_id >= end_id || (end_id - start_id) > U8_MB_CUR_MAX)
523185029Spjd			return ((size_t)sz);
524185029Spjd
525185029Spjd		b3_base = u8_toupper_b3_tbl[uv][b2][b3].base;
526185029Spjd
527185029Spjd		for (i = 0; start_id < end_id; start_id++)
528185029Spjd			u8s[i++] = u8_toupper_final_tbl[uv][b3_base + start_id];
529185029Spjd	} else {
530185029Spjd		b3_tbl = u8_tolower_b3_tbl[uv][b2][b3].tbl_id;
531185029Spjd		if (b3_tbl == U8_TBL_ELEMENT_NOT_DEF)
532185029Spjd			return ((size_t)sz);
533185029Spjd
534185029Spjd		start_id = u8_tolower_b4_tbl[uv][b3_tbl][b4];
535185029Spjd		end_id = u8_tolower_b4_tbl[uv][b3_tbl][b4 + 1];
536185029Spjd
537185029Spjd		if (start_id >= end_id || (end_id - start_id) > U8_MB_CUR_MAX)
538185029Spjd			return ((size_t)sz);
539185029Spjd
540185029Spjd		b3_base = u8_tolower_b3_tbl[uv][b2][b3].base;
541185029Spjd
542185029Spjd		for (i = 0; start_id < end_id; start_id++)
543185029Spjd			u8s[i++] = u8_tolower_final_tbl[uv][b3_base + start_id];
544185029Spjd	}
545185029Spjd
546185029Spjd	/*
547185029Spjd	 * If i is still zero, that means there is no corresponding character.
548185029Spjd	 */
549185029Spjd	if (i == 0)
550185029Spjd		return ((size_t)sz);
551185029Spjd
552185029Spjd	u8s[i] = '\0';
553185029Spjd
554185029Spjd	return (i);
555185029Spjd}
556185029Spjd
557185029Spjd/*
558185029Spjd * The do_case_compare() function compares the two input strings, s1 and s2,
559185029Spjd * one character at a time doing case conversions if applicable and return
560185029Spjd * the comparison result as like strcmp().
561185029Spjd *
562185029Spjd * Since, in empirical sense, most of text data are 7-bit ASCII characters,
563185029Spjd * we treat the 7-bit ASCII characters as a special case trying to yield
564185029Spjd * faster processing time.
565185029Spjd */
566185029Spjdstatic int
567185029Spjddo_case_compare(size_t uv, uchar_t *s1, uchar_t *s2, size_t n1,
568185029Spjd	size_t n2, boolean_t is_it_toupper, int *errnum)
569185029Spjd{
570185029Spjd	int f;
571185029Spjd	int sz1;
572185029Spjd	int sz2;
573185029Spjd	size_t j;
574185029Spjd	size_t i1;
575185029Spjd	size_t i2;
576185029Spjd	uchar_t u8s1[U8_MB_CUR_MAX + 1];
577185029Spjd	uchar_t u8s2[U8_MB_CUR_MAX + 1];
578185029Spjd
579185029Spjd	i1 = i2 = 0;
580185029Spjd	while (i1 < n1 && i2 < n2) {
581185029Spjd		/*
582185029Spjd		 * Find out what would be the byte length for this UTF-8
583185029Spjd		 * character at string s1 and also find out if this is
584185029Spjd		 * an illegal start byte or not and if so, issue a proper
585185029Spjd		 * error number and yet treat this byte as a character.
586185029Spjd		 */
587185029Spjd		sz1 = u8_number_of_bytes[*s1];
588185029Spjd		if (sz1 < 0) {
589185029Spjd			*errnum = EILSEQ;
590185029Spjd			sz1 = 1;
591185029Spjd		}
592185029Spjd
593185029Spjd		/*
594185029Spjd		 * For 7-bit ASCII characters mainly, we do a quick case
595185029Spjd		 * conversion right at here.
596185029Spjd		 *
597185029Spjd		 * If we don't have enough bytes for this character, issue
598185029Spjd		 * an EINVAL error and use what are available.
599185029Spjd		 *
600185029Spjd		 * If we have enough bytes, find out if there is
601185029Spjd		 * a corresponding uppercase character and if so, copy over
602185029Spjd		 * the bytes for a comparison later. If there is no
603185029Spjd		 * corresponding uppercase character, then, use what we have
604185029Spjd		 * for the comparison.
605185029Spjd		 */
606185029Spjd		if (sz1 == 1) {
607185029Spjd			if (is_it_toupper)
608185029Spjd				u8s1[0] = U8_ASCII_TOUPPER(*s1);
609185029Spjd			else
610185029Spjd				u8s1[0] = U8_ASCII_TOLOWER(*s1);
611185029Spjd			s1++;
612185029Spjd			u8s1[1] = '\0';
613185029Spjd		} else if ((i1 + sz1) > n1) {
614185029Spjd			*errnum = EINVAL;
615185029Spjd			for (j = 0; (i1 + j) < n1; )
616185029Spjd				u8s1[j++] = *s1++;
617185029Spjd			u8s1[j] = '\0';
618185029Spjd		} else {
619185029Spjd			(void) do_case_conv(uv, u8s1, s1, sz1, is_it_toupper);
620185029Spjd			s1 += sz1;
621185029Spjd		}
622185029Spjd
623185029Spjd		/* Do the same for the string s2. */
624185029Spjd		sz2 = u8_number_of_bytes[*s2];
625185029Spjd		if (sz2 < 0) {
626185029Spjd			*errnum = EILSEQ;
627185029Spjd			sz2 = 1;
628185029Spjd		}
629185029Spjd
630185029Spjd		if (sz2 == 1) {
631185029Spjd			if (is_it_toupper)
632185029Spjd				u8s2[0] = U8_ASCII_TOUPPER(*s2);
633185029Spjd			else
634185029Spjd				u8s2[0] = U8_ASCII_TOLOWER(*s2);
635185029Spjd			s2++;
636185029Spjd			u8s2[1] = '\0';
637185029Spjd		} else if ((i2 + sz2) > n2) {
638185029Spjd			*errnum = EINVAL;
639185029Spjd			for (j = 0; (i2 + j) < n2; )
640185029Spjd				u8s2[j++] = *s2++;
641185029Spjd			u8s2[j] = '\0';
642185029Spjd		} else {
643185029Spjd			(void) do_case_conv(uv, u8s2, s2, sz2, is_it_toupper);
644185029Spjd			s2 += sz2;
645185029Spjd		}
646185029Spjd
647185029Spjd		/* Now compare the two characters. */
648185029Spjd		if (sz1 == 1 && sz2 == 1) {
649185029Spjd			if (*u8s1 > *u8s2)
650185029Spjd				return (1);
651185029Spjd			if (*u8s1 < *u8s2)
652185029Spjd				return (-1);
653185029Spjd		} else {
654185029Spjd			f = strcmp((const char *)u8s1, (const char *)u8s2);
655185029Spjd			if (f != 0)
656185029Spjd				return (f);
657185029Spjd		}
658185029Spjd
659185029Spjd		/*
660185029Spjd		 * They were the same. Let's move on to the next
661185029Spjd		 * characters then.
662185029Spjd		 */
663185029Spjd		i1 += sz1;
664185029Spjd		i2 += sz2;
665185029Spjd	}
666185029Spjd
667185029Spjd	/*
668185029Spjd	 * We compared until the end of either or both strings.
669185029Spjd	 *
670185029Spjd	 * If we reached to or went over the ends for the both, that means
671185029Spjd	 * they are the same.
672185029Spjd	 *
673185029Spjd	 * If we reached only one of the two ends, that means the other string
674185029Spjd	 * has something which then the fact can be used to determine
675185029Spjd	 * the return value.
676185029Spjd	 */
677185029Spjd	if (i1 >= n1) {
678185029Spjd		if (i2 >= n2)
679185029Spjd			return (0);
680185029Spjd		return (-1);
681185029Spjd	}
682185029Spjd	return (1);
683185029Spjd}
684185029Spjd
685185029Spjd/*
686185029Spjd * The combining_class() function checks on the given bytes and find out
687185029Spjd * the corresponding Unicode combining class value. The return value 0 means
688185029Spjd * it is a Starter. Any illegal UTF-8 character will also be treated as
689185029Spjd * a Starter.
690185029Spjd */
691185029Spjdstatic uchar_t
692185029Spjdcombining_class(size_t uv, uchar_t *s, size_t sz)
693185029Spjd{
694185029Spjd	uint16_t b1 = 0;
695185029Spjd	uint16_t b2 = 0;
696185029Spjd	uint16_t b3 = 0;
697185029Spjd	uint16_t b4 = 0;
698185029Spjd
699185029Spjd	if (sz == 1 || sz > 4)
700185029Spjd		return (0);
701185029Spjd
702185029Spjd	if (sz == 2) {
703185029Spjd		b3 = s[0];
704185029Spjd		b4 = s[1];
705185029Spjd	} else if (sz == 3) {
706185029Spjd		b2 = s[0];
707185029Spjd		b3 = s[1];
708185029Spjd		b4 = s[2];
709185029Spjd	} else if (sz == 4) {
710185029Spjd		b1 = s[0];
711185029Spjd		b2 = s[1];
712185029Spjd		b3 = s[2];
713185029Spjd		b4 = s[3];
714185029Spjd	}
715185029Spjd
716185029Spjd	b1 = u8_common_b1_tbl[uv][b1];
717185029Spjd	if (b1 == U8_TBL_ELEMENT_NOT_DEF)
718185029Spjd		return (0);
719185029Spjd
720185029Spjd	b2 = u8_combining_class_b2_tbl[uv][b1][b2];
721185029Spjd	if (b2 == U8_TBL_ELEMENT_NOT_DEF)
722185029Spjd		return (0);
723185029Spjd
724185029Spjd	b3 = u8_combining_class_b3_tbl[uv][b2][b3];
725185029Spjd	if (b3 == U8_TBL_ELEMENT_NOT_DEF)
726185029Spjd		return (0);
727185029Spjd
728185029Spjd	return (u8_combining_class_b4_tbl[uv][b3][b4]);
729185029Spjd}
730185029Spjd
731185029Spjd/*
732185029Spjd * The do_decomp() function finds out a matching decomposition if any
733185029Spjd * and return. If there is no match, the input bytes are copied and returned.
734185029Spjd * The function also checks if there is a Hangul, decomposes it if necessary
735185029Spjd * and returns.
736185029Spjd *
737185029Spjd * To save time, a single byte 7-bit ASCII character should be handled by
738185029Spjd * the caller.
739185029Spjd *
740185029Spjd * The function returns the number of bytes returned sans always terminating
741185029Spjd * the null byte. It will also return a state that will tell if there was
742185029Spjd * a Hangul character decomposed which then will be used by the caller.
743185029Spjd */
744185029Spjdstatic size_t
745185029Spjddo_decomp(size_t uv, uchar_t *u8s, uchar_t *s, int sz,
746185029Spjd	boolean_t canonical_decomposition, u8_normalization_states_t *state)
747185029Spjd{
748185029Spjd	uint16_t b1 = 0;
749185029Spjd	uint16_t b2 = 0;
750185029Spjd	uint16_t b3 = 0;
751185029Spjd	uint16_t b3_tbl;
752185029Spjd	uint16_t b3_base;
753185029Spjd	uint16_t b4 = 0;
754185029Spjd	size_t start_id;
755185029Spjd	size_t end_id;
756185029Spjd	size_t i;
757185029Spjd	uint32_t u1;
758185029Spjd
759185029Spjd	if (sz == 2) {
760185029Spjd		b3 = u8s[0] = s[0];
761185029Spjd		b4 = u8s[1] = s[1];
762185029Spjd		u8s[2] = '\0';
763185029Spjd	} else if (sz == 3) {
764185029Spjd		/* Convert it to a Unicode scalar value. */
765185029Spjd		U8_PUT_3BYTES_INTO_UTF32(u1, s[0], s[1], s[2]);
766185029Spjd
767185029Spjd		/*
768185029Spjd		 * If this is a Hangul syllable, we decompose it into
769185029Spjd		 * a leading consonant, a vowel, and an optional trailing
770185029Spjd		 * consonant and then return.
771185029Spjd		 */
772185029Spjd		if (U8_HANGUL_SYLLABLE(u1)) {
773185029Spjd			u1 -= U8_HANGUL_SYL_FIRST;
774185029Spjd
775185029Spjd			b1 = U8_HANGUL_JAMO_L_FIRST + u1 / U8_HANGUL_VT_COUNT;
776185029Spjd			b2 = U8_HANGUL_JAMO_V_FIRST + (u1 % U8_HANGUL_VT_COUNT)
777185029Spjd			    / U8_HANGUL_T_COUNT;
778185029Spjd			b3 = u1 % U8_HANGUL_T_COUNT;
779185029Spjd
780185029Spjd			U8_SAVE_HANGUL_AS_UTF8(u8s, 0, 1, 2, b1);
781185029Spjd			U8_SAVE_HANGUL_AS_UTF8(u8s, 3, 4, 5, b2);
782185029Spjd			if (b3) {
783185029Spjd				b3 += U8_HANGUL_JAMO_T_FIRST;
784185029Spjd				U8_SAVE_HANGUL_AS_UTF8(u8s, 6, 7, 8, b3);
785185029Spjd
786185029Spjd				u8s[9] = '\0';
787185029Spjd				*state = U8_STATE_HANGUL_LVT;
788185029Spjd				return (9);
789185029Spjd			}
790185029Spjd
791185029Spjd			u8s[6] = '\0';
792185029Spjd			*state = U8_STATE_HANGUL_LV;
793185029Spjd			return (6);
794185029Spjd		}
795185029Spjd
796185029Spjd		b2 = u8s[0] = s[0];
797185029Spjd		b3 = u8s[1] = s[1];
798185029Spjd		b4 = u8s[2] = s[2];
799185029Spjd		u8s[3] = '\0';
800185029Spjd
801185029Spjd		/*
802185029Spjd		 * If this is a Hangul Jamo, we know there is nothing
803185029Spjd		 * further that we can decompose.
804185029Spjd		 */
805185029Spjd		if (U8_HANGUL_JAMO_L(u1)) {
806185029Spjd			*state = U8_STATE_HANGUL_L;
807185029Spjd			return (3);
808185029Spjd		}
809185029Spjd
810185029Spjd		if (U8_HANGUL_JAMO_V(u1)) {
811185029Spjd			if (*state == U8_STATE_HANGUL_L)
812185029Spjd				*state = U8_STATE_HANGUL_LV;
813185029Spjd			else
814185029Spjd				*state = U8_STATE_HANGUL_V;
815185029Spjd			return (3);
816185029Spjd		}
817185029Spjd
818185029Spjd		if (U8_HANGUL_JAMO_T(u1)) {
819185029Spjd			if (*state == U8_STATE_HANGUL_LV)
820185029Spjd				*state = U8_STATE_HANGUL_LVT;
821185029Spjd			else
822185029Spjd				*state = U8_STATE_HANGUL_T;
823185029Spjd			return (3);
824185029Spjd		}
825185029Spjd	} else if (sz == 4) {
826185029Spjd		b1 = u8s[0] = s[0];
827185029Spjd		b2 = u8s[1] = s[1];
828185029Spjd		b3 = u8s[2] = s[2];
829185029Spjd		b4 = u8s[3] = s[3];
830185029Spjd		u8s[4] = '\0';
831185029Spjd	} else {
832185029Spjd		/*
833185029Spjd		 * This is a fallback and should not happen if the function
834185029Spjd		 * was called properly.
835185029Spjd		 */
836185029Spjd		u8s[0] = s[0];
837185029Spjd		u8s[1] = '\0';
838185029Spjd		*state = U8_STATE_START;
839185029Spjd		return (1);
840185029Spjd	}
841185029Spjd
842185029Spjd	/*
843185029Spjd	 * At this point, this rountine does not know what it would get.
844185029Spjd	 * The caller should sort it out if the state isn't a Hangul one.
845185029Spjd	 */
846185029Spjd	*state = U8_STATE_START;
847185029Spjd
848185029Spjd	/* Try to find matching decomposition mapping byte sequence. */
849185029Spjd	b1 = u8_common_b1_tbl[uv][b1];
850185029Spjd	if (b1 == U8_TBL_ELEMENT_NOT_DEF)
851185029Spjd		return ((size_t)sz);
852185029Spjd
853185029Spjd	b2 = u8_decomp_b2_tbl[uv][b1][b2];
854185029Spjd	if (b2 == U8_TBL_ELEMENT_NOT_DEF)
855185029Spjd		return ((size_t)sz);
856185029Spjd
857185029Spjd	b3_tbl = u8_decomp_b3_tbl[uv][b2][b3].tbl_id;
858185029Spjd	if (b3_tbl == U8_TBL_ELEMENT_NOT_DEF)
859185029Spjd		return ((size_t)sz);
860185029Spjd
861185029Spjd	/*
862185029Spjd	 * If b3_tbl is bigger than or equal to U8_16BIT_TABLE_INDICATOR
863185029Spjd	 * which is 0x8000, this means we couldn't fit the mappings into
864185029Spjd	 * the cardinality of a unsigned byte.
865185029Spjd	 */
866185029Spjd	if (b3_tbl >= U8_16BIT_TABLE_INDICATOR) {
867185029Spjd		b3_tbl -= U8_16BIT_TABLE_INDICATOR;
868185029Spjd		start_id = u8_decomp_b4_16bit_tbl[uv][b3_tbl][b4];
869185029Spjd		end_id = u8_decomp_b4_16bit_tbl[uv][b3_tbl][b4 + 1];
870185029Spjd	} else {
871185029Spjd		start_id = u8_decomp_b4_tbl[uv][b3_tbl][b4];
872185029Spjd		end_id = u8_decomp_b4_tbl[uv][b3_tbl][b4 + 1];
873185029Spjd	}
874185029Spjd
875185029Spjd	/* This also means there wasn't any matching decomposition. */
876185029Spjd	if (start_id >= end_id)
877185029Spjd		return ((size_t)sz);
878185029Spjd
879185029Spjd	/*
880185029Spjd	 * The final table for decomposition mappings has three types of
881185029Spjd	 * byte sequences depending on whether a mapping is for compatibility
882185029Spjd	 * decomposition, canonical decomposition, or both like the following:
883185029Spjd	 *
884185029Spjd	 * (1) Compatibility decomposition mappings:
885185029Spjd	 *
886185029Spjd	 *	+---+---+-...-+---+
887185029Spjd	 *	| B0| B1| ... | Bm|
888185029Spjd	 *	+---+---+-...-+---+
889185029Spjd	 *
890185029Spjd	 *	The first byte, B0, is always less then 0xF5 (U8_DECOMP_BOTH).
891185029Spjd	 *
892185029Spjd	 * (2) Canonical decomposition mappings:
893185029Spjd	 *
894185029Spjd	 *	+---+---+---+-...-+---+
895185029Spjd	 *	| T | b0| b1| ... | bn|
896185029Spjd	 *	+---+---+---+-...-+---+
897185029Spjd	 *
898185029Spjd	 *	where the first byte, T, is 0xF6 (U8_DECOMP_CANONICAL).
899185029Spjd	 *
900185029Spjd	 * (3) Both mappings:
901185029Spjd	 *
902185029Spjd	 *	+---+---+---+---+-...-+---+---+---+-...-+---+
903185029Spjd	 *	| T | D | b0| b1| ... | bn| B0| B1| ... | Bm|
904185029Spjd	 *	+---+---+---+---+-...-+---+---+---+-...-+---+
905185029Spjd	 *
906185029Spjd	 *	where T is 0xF5 (U8_DECOMP_BOTH) and D is a displacement
907185029Spjd	 *	byte, b0 to bn are canonical mapping bytes and B0 to Bm are
908185029Spjd	 *	compatibility mapping bytes.
909185029Spjd	 *
910185029Spjd	 * Note that compatibility decomposition means doing recursive
911185029Spjd	 * decompositions using both compatibility decomposition mappings and
912185029Spjd	 * canonical decomposition mappings. On the other hand, canonical
913185029Spjd	 * decomposition means doing recursive decompositions using only
914185029Spjd	 * canonical decomposition mappings. Since the table we have has gone
915185029Spjd	 * through the recursions already, we do not need to do so during
916185029Spjd	 * runtime, i.e., the table has been completely flattened out
917185029Spjd	 * already.
918185029Spjd	 */
919185029Spjd
920185029Spjd	b3_base = u8_decomp_b3_tbl[uv][b2][b3].base;
921185029Spjd
922185029Spjd	/* Get the type, T, of the byte sequence. */
923185029Spjd	b1 = u8_decomp_final_tbl[uv][b3_base + start_id];
924185029Spjd
925185029Spjd	/*
926185029Spjd	 * If necessary, adjust start_id, end_id, or both. Note that if
927185029Spjd	 * this is compatibility decomposition mapping, there is no
928185029Spjd	 * adjustment.
929185029Spjd	 */
930185029Spjd	if (canonical_decomposition) {
931185029Spjd		/* Is the mapping only for compatibility decomposition? */
932185029Spjd		if (b1 < U8_DECOMP_BOTH)
933185029Spjd			return ((size_t)sz);
934185029Spjd
935185029Spjd		start_id++;
936185029Spjd
937185029Spjd		if (b1 == U8_DECOMP_BOTH) {
938185029Spjd			end_id = start_id +
939185029Spjd			    u8_decomp_final_tbl[uv][b3_base + start_id];
940185029Spjd			start_id++;
941185029Spjd		}
942185029Spjd	} else {
943185029Spjd		/*
944185029Spjd		 * Unless this is a compatibility decomposition mapping,
945185029Spjd		 * we adjust the start_id.
946185029Spjd		 */
947185029Spjd		if (b1 == U8_DECOMP_BOTH) {
948185029Spjd			start_id++;
949185029Spjd			start_id += u8_decomp_final_tbl[uv][b3_base + start_id];
950185029Spjd		} else if (b1 == U8_DECOMP_CANONICAL) {
951185029Spjd			start_id++;
952185029Spjd		}
953185029Spjd	}
954185029Spjd
955185029Spjd	for (i = 0; start_id < end_id; start_id++)
956185029Spjd		u8s[i++] = u8_decomp_final_tbl[uv][b3_base + start_id];
957185029Spjd	u8s[i] = '\0';
958185029Spjd
959185029Spjd	return (i);
960185029Spjd}
961185029Spjd
962185029Spjd/*
963185029Spjd * The find_composition_start() function uses the character bytes given and
964185029Spjd * find out the matching composition mappings if any and return the address
965185029Spjd * to the composition mappings as explained in the do_composition().
966185029Spjd */
967185029Spjdstatic uchar_t *
968185029Spjdfind_composition_start(size_t uv, uchar_t *s, size_t sz)
969185029Spjd{
970185029Spjd	uint16_t b1 = 0;
971185029Spjd	uint16_t b2 = 0;
972185029Spjd	uint16_t b3 = 0;
973185029Spjd	uint16_t b3_tbl;
974185029Spjd	uint16_t b3_base;
975185029Spjd	uint16_t b4 = 0;
976185029Spjd	size_t start_id;
977185029Spjd	size_t end_id;
978185029Spjd
979185029Spjd	if (sz == 1) {
980185029Spjd		b4 = s[0];
981185029Spjd	} else if (sz == 2) {
982185029Spjd		b3 = s[0];
983185029Spjd		b4 = s[1];
984185029Spjd	} else if (sz == 3) {
985185029Spjd		b2 = s[0];
986185029Spjd		b3 = s[1];
987185029Spjd		b4 = s[2];
988185029Spjd	} else if (sz == 4) {
989185029Spjd		b1 = s[0];
990185029Spjd		b2 = s[1];
991185029Spjd		b3 = s[2];
992185029Spjd		b4 = s[3];
993185029Spjd	} else {
994185029Spjd		/*
995185029Spjd		 * This is a fallback and should not happen if the function
996185029Spjd		 * was called properly.
997185029Spjd		 */
998185029Spjd		return (NULL);
999185029Spjd	}
1000185029Spjd
1001185029Spjd	b1 = u8_composition_b1_tbl[uv][b1];
1002185029Spjd	if (b1 == U8_TBL_ELEMENT_NOT_DEF)
1003185029Spjd		return (NULL);
1004185029Spjd
1005185029Spjd	b2 = u8_composition_b2_tbl[uv][b1][b2];
1006185029Spjd	if (b2 == U8_TBL_ELEMENT_NOT_DEF)
1007185029Spjd		return (NULL);
1008185029Spjd
1009185029Spjd	b3_tbl = u8_composition_b3_tbl[uv][b2][b3].tbl_id;
1010185029Spjd	if (b3_tbl == U8_TBL_ELEMENT_NOT_DEF)
1011185029Spjd		return (NULL);
1012185029Spjd
1013185029Spjd	if (b3_tbl >= U8_16BIT_TABLE_INDICATOR) {
1014185029Spjd		b3_tbl -= U8_16BIT_TABLE_INDICATOR;
1015185029Spjd		start_id = u8_composition_b4_16bit_tbl[uv][b3_tbl][b4];
1016185029Spjd		end_id = u8_composition_b4_16bit_tbl[uv][b3_tbl][b4 + 1];
1017185029Spjd	} else {
1018185029Spjd		start_id = u8_composition_b4_tbl[uv][b3_tbl][b4];
1019185029Spjd		end_id = u8_composition_b4_tbl[uv][b3_tbl][b4 + 1];
1020185029Spjd	}
1021185029Spjd
1022185029Spjd	if (start_id >= end_id)
1023185029Spjd		return (NULL);
1024185029Spjd
1025185029Spjd	b3_base = u8_composition_b3_tbl[uv][b2][b3].base;
1026185029Spjd
1027185029Spjd	return ((uchar_t *)&(u8_composition_final_tbl[uv][b3_base + start_id]));
1028185029Spjd}
1029185029Spjd
1030185029Spjd/*
1031185029Spjd * The blocked() function checks on the combining class values of previous
1032185029Spjd * characters in this sequence and return whether it is blocked or not.
1033185029Spjd */
1034185029Spjdstatic boolean_t
1035185029Spjdblocked(uchar_t *comb_class, size_t last)
1036185029Spjd{
1037185029Spjd	uchar_t my_comb_class;
1038185029Spjd	size_t i;
1039185029Spjd
1040185029Spjd	my_comb_class = comb_class[last];
1041185029Spjd	for (i = 1; i < last; i++)
1042185029Spjd		if (comb_class[i] >= my_comb_class ||
1043185029Spjd		    comb_class[i] == U8_COMBINING_CLASS_STARTER)
1044185029Spjd			return (B_TRUE);
1045185029Spjd
1046185029Spjd	return (B_FALSE);
1047185029Spjd}
1048185029Spjd
1049185029Spjd/*
1050185029Spjd * The do_composition() reads the character string pointed by 's' and
1051185029Spjd * do necessary canonical composition and then copy over the result back to
1052185029Spjd * the 's'.
1053185029Spjd *
1054185029Spjd * The input argument 's' cannot contain more than 32 characters.
1055185029Spjd */
1056185029Spjdstatic size_t
1057185029Spjddo_composition(size_t uv, uchar_t *s, uchar_t *comb_class, uchar_t *start,
1058185029Spjd	uchar_t *disp, size_t last, uchar_t **os, uchar_t *oslast)
1059185029Spjd{
1060185029Spjd	uchar_t t[U8_STREAM_SAFE_TEXT_MAX + 1];
1061185029Spjd	uchar_t tc[U8_MB_CUR_MAX];
1062185029Spjd	uint8_t saved_marks[U8_MAX_CHARS_A_SEQ];
1063185029Spjd	size_t saved_marks_count;
1064185029Spjd	uchar_t *p;
1065185029Spjd	uchar_t *saved_p;
1066185029Spjd	uchar_t *q;
1067185029Spjd	size_t i;
1068185029Spjd	size_t saved_i;
1069185029Spjd	size_t j;
1070185029Spjd	size_t k;
1071185029Spjd	size_t l;
1072185029Spjd	size_t C;
1073185029Spjd	size_t saved_l;
1074185029Spjd	size_t size;
1075185029Spjd	uint32_t u1;
1076185029Spjd	uint32_t u2;
1077185029Spjd	boolean_t match_not_found = B_TRUE;
1078185029Spjd
1079185029Spjd	/*
1080185029Spjd	 * This should never happen unless the callers are doing some strange
1081185029Spjd	 * and unexpected things.
1082185029Spjd	 *
1083185029Spjd	 * The "last" is the index pointing to the last character not last + 1.
1084185029Spjd	 */
1085185029Spjd	if (last >= U8_MAX_CHARS_A_SEQ)
1086185029Spjd		last = U8_UPPER_LIMIT_IN_A_SEQ;
1087185029Spjd
1088185029Spjd	for (i = l = 0; i <= last; i++) {
1089185029Spjd		/*
1090185029Spjd		 * The last or any non-Starters at the beginning, we don't
1091185029Spjd		 * have any chance to do composition and so we just copy them
1092185029Spjd		 * to the temporary buffer.
1093185029Spjd		 */
1094185029Spjd		if (i >= last || comb_class[i] != U8_COMBINING_CLASS_STARTER) {
1095185029SpjdSAVE_THE_CHAR:
1096185029Spjd			p = s + start[i];
1097185029Spjd			size = disp[i];
1098185029Spjd			for (k = 0; k < size; k++)
1099185029Spjd				t[l++] = *p++;
1100185029Spjd			continue;
1101185029Spjd		}
1102185029Spjd
1103185029Spjd		/*
1104185029Spjd		 * If this could be a start of Hangul Jamos, then, we try to
1105185029Spjd		 * conjoin them.
1106185029Spjd		 */
1107185029Spjd		if (s[start[i]] == U8_HANGUL_JAMO_1ST_BYTE) {
1108185029Spjd			U8_PUT_3BYTES_INTO_UTF32(u1, s[start[i]],
1109185029Spjd			    s[start[i] + 1], s[start[i] + 2]);
1110185029Spjd			U8_PUT_3BYTES_INTO_UTF32(u2, s[start[i] + 3],
1111185029Spjd			    s[start[i] + 4], s[start[i] + 5]);
1112185029Spjd
1113185029Spjd			if (U8_HANGUL_JAMO_L(u1) && U8_HANGUL_JAMO_V(u2)) {
1114185029Spjd				u1 -= U8_HANGUL_JAMO_L_FIRST;
1115185029Spjd				u2 -= U8_HANGUL_JAMO_V_FIRST;
1116185029Spjd				u1 = U8_HANGUL_SYL_FIRST +
1117185029Spjd				    (u1 * U8_HANGUL_V_COUNT + u2) *
1118185029Spjd				    U8_HANGUL_T_COUNT;
1119185029Spjd
1120185029Spjd				i += 2;
1121185029Spjd				if (i <= last) {
1122185029Spjd					U8_PUT_3BYTES_INTO_UTF32(u2,
1123185029Spjd					    s[start[i]], s[start[i] + 1],
1124185029Spjd					    s[start[i] + 2]);
1125185029Spjd
1126185029Spjd					if (U8_HANGUL_JAMO_T(u2)) {
1127185029Spjd						u1 += u2 -
1128185029Spjd						    U8_HANGUL_JAMO_T_FIRST;
1129185029Spjd						i++;
1130185029Spjd					}
1131185029Spjd				}
1132185029Spjd
1133185029Spjd				U8_SAVE_HANGUL_AS_UTF8(t + l, 0, 1, 2, u1);
1134185029Spjd				i--;
1135185029Spjd				l += 3;
1136185029Spjd				continue;
1137185029Spjd			}
1138185029Spjd		}
1139185029Spjd
1140185029Spjd		/*
1141185029Spjd		 * Let's then find out if this Starter has composition
1142185029Spjd		 * mapping.
1143185029Spjd		 */
1144185029Spjd		p = find_composition_start(uv, s + start[i], disp[i]);
1145185029Spjd		if (p == NULL)
1146185029Spjd			goto SAVE_THE_CHAR;
1147185029Spjd
1148185029Spjd		/*
1149185029Spjd		 * We have a Starter with composition mapping and the next
1150185029Spjd		 * character is a non-Starter. Let's try to find out if
1151185029Spjd		 * we can do composition.
1152185029Spjd		 */
1153185029Spjd
1154185029Spjd		saved_p = p;
1155185029Spjd		saved_i = i;
1156185029Spjd		saved_l = l;
1157185029Spjd		saved_marks_count = 0;
1158185029Spjd
1159185029SpjdTRY_THE_NEXT_MARK:
1160185029Spjd		q = s + start[++i];
1161185029Spjd		size = disp[i];
1162185029Spjd
1163185029Spjd		/*
1164185029Spjd		 * The next for() loop compares the non-Starter pointed by
1165185029Spjd		 * 'q' with the possible (joinable) characters pointed by 'p'.
1166185029Spjd		 *
1167185029Spjd		 * The composition final table entry pointed by the 'p'
1168185029Spjd		 * looks like the following:
1169185029Spjd		 *
1170185029Spjd		 * +---+---+---+-...-+---+---+---+---+-...-+---+---+
1171185029Spjd		 * | C | b0| b2| ... | bn| F | B0| B1| ... | Bm| F |
1172185029Spjd		 * +---+---+---+-...-+---+---+---+---+-...-+---+---+
1173185029Spjd		 *
1174185029Spjd		 * where C is the count byte indicating the number of
1175185029Spjd		 * mapping pairs where each pair would be look like
1176185029Spjd		 * (b0-bn F, B0-Bm F). The b0-bn are the bytes of the second
1177185029Spjd		 * character of a canonical decomposition and the B0-Bm are
1178185029Spjd		 * the bytes of a matching composite character. The F is
1179185029Spjd		 * a filler byte after each character as the separator.
1180185029Spjd		 */
1181185029Spjd
1182185029Spjd		match_not_found = B_TRUE;
1183185029Spjd
1184185029Spjd		for (C = *p++; C > 0; C--) {
1185185029Spjd			for (k = 0; k < size; p++, k++)
1186185029Spjd				if (*p != q[k])
1187185029Spjd					break;
1188185029Spjd
1189185029Spjd			/* Have we found it? */
1190185029Spjd			if (k >= size && *p == U8_TBL_ELEMENT_FILLER) {
1191185029Spjd				match_not_found = B_FALSE;
1192185029Spjd
1193185029Spjd				l = saved_l;
1194185029Spjd
1195185029Spjd				while (*++p != U8_TBL_ELEMENT_FILLER)
1196185029Spjd					t[l++] = *p;
1197185029Spjd
1198185029Spjd				break;
1199185029Spjd			}
1200185029Spjd
1201185029Spjd			/* We didn't find; skip to the next pair. */
1202185029Spjd			if (*p != U8_TBL_ELEMENT_FILLER)
1203185029Spjd				while (*++p != U8_TBL_ELEMENT_FILLER)
1204185029Spjd					;
1205185029Spjd			while (*++p != U8_TBL_ELEMENT_FILLER)
1206185029Spjd				;
1207185029Spjd			p++;
1208185029Spjd		}
1209185029Spjd
1210185029Spjd		/*
1211185029Spjd		 * If there was no match, we will need to save the combining
1212185029Spjd		 * mark for later appending. After that, if the next one
1213185029Spjd		 * is a non-Starter and not blocked, then, we try once
1214185029Spjd		 * again to do composition with the next non-Starter.
1215185029Spjd		 *
1216185029Spjd		 * If there was no match and this was a Starter, then,
1217185029Spjd		 * this is a new start.
1218185029Spjd		 *
1219185029Spjd		 * If there was a match and a composition done and we have
1220185029Spjd		 * more to check on, then, we retrieve a new composition final
1221185029Spjd		 * table entry for the composite and then try to do the
1222185029Spjd		 * composition again.
1223185029Spjd		 */
1224185029Spjd
1225185029Spjd		if (match_not_found) {
1226185029Spjd			if (comb_class[i] == U8_COMBINING_CLASS_STARTER) {
1227185029Spjd				i--;
1228185029Spjd				goto SAVE_THE_CHAR;
1229185029Spjd			}
1230185029Spjd
1231185029Spjd			saved_marks[saved_marks_count++] = i;
1232185029Spjd		}
1233185029Spjd
1234185029Spjd		if (saved_l == l) {
1235185029Spjd			while (i < last) {
1236185029Spjd				if (blocked(comb_class, i + 1))
1237185029Spjd					saved_marks[saved_marks_count++] = ++i;
1238185029Spjd				else
1239185029Spjd					break;
1240185029Spjd			}
1241185029Spjd			if (i < last) {
1242185029Spjd				p = saved_p;
1243185029Spjd				goto TRY_THE_NEXT_MARK;
1244185029Spjd			}
1245185029Spjd		} else if (i < last) {
1246185029Spjd			p = find_composition_start(uv, t + saved_l,
1247185029Spjd			    l - saved_l);
1248185029Spjd			if (p != NULL) {
1249185029Spjd				saved_p = p;
1250185029Spjd				goto TRY_THE_NEXT_MARK;
1251185029Spjd			}
1252185029Spjd		}
1253185029Spjd
1254185029Spjd		/*
1255185029Spjd		 * There is no more composition possible.
1256185029Spjd		 *
1257185029Spjd		 * If there was no composition what so ever then we copy
1258185029Spjd		 * over the original Starter and then append any non-Starters
1259185029Spjd		 * remaining at the target string sequentially after that.
1260185029Spjd		 */
1261185029Spjd
1262185029Spjd		if (saved_l == l) {
1263185029Spjd			p = s + start[saved_i];
1264185029Spjd			size = disp[saved_i];
1265185029Spjd			for (j = 0; j < size; j++)
1266185029Spjd				t[l++] = *p++;
1267185029Spjd		}
1268185029Spjd
1269185029Spjd		for (k = 0; k < saved_marks_count; k++) {
1270185029Spjd			p = s + start[saved_marks[k]];
1271185029Spjd			size = disp[saved_marks[k]];
1272185029Spjd			for (j = 0; j < size; j++)
1273185029Spjd				t[l++] = *p++;
1274185029Spjd		}
1275185029Spjd	}
1276185029Spjd
1277185029Spjd	/*
1278185029Spjd	 * If the last character is a Starter and if we have a character
1279185029Spjd	 * (possibly another Starter) that can be turned into a composite,
1280185029Spjd	 * we do so and we do so until there is no more of composition
1281185029Spjd	 * possible.
1282185029Spjd	 */
1283185029Spjd	if (comb_class[last] == U8_COMBINING_CLASS_STARTER) {
1284185029Spjd		p = *os;
1285185029Spjd		saved_l = l - disp[last];
1286185029Spjd
1287185029Spjd		while (p < oslast) {
1288185029Spjd			size = u8_number_of_bytes[*p];
1289185029Spjd			if (size <= 1 || (p + size) > oslast)
1290185029Spjd				break;
1291185029Spjd
1292185029Spjd			saved_p = p;
1293185029Spjd
1294185029Spjd			for (i = 0; i < size; i++)
1295185029Spjd				tc[i] = *p++;
1296185029Spjd
1297185029Spjd			q = find_composition_start(uv, t + saved_l,
1298185029Spjd			    l - saved_l);
1299185029Spjd			if (q == NULL) {
1300185029Spjd				p = saved_p;
1301185029Spjd				break;
1302185029Spjd			}
1303185029Spjd
1304185029Spjd			match_not_found = B_TRUE;
1305185029Spjd
1306185029Spjd			for (C = *q++; C > 0; C--) {
1307185029Spjd				for (k = 0; k < size; q++, k++)
1308185029Spjd					if (*q != tc[k])
1309185029Spjd						break;
1310185029Spjd
1311185029Spjd				if (k >= size && *q == U8_TBL_ELEMENT_FILLER) {
1312185029Spjd					match_not_found = B_FALSE;
1313185029Spjd
1314185029Spjd					l = saved_l;
1315185029Spjd
1316185029Spjd					while (*++q != U8_TBL_ELEMENT_FILLER) {
1317185029Spjd						/*
1318185029Spjd						 * This is practically
1319185029Spjd						 * impossible but we don't
1320185029Spjd						 * want to take any chances.
1321185029Spjd						 */
1322185029Spjd						if (l >=
1323185029Spjd						    U8_STREAM_SAFE_TEXT_MAX) {
1324185029Spjd							p = saved_p;
1325185029Spjd							goto SAFE_RETURN;
1326185029Spjd						}
1327185029Spjd						t[l++] = *q;
1328185029Spjd					}
1329185029Spjd
1330185029Spjd					break;
1331185029Spjd				}
1332185029Spjd
1333185029Spjd				if (*q != U8_TBL_ELEMENT_FILLER)
1334185029Spjd					while (*++q != U8_TBL_ELEMENT_FILLER)
1335185029Spjd						;
1336185029Spjd				while (*++q != U8_TBL_ELEMENT_FILLER)
1337185029Spjd					;
1338185029Spjd				q++;
1339185029Spjd			}
1340185029Spjd
1341185029Spjd			if (match_not_found) {
1342185029Spjd				p = saved_p;
1343185029Spjd				break;
1344185029Spjd			}
1345185029Spjd		}
1346185029SpjdSAFE_RETURN:
1347185029Spjd		*os = p;
1348185029Spjd	}
1349185029Spjd
1350185029Spjd	/*
1351185029Spjd	 * Now we copy over the temporary string to the target string.
1352185029Spjd	 * Since composition always reduces the number of characters or
1353185029Spjd	 * the number of characters stay, we don't need to worry about
1354185029Spjd	 * the buffer overflow here.
1355185029Spjd	 */
1356185029Spjd	for (i = 0; i < l; i++)
1357185029Spjd		s[i] = t[i];
1358185029Spjd	s[l] = '\0';
1359185029Spjd
1360185029Spjd	return (l);
1361185029Spjd}
1362185029Spjd
1363185029Spjd/*
1364185029Spjd * The collect_a_seq() function checks on the given string s, collect
1365185029Spjd * a sequence of characters at u8s, and return the sequence. While it collects
1366185029Spjd * a sequence, it also applies case conversion, canonical or compatibility
1367185029Spjd * decomposition, canonical decomposition, or some or all of them and
1368185029Spjd * in that order.
1369185029Spjd *
1370185029Spjd * The collected sequence cannot be bigger than 32 characters since if
1371185029Spjd * it is having more than 31 characters, the sequence will be terminated
1372185029Spjd * with a U+034F COMBINING GRAPHEME JOINER (CGJ) character and turned into
1373185029Spjd * a Stream-Safe Text. The collected sequence is always terminated with
1374185029Spjd * a null byte and the return value is the byte length of the sequence
1375185029Spjd * including 0. The return value does not include the terminating
1376185029Spjd * null byte.
1377185029Spjd */
1378185029Spjdstatic size_t
1379185029Spjdcollect_a_seq(size_t uv, uchar_t *u8s, uchar_t **source, uchar_t *slast,
1380185029Spjd	boolean_t is_it_toupper,
1381185029Spjd	boolean_t is_it_tolower,
1382185029Spjd	boolean_t canonical_decomposition,
1383185029Spjd	boolean_t compatibility_decomposition,
1384185029Spjd	boolean_t canonical_composition,
1385185029Spjd	int *errnum, u8_normalization_states_t *state)
1386185029Spjd{
1387185029Spjd	uchar_t *s;
1388185029Spjd	int sz;
1389185029Spjd	int saved_sz;
1390185029Spjd	size_t i;
1391185029Spjd	size_t j;
1392185029Spjd	size_t k;
1393185029Spjd	size_t l;
1394185029Spjd	uchar_t comb_class[U8_MAX_CHARS_A_SEQ];
1395185029Spjd	uchar_t disp[U8_MAX_CHARS_A_SEQ];
1396185029Spjd	uchar_t start[U8_MAX_CHARS_A_SEQ];
1397185029Spjd	uchar_t u8t[U8_MB_CUR_MAX];
1398185029Spjd	uchar_t uts[U8_STREAM_SAFE_TEXT_MAX + 1];
1399185029Spjd	uchar_t tc;
1400185029Spjd	size_t last;
1401185029Spjd	size_t saved_last;
1402185029Spjd	uint32_t u1;
1403185029Spjd
1404185029Spjd	/*
1405185029Spjd	 * Save the source string pointer which we will return a changed
1406185029Spjd	 * pointer if we do processing.
1407185029Spjd	 */
1408185029Spjd	s = *source;
1409185029Spjd
1410185029Spjd	/*
1411185029Spjd	 * The following is a fallback for just in case callers are not
1412185029Spjd	 * checking the string boundaries before the calling.
1413185029Spjd	 */
1414185029Spjd	if (s >= slast) {
1415185029Spjd		u8s[0] = '\0';
1416185029Spjd
1417185029Spjd		return (0);
1418185029Spjd	}
1419185029Spjd
1420185029Spjd	/*
1421185029Spjd	 * As the first thing, let's collect a character and do case
1422185029Spjd	 * conversion if necessary.
1423185029Spjd	 */
1424185029Spjd
1425185029Spjd	sz = u8_number_of_bytes[*s];
1426185029Spjd
1427185029Spjd	if (sz < 0) {
1428185029Spjd		*errnum = EILSEQ;
1429185029Spjd
1430185029Spjd		u8s[0] = *s++;
1431185029Spjd		u8s[1] = '\0';
1432185029Spjd
1433185029Spjd		*source = s;
1434185029Spjd
1435185029Spjd		return (1);
1436185029Spjd	}
1437185029Spjd
1438185029Spjd	if (sz == 1) {
1439185029Spjd		if (is_it_toupper)
1440185029Spjd			u8s[0] = U8_ASCII_TOUPPER(*s);
1441185029Spjd		else if (is_it_tolower)
1442185029Spjd			u8s[0] = U8_ASCII_TOLOWER(*s);
1443185029Spjd		else
1444185029Spjd			u8s[0] = *s;
1445185029Spjd		s++;
1446185029Spjd		u8s[1] = '\0';
1447185029Spjd	} else if ((s + sz) > slast) {
1448185029Spjd		*errnum = EINVAL;
1449185029Spjd
1450185029Spjd		for (i = 0; s < slast; )
1451185029Spjd			u8s[i++] = *s++;
1452185029Spjd		u8s[i] = '\0';
1453185029Spjd
1454185029Spjd		*source = s;
1455185029Spjd
1456185029Spjd		return (i);
1457185029Spjd	} else {
1458185029Spjd		if (is_it_toupper || is_it_tolower) {
1459185029Spjd			i = do_case_conv(uv, u8s, s, sz, is_it_toupper);
1460185029Spjd			s += sz;
1461185029Spjd			sz = i;
1462185029Spjd		} else {
1463185029Spjd			for (i = 0; i < sz; )
1464185029Spjd				u8s[i++] = *s++;
1465185029Spjd			u8s[i] = '\0';
1466185029Spjd		}
1467185029Spjd	}
1468185029Spjd
1469185029Spjd	/*
1470185029Spjd	 * And then canonical/compatibility decomposition followed by
1471185029Spjd	 * an optional canonical composition. Please be noted that
1472185029Spjd	 * canonical composition is done only when a decomposition is
1473185029Spjd	 * done.
1474185029Spjd	 */
1475185029Spjd	if (canonical_decomposition || compatibility_decomposition) {
1476185029Spjd		if (sz == 1) {
1477185029Spjd			*state = U8_STATE_START;
1478185029Spjd
1479185029Spjd			saved_sz = 1;
1480185029Spjd
1481185029Spjd			comb_class[0] = 0;
1482185029Spjd			start[0] = 0;
1483185029Spjd			disp[0] = 1;
1484185029Spjd
1485185029Spjd			last = 1;
1486185029Spjd		} else {
1487185029Spjd			saved_sz = do_decomp(uv, u8s, u8s, sz,
1488185029Spjd			    canonical_decomposition, state);
1489185029Spjd
1490185029Spjd			last = 0;
1491185029Spjd
1492185029Spjd			for (i = 0; i < saved_sz; ) {
1493185029Spjd				sz = u8_number_of_bytes[u8s[i]];
1494185029Spjd
1495185029Spjd				comb_class[last] = combining_class(uv,
1496185029Spjd				    u8s + i, sz);
1497185029Spjd				start[last] = i;
1498185029Spjd				disp[last] = sz;
1499185029Spjd
1500185029Spjd				last++;
1501185029Spjd				i += sz;
1502185029Spjd			}
1503185029Spjd
1504185029Spjd			/*
1505185029Spjd			 * Decomposition yields various Hangul related
1506185029Spjd			 * states but not on combining marks. We need to
1507185029Spjd			 * find out at here by checking on the last
1508185029Spjd			 * character.
1509185029Spjd			 */
1510185029Spjd			if (*state == U8_STATE_START) {
1511185029Spjd				if (comb_class[last - 1])
1512185029Spjd					*state = U8_STATE_COMBINING_MARK;
1513185029Spjd			}
1514185029Spjd		}
1515185029Spjd
1516185029Spjd		saved_last = last;
1517185029Spjd
1518185029Spjd		while (s < slast) {
1519185029Spjd			sz = u8_number_of_bytes[*s];
1520185029Spjd
1521185029Spjd			/*
1522185029Spjd			 * If this is an illegal character, an incomplete
1523185029Spjd			 * character, or an 7-bit ASCII Starter character,
1524185029Spjd			 * then we have collected a sequence; break and let
1525185029Spjd			 * the next call deal with the two cases.
1526185029Spjd			 *
1527185029Spjd			 * Note that this is okay only if you are using this
1528185029Spjd			 * function with a fixed length string, not on
1529185029Spjd			 * a buffer with multiple calls of one chunk at a time.
1530185029Spjd			 */
1531185029Spjd			if (sz <= 1) {
1532185029Spjd				break;
1533185029Spjd			} else if ((s + sz) > slast) {
1534185029Spjd				break;
1535185029Spjd			} else {
1536185029Spjd				/*
1537185029Spjd				 * If the previous character was a Hangul Jamo
1538185029Spjd				 * and this character is a Hangul Jamo that
1539185029Spjd				 * can be conjoined, we collect the Jamo.
1540185029Spjd				 */
1541185029Spjd				if (*s == U8_HANGUL_JAMO_1ST_BYTE) {
1542185029Spjd					U8_PUT_3BYTES_INTO_UTF32(u1,
1543185029Spjd					    *s, *(s + 1), *(s + 2));
1544185029Spjd
1545185029Spjd					if (U8_HANGUL_COMPOSABLE_L_V(*state,
1546185029Spjd					    u1)) {
1547185029Spjd						i = 0;
1548185029Spjd						*state = U8_STATE_HANGUL_LV;
1549185029Spjd						goto COLLECT_A_HANGUL;
1550185029Spjd					}
1551185029Spjd
1552185029Spjd					if (U8_HANGUL_COMPOSABLE_LV_T(*state,
1553185029Spjd					    u1)) {
1554185029Spjd						i = 0;
1555185029Spjd						*state = U8_STATE_HANGUL_LVT;
1556185029Spjd						goto COLLECT_A_HANGUL;
1557185029Spjd					}
1558185029Spjd				}
1559185029Spjd
1560185029Spjd				/*
1561185029Spjd				 * Regardless of whatever it was, if this is
1562185029Spjd				 * a Starter, we don't collect the character
1563185029Spjd				 * since that's a new start and we will deal
1564185029Spjd				 * with it at the next time.
1565185029Spjd				 */
1566185029Spjd				i = combining_class(uv, s, sz);
1567185029Spjd				if (i == U8_COMBINING_CLASS_STARTER)
1568185029Spjd					break;
1569185029Spjd
1570185029Spjd				/*
1571185029Spjd				 * We know the current character is a combining
1572185029Spjd				 * mark. If the previous character wasn't
1573185029Spjd				 * a Starter (not Hangul) or a combining mark,
1574185029Spjd				 * then, we don't collect this combining mark.
1575185029Spjd				 */
1576185029Spjd				if (*state != U8_STATE_START &&
1577185029Spjd				    *state != U8_STATE_COMBINING_MARK)
1578185029Spjd					break;
1579185029Spjd
1580185029Spjd				*state = U8_STATE_COMBINING_MARK;
1581185029SpjdCOLLECT_A_HANGUL:
1582185029Spjd				/*
1583185029Spjd				 * If we collected a Starter and combining
1584185029Spjd				 * marks up to 30, i.e., total 31 characters,
1585185029Spjd				 * then, we terminate this degenerately long
1586185029Spjd				 * combining sequence with a U+034F COMBINING
1587185029Spjd				 * GRAPHEME JOINER (CGJ) which is 0xCD 0x8F in
1588185029Spjd				 * UTF-8 and turn this into a Stream-Safe
1589185029Spjd				 * Text. This will be extremely rare but
1590185029Spjd				 * possible.
1591185029Spjd				 *
1592185029Spjd				 * The following will also guarantee that
1593185029Spjd				 * we are not writing more than 32 characters
1594185029Spjd				 * plus a NULL at u8s[].
1595185029Spjd				 */
1596185029Spjd				if (last >= U8_UPPER_LIMIT_IN_A_SEQ) {
1597185029SpjdTURN_STREAM_SAFE:
1598185029Spjd					*state = U8_STATE_START;
1599185029Spjd					comb_class[last] = 0;
1600185029Spjd					start[last] = saved_sz;
1601185029Spjd					disp[last] = 2;
1602185029Spjd					last++;
1603185029Spjd
1604185029Spjd					u8s[saved_sz++] = 0xCD;
1605185029Spjd					u8s[saved_sz++] = 0x8F;
1606185029Spjd
1607185029Spjd					break;
1608185029Spjd				}
1609185029Spjd
1610185029Spjd				/*
1611185029Spjd				 * Some combining marks also do decompose into
1612185029Spjd				 * another combining mark or marks.
1613185029Spjd				 */
1614185029Spjd				if (*state == U8_STATE_COMBINING_MARK) {
1615185029Spjd					k = last;
1616185029Spjd					l = sz;
1617185029Spjd					i = do_decomp(uv, uts, s, sz,
1618185029Spjd					    canonical_decomposition, state);
1619185029Spjd					for (j = 0; j < i; ) {
1620185029Spjd						sz = u8_number_of_bytes[uts[j]];
1621185029Spjd
1622185029Spjd						comb_class[last] =
1623185029Spjd						    combining_class(uv,
1624185029Spjd						    uts + j, sz);
1625185029Spjd						start[last] = saved_sz + j;
1626185029Spjd						disp[last] = sz;
1627185029Spjd
1628185029Spjd						last++;
1629185029Spjd						if (last >=
1630185029Spjd						    U8_UPPER_LIMIT_IN_A_SEQ) {
1631185029Spjd							last = k;
1632185029Spjd							goto TURN_STREAM_SAFE;
1633185029Spjd						}
1634185029Spjd						j += sz;
1635185029Spjd					}
1636185029Spjd
1637185029Spjd					*state = U8_STATE_COMBINING_MARK;
1638185029Spjd					sz = i;
1639185029Spjd					s += l;
1640185029Spjd
1641185029Spjd					for (i = 0; i < sz; i++)
1642185029Spjd						u8s[saved_sz++] = uts[i];
1643185029Spjd				} else {
1644185029Spjd					comb_class[last] = i;
1645185029Spjd					start[last] = saved_sz;
1646185029Spjd					disp[last] = sz;
1647185029Spjd					last++;
1648185029Spjd
1649185029Spjd					for (i = 0; i < sz; i++)
1650185029Spjd						u8s[saved_sz++] = *s++;
1651185029Spjd				}
1652185029Spjd
1653185029Spjd				/*
1654185029Spjd				 * If this is U+0345 COMBINING GREEK
1655185029Spjd				 * YPOGEGRAMMENI (0xCD 0x85 in UTF-8), a.k.a.,
1656185029Spjd				 * iota subscript, and need to be converted to
1657185029Spjd				 * uppercase letter, convert it to U+0399 GREEK
1658185029Spjd				 * CAPITAL LETTER IOTA (0xCE 0x99 in UTF-8),
1659185029Spjd				 * i.e., convert to capital adscript form as
1660185029Spjd				 * specified in the Unicode standard.
1661185029Spjd				 *
1662185029Spjd				 * This is the only special case of (ambiguous)
1663185029Spjd				 * case conversion at combining marks and
1664185029Spjd				 * probably the standard will never have
1665185029Spjd				 * anything similar like this in future.
1666185029Spjd				 */
1667185029Spjd				if (is_it_toupper && sz >= 2 &&
1668185029Spjd				    u8s[saved_sz - 2] == 0xCD &&
1669185029Spjd				    u8s[saved_sz - 1] == 0x85) {
1670185029Spjd					u8s[saved_sz - 2] = 0xCE;
1671185029Spjd					u8s[saved_sz - 1] = 0x99;
1672185029Spjd				}
1673185029Spjd			}
1674185029Spjd		}
1675185029Spjd
1676185029Spjd		/*
1677185029Spjd		 * Let's try to ensure a canonical ordering for the collected
1678185029Spjd		 * combining marks. We do this only if we have collected
1679185029Spjd		 * at least one more non-Starter. (The decomposition mapping
1680185029Spjd		 * data tables have fully (and recursively) expanded and
1681185029Spjd		 * canonically ordered decompositions.)
1682185029Spjd		 *
1683185029Spjd		 * The U8_SWAP_COMB_MARKS() convenience macro has some
1684185029Spjd		 * assumptions and we are meeting the assumptions.
1685185029Spjd		 */
1686185029Spjd		last--;
1687185029Spjd		if (last >= saved_last) {
1688185029Spjd			for (i = 0; i < last; i++)
1689185029Spjd				for (j = last; j > i; j--)
1690185029Spjd					if (comb_class[j] &&
1691185029Spjd					    comb_class[j - 1] > comb_class[j]) {
1692185029Spjd						U8_SWAP_COMB_MARKS(j - 1, j);
1693185029Spjd					}
1694185029Spjd		}
1695185029Spjd
1696185029Spjd		*source = s;
1697185029Spjd
1698185029Spjd		if (! canonical_composition) {
1699185029Spjd			u8s[saved_sz] = '\0';
1700185029Spjd			return (saved_sz);
1701185029Spjd		}
1702185029Spjd
1703185029Spjd		/*
1704185029Spjd		 * Now do the canonical composition. Note that we do this
1705185029Spjd		 * only after a canonical or compatibility decomposition to
1706185029Spjd		 * finish up NFC or NFKC.
1707185029Spjd		 */
1708185029Spjd		sz = do_composition(uv, u8s, comb_class, start, disp, last,
1709185029Spjd		    &s, slast);
1710185029Spjd	}
1711185029Spjd
1712185029Spjd	*source = s;
1713185029Spjd
1714185029Spjd	return ((size_t)sz);
1715185029Spjd}
1716185029Spjd
1717185029Spjd/*
1718185029Spjd * The do_norm_compare() function does string comparion based on Unicode
1719185029Spjd * simple case mappings and Unicode Normalization definitions.
1720185029Spjd *
1721185029Spjd * It does so by collecting a sequence of character at a time and comparing
1722185029Spjd * the collected sequences from the strings.
1723185029Spjd *
1724185029Spjd * The meanings on the return values are the same as the usual strcmp().
1725185029Spjd */
1726185029Spjdstatic int
1727185029Spjddo_norm_compare(size_t uv, uchar_t *s1, uchar_t *s2, size_t n1, size_t n2,
1728185029Spjd	int flag, int *errnum)
1729185029Spjd{
1730185029Spjd	int result;
1731185029Spjd	size_t sz1;
1732185029Spjd	size_t sz2;
1733185029Spjd	uchar_t u8s1[U8_STREAM_SAFE_TEXT_MAX + 1];
1734185029Spjd	uchar_t u8s2[U8_STREAM_SAFE_TEXT_MAX + 1];
1735185029Spjd	uchar_t *s1last;
1736185029Spjd	uchar_t *s2last;
1737185029Spjd	boolean_t is_it_toupper;
1738185029Spjd	boolean_t is_it_tolower;
1739185029Spjd	boolean_t canonical_decomposition;
1740185029Spjd	boolean_t compatibility_decomposition;
1741185029Spjd	boolean_t canonical_composition;
1742185029Spjd	u8_normalization_states_t state;
1743185029Spjd
1744185029Spjd	s1last = s1 + n1;
1745185029Spjd	s2last = s2 + n2;
1746185029Spjd
1747185029Spjd	is_it_toupper = flag & U8_TEXTPREP_TOUPPER;
1748185029Spjd	is_it_tolower = flag & U8_TEXTPREP_TOLOWER;
1749185029Spjd	canonical_decomposition = flag & U8_CANON_DECOMP;
1750185029Spjd	compatibility_decomposition = flag & U8_COMPAT_DECOMP;
1751185029Spjd	canonical_composition = flag & U8_CANON_COMP;
1752185029Spjd
1753185029Spjd	while (s1 < s1last && s2 < s2last) {
1754185029Spjd		/*
1755185029Spjd		 * If the current character is a 7-bit ASCII and the last
1756185029Spjd		 * character, or, if the current character and the next
1757185029Spjd		 * character are both some 7-bit ASCII characters then
1758185029Spjd		 * we treat the current character as a sequence.
1759185029Spjd		 *
1760185029Spjd		 * In any other cases, we need to call collect_a_seq().
1761185029Spjd		 */
1762185029Spjd
1763185029Spjd		if (U8_ISASCII(*s1) && ((s1 + 1) >= s1last ||
1764185029Spjd		    ((s1 + 1) < s1last && U8_ISASCII(*(s1 + 1))))) {
1765185029Spjd			if (is_it_toupper)
1766185029Spjd				u8s1[0] = U8_ASCII_TOUPPER(*s1);
1767185029Spjd			else if (is_it_tolower)
1768185029Spjd				u8s1[0] = U8_ASCII_TOLOWER(*s1);
1769185029Spjd			else
1770185029Spjd				u8s1[0] = *s1;
1771185029Spjd			u8s1[1] = '\0';
1772185029Spjd			sz1 = 1;
1773185029Spjd			s1++;
1774185029Spjd		} else {
1775185029Spjd			state = U8_STATE_START;
1776185029Spjd			sz1 = collect_a_seq(uv, u8s1, &s1, s1last,
1777185029Spjd			    is_it_toupper, is_it_tolower,
1778185029Spjd			    canonical_decomposition,
1779185029Spjd			    compatibility_decomposition,
1780185029Spjd			    canonical_composition, errnum, &state);
1781185029Spjd		}
1782185029Spjd
1783185029Spjd		if (U8_ISASCII(*s2) && ((s2 + 1) >= s2last ||
1784185029Spjd		    ((s2 + 1) < s2last && U8_ISASCII(*(s2 + 1))))) {
1785185029Spjd			if (is_it_toupper)
1786185029Spjd				u8s2[0] = U8_ASCII_TOUPPER(*s2);
1787185029Spjd			else if (is_it_tolower)
1788185029Spjd				u8s2[0] = U8_ASCII_TOLOWER(*s2);
1789185029Spjd			else
1790185029Spjd				u8s2[0] = *s2;
1791185029Spjd			u8s2[1] = '\0';
1792185029Spjd			sz2 = 1;
1793185029Spjd			s2++;
1794185029Spjd		} else {
1795185029Spjd			state = U8_STATE_START;
1796185029Spjd			sz2 = collect_a_seq(uv, u8s2, &s2, s2last,
1797185029Spjd			    is_it_toupper, is_it_tolower,
1798185029Spjd			    canonical_decomposition,
1799185029Spjd			    compatibility_decomposition,
1800185029Spjd			    canonical_composition, errnum, &state);
1801185029Spjd		}
1802185029Spjd
1803185029Spjd		/*
1804185029Spjd		 * Now compare the two characters. If they are the same,
1805185029Spjd		 * we move on to the next character sequences.
1806185029Spjd		 */
1807185029Spjd		if (sz1 == 1 && sz2 == 1) {
1808185029Spjd			if (*u8s1 > *u8s2)
1809185029Spjd				return (1);
1810185029Spjd			if (*u8s1 < *u8s2)
1811185029Spjd				return (-1);
1812185029Spjd		} else {
1813185029Spjd			result = strcmp((const char *)u8s1, (const char *)u8s2);
1814185029Spjd			if (result != 0)
1815185029Spjd				return (result);
1816185029Spjd		}
1817185029Spjd	}
1818185029Spjd
1819185029Spjd	/*
1820185029Spjd	 * We compared until the end of either or both strings.
1821185029Spjd	 *
1822185029Spjd	 * If we reached to or went over the ends for the both, that means
1823185029Spjd	 * they are the same.
1824185029Spjd	 *
1825185029Spjd	 * If we reached only one end, that means the other string has
1826185029Spjd	 * something which then can be used to determine the return value.
1827185029Spjd	 */
1828185029Spjd	if (s1 >= s1last) {
1829185029Spjd		if (s2 >= s2last)
1830185029Spjd			return (0);
1831185029Spjd		return (-1);
1832185029Spjd	}
1833185029Spjd	return (1);
1834185029Spjd}
1835185029Spjd
1836185029Spjd/*
1837185029Spjd * The u8_strcmp() function compares two UTF-8 strings quite similar to
1838185029Spjd * the strcmp(). For the comparison, however, Unicode Normalization specific
1839185029Spjd * equivalency and Unicode simple case conversion mappings based equivalency
1840185029Spjd * can be requested and checked against.
1841185029Spjd */
1842185029Spjdint
1843185029Spjdu8_strcmp(const char *s1, const char *s2, size_t n, int flag, size_t uv,
1844185029Spjd		int *errnum)
1845185029Spjd{
1846185029Spjd	int f;
1847185029Spjd	size_t n1;
1848185029Spjd	size_t n2;
1849185029Spjd
1850185029Spjd	*errnum = 0;
1851185029Spjd
1852185029Spjd	/*
1853185029Spjd	 * Check on the requested Unicode version, case conversion, and
1854185029Spjd	 * normalization flag values.
1855185029Spjd	 */
1856185029Spjd
1857185029Spjd	if (uv > U8_UNICODE_LATEST) {
1858185029Spjd		*errnum = ERANGE;
1859185029Spjd		uv = U8_UNICODE_LATEST;
1860185029Spjd	}
1861185029Spjd
1862185029Spjd	if (flag == 0) {
1863185029Spjd		flag = U8_STRCMP_CS;
1864185029Spjd	} else {
1865185029Spjd		f = flag & (U8_STRCMP_CS | U8_STRCMP_CI_UPPER |
1866185029Spjd		    U8_STRCMP_CI_LOWER);
1867185029Spjd		if (f == 0) {
1868185029Spjd			flag |= U8_STRCMP_CS;
1869185029Spjd		} else if (f != U8_STRCMP_CS && f != U8_STRCMP_CI_UPPER &&
1870185029Spjd		    f != U8_STRCMP_CI_LOWER) {
1871185029Spjd			*errnum = EBADF;
1872185029Spjd			flag = U8_STRCMP_CS;
1873185029Spjd		}
1874185029Spjd
1875185029Spjd		f = flag & (U8_CANON_DECOMP | U8_COMPAT_DECOMP | U8_CANON_COMP);
1876185029Spjd		if (f && f != U8_STRCMP_NFD && f != U8_STRCMP_NFC &&
1877185029Spjd		    f != U8_STRCMP_NFKD && f != U8_STRCMP_NFKC) {
1878185029Spjd			*errnum = EBADF;
1879185029Spjd			flag = U8_STRCMP_CS;
1880185029Spjd		}
1881185029Spjd	}
1882185029Spjd
1883185029Spjd	if (flag == U8_STRCMP_CS) {
1884185029Spjd		return (n == 0 ? strcmp(s1, s2) : strncmp(s1, s2, n));
1885185029Spjd	}
1886185029Spjd
1887185029Spjd	n1 = strlen(s1);
1888185029Spjd	n2 = strlen(s2);
1889185029Spjd	if (n != 0) {
1890185029Spjd		if (n < n1)
1891185029Spjd			n1 = n;
1892185029Spjd		if (n < n2)
1893185029Spjd			n2 = n;
1894185029Spjd	}
1895185029Spjd
1896185029Spjd	/*
1897185029Spjd	 * Simple case conversion can be done much faster and so we do
1898185029Spjd	 * them separately here.
1899185029Spjd	 */
1900185029Spjd	if (flag == U8_STRCMP_CI_UPPER) {
1901185029Spjd		return (do_case_compare(uv, (uchar_t *)s1, (uchar_t *)s2,
1902185029Spjd		    n1, n2, B_TRUE, errnum));
1903185029Spjd	} else if (flag == U8_STRCMP_CI_LOWER) {
1904185029Spjd		return (do_case_compare(uv, (uchar_t *)s1, (uchar_t *)s2,
1905185029Spjd		    n1, n2, B_FALSE, errnum));
1906185029Spjd	}
1907185029Spjd
1908185029Spjd	return (do_norm_compare(uv, (uchar_t *)s1, (uchar_t *)s2, n1, n2,
1909185029Spjd	    flag, errnum));
1910185029Spjd}
1911185029Spjd
1912185029Spjdsize_t
1913185029Spjdu8_textprep_str(char *inarray, size_t *inlen, char *outarray, size_t *outlen,
1914185029Spjd	int flag, size_t unicode_version, int *errnum)
1915185029Spjd{
1916185029Spjd	int f;
1917185029Spjd	int sz;
1918185029Spjd	uchar_t *ib;
1919185029Spjd	uchar_t *ibtail;
1920185029Spjd	uchar_t *ob;
1921185029Spjd	uchar_t *obtail;
1922185029Spjd	boolean_t do_not_ignore_null;
1923185029Spjd	boolean_t do_not_ignore_invalid;
1924185029Spjd	boolean_t is_it_toupper;
1925185029Spjd	boolean_t is_it_tolower;
1926185029Spjd	boolean_t canonical_decomposition;
1927185029Spjd	boolean_t compatibility_decomposition;
1928185029Spjd	boolean_t canonical_composition;
1929185029Spjd	size_t ret_val;
1930185029Spjd	size_t i;
1931185029Spjd	size_t j;
1932185029Spjd	uchar_t u8s[U8_STREAM_SAFE_TEXT_MAX + 1];
1933185029Spjd	u8_normalization_states_t state;
1934185029Spjd
1935185029Spjd	if (unicode_version > U8_UNICODE_LATEST) {
1936185029Spjd		*errnum = ERANGE;
1937185029Spjd		return ((size_t)-1);
1938185029Spjd	}
1939185029Spjd
1940185029Spjd	f = flag & (U8_TEXTPREP_TOUPPER | U8_TEXTPREP_TOLOWER);
1941185029Spjd	if (f == (U8_TEXTPREP_TOUPPER | U8_TEXTPREP_TOLOWER)) {
1942185029Spjd		*errnum = EBADF;
1943185029Spjd		return ((size_t)-1);
1944185029Spjd	}
1945185029Spjd
1946185029Spjd	f = flag & (U8_CANON_DECOMP | U8_COMPAT_DECOMP | U8_CANON_COMP);
1947185029Spjd	if (f && f != U8_TEXTPREP_NFD && f != U8_TEXTPREP_NFC &&
1948185029Spjd	    f != U8_TEXTPREP_NFKD && f != U8_TEXTPREP_NFKC) {
1949185029Spjd		*errnum = EBADF;
1950185029Spjd		return ((size_t)-1);
1951185029Spjd	}
1952185029Spjd
1953185029Spjd	if (inarray == NULL || *inlen == 0)
1954185029Spjd		return (0);
1955185029Spjd
1956185029Spjd	if (outarray == NULL) {
1957185029Spjd		*errnum = E2BIG;
1958185029Spjd		return ((size_t)-1);
1959185029Spjd	}
1960185029Spjd
1961185029Spjd	ib = (uchar_t *)inarray;
1962185029Spjd	ob = (uchar_t *)outarray;
1963185029Spjd	ibtail = ib + *inlen;
1964185029Spjd	obtail = ob + *outlen;
1965185029Spjd
1966185029Spjd	do_not_ignore_null = !(flag & U8_TEXTPREP_IGNORE_NULL);
1967185029Spjd	do_not_ignore_invalid = !(flag & U8_TEXTPREP_IGNORE_INVALID);
1968185029Spjd	is_it_toupper = flag & U8_TEXTPREP_TOUPPER;
1969185029Spjd	is_it_tolower = flag & U8_TEXTPREP_TOLOWER;
1970185029Spjd
1971185029Spjd	ret_val = 0;
1972185029Spjd
1973185029Spjd	/*
1974185029Spjd	 * If we don't have a normalization flag set, we do the simple case
1975185029Spjd	 * conversion based text preparation separately below. Text
1976185029Spjd	 * preparation involving Normalization will be done in the false task
1977185029Spjd	 * block, again, separately since it will take much more time and
1978185029Spjd	 * resource than doing simple case conversions.
1979185029Spjd	 */
1980185029Spjd	if (f == 0) {
1981185029Spjd		while (ib < ibtail) {
1982185029Spjd			if (*ib == '\0' && do_not_ignore_null)
1983185029Spjd				break;
1984185029Spjd
1985185029Spjd			sz = u8_number_of_bytes[*ib];
1986185029Spjd
1987185029Spjd			if (sz < 0) {
1988185029Spjd				if (do_not_ignore_invalid) {
1989185029Spjd					*errnum = EILSEQ;
1990185029Spjd					ret_val = (size_t)-1;
1991185029Spjd					break;
1992185029Spjd				}
1993185029Spjd
1994185029Spjd				sz = 1;
1995185029Spjd				ret_val++;
1996185029Spjd			}
1997185029Spjd
1998185029Spjd			if (sz == 1) {
1999185029Spjd				if (ob >= obtail) {
2000185029Spjd					*errnum = E2BIG;
2001185029Spjd					ret_val = (size_t)-1;
2002185029Spjd					break;
2003185029Spjd				}
2004185029Spjd
2005185029Spjd				if (is_it_toupper)
2006185029Spjd					*ob = U8_ASCII_TOUPPER(*ib);
2007185029Spjd				else if (is_it_tolower)
2008185029Spjd					*ob = U8_ASCII_TOLOWER(*ib);
2009185029Spjd				else
2010185029Spjd					*ob = *ib;
2011185029Spjd				ib++;
2012185029Spjd				ob++;
2013185029Spjd			} else if ((ib + sz) > ibtail) {
2014185029Spjd				if (do_not_ignore_invalid) {
2015185029Spjd					*errnum = EINVAL;
2016185029Spjd					ret_val = (size_t)-1;
2017185029Spjd					break;
2018185029Spjd				}
2019185029Spjd
2020185029Spjd				if ((obtail - ob) < (ibtail - ib)) {
2021185029Spjd					*errnum = E2BIG;
2022185029Spjd					ret_val = (size_t)-1;
2023185029Spjd					break;
2024185029Spjd				}
2025185029Spjd
2026185029Spjd				/*
2027185029Spjd				 * We treat the remaining incomplete character
2028185029Spjd				 * bytes as a character.
2029185029Spjd				 */
2030185029Spjd				ret_val++;
2031185029Spjd
2032185029Spjd				while (ib < ibtail)
2033185029Spjd					*ob++ = *ib++;
2034185029Spjd			} else {
2035185029Spjd				if (is_it_toupper || is_it_tolower) {
2036185029Spjd					i = do_case_conv(unicode_version, u8s,
2037185029Spjd					    ib, sz, is_it_toupper);
2038185029Spjd
2039185029Spjd					if ((obtail - ob) < i) {
2040185029Spjd						*errnum = E2BIG;
2041185029Spjd						ret_val = (size_t)-1;
2042185029Spjd						break;
2043185029Spjd					}
2044185029Spjd
2045185029Spjd					ib += sz;
2046185029Spjd
2047185029Spjd					for (sz = 0; sz < i; sz++)
2048185029Spjd						*ob++ = u8s[sz];
2049185029Spjd				} else {
2050185029Spjd					if ((obtail - ob) < sz) {
2051185029Spjd						*errnum = E2BIG;
2052185029Spjd						ret_val = (size_t)-1;
2053185029Spjd						break;
2054185029Spjd					}
2055185029Spjd
2056185029Spjd					for (i = 0; i < sz; i++)
2057185029Spjd						*ob++ = *ib++;
2058185029Spjd				}
2059185029Spjd			}
2060185029Spjd		}
2061185029Spjd	} else {
2062185029Spjd		canonical_decomposition = flag & U8_CANON_DECOMP;
2063185029Spjd		compatibility_decomposition = flag & U8_COMPAT_DECOMP;
2064185029Spjd		canonical_composition = flag & U8_CANON_COMP;
2065185029Spjd
2066185029Spjd		while (ib < ibtail) {
2067185029Spjd			if (*ib == '\0' && do_not_ignore_null)
2068185029Spjd				break;
2069185029Spjd
2070185029Spjd			/*
2071185029Spjd			 * If the current character is a 7-bit ASCII
2072185029Spjd			 * character and it is the last character, or,
2073185029Spjd			 * if the current character is a 7-bit ASCII
2074185029Spjd			 * character and the next character is also a 7-bit
2075185029Spjd			 * ASCII character, then, we copy over this
2076185029Spjd			 * character without going through collect_a_seq().
2077185029Spjd			 *
2078185029Spjd			 * In any other cases, we need to look further with
2079185029Spjd			 * the collect_a_seq() function.
2080185029Spjd			 */
2081185029Spjd			if (U8_ISASCII(*ib) && ((ib + 1) >= ibtail ||
2082185029Spjd			    ((ib + 1) < ibtail && U8_ISASCII(*(ib + 1))))) {
2083185029Spjd				if (ob >= obtail) {
2084185029Spjd					*errnum = E2BIG;
2085185029Spjd					ret_val = (size_t)-1;
2086185029Spjd					break;
2087185029Spjd				}
2088185029Spjd
2089185029Spjd				if (is_it_toupper)
2090185029Spjd					*ob = U8_ASCII_TOUPPER(*ib);
2091185029Spjd				else if (is_it_tolower)
2092185029Spjd					*ob = U8_ASCII_TOLOWER(*ib);
2093185029Spjd				else
2094185029Spjd					*ob = *ib;
2095185029Spjd				ib++;
2096185029Spjd				ob++;
2097185029Spjd			} else {
2098185029Spjd				*errnum = 0;
2099185029Spjd				state = U8_STATE_START;
2100185029Spjd
2101185029Spjd				j = collect_a_seq(unicode_version, u8s,
2102185029Spjd				    &ib, ibtail,
2103185029Spjd				    is_it_toupper,
2104185029Spjd				    is_it_tolower,
2105185029Spjd				    canonical_decomposition,
2106185029Spjd				    compatibility_decomposition,
2107185029Spjd				    canonical_composition,
2108185029Spjd				    errnum, &state);
2109185029Spjd
2110185029Spjd				if (*errnum && do_not_ignore_invalid) {
2111185029Spjd					ret_val = (size_t)-1;
2112185029Spjd					break;
2113185029Spjd				}
2114185029Spjd
2115185029Spjd				if ((obtail - ob) < j) {
2116185029Spjd					*errnum = E2BIG;
2117185029Spjd					ret_val = (size_t)-1;
2118185029Spjd					break;
2119185029Spjd				}
2120185029Spjd
2121185029Spjd				for (i = 0; i < j; i++)
2122185029Spjd					*ob++ = u8s[i];
2123185029Spjd			}
2124185029Spjd		}
2125185029Spjd	}
2126185029Spjd
2127185029Spjd	*inlen = ibtail - ib;
2128185029Spjd	*outlen = obtail - ob;
2129185029Spjd
2130185029Spjd	return (ret_val);
2131185029Spjd}
2132