xref: /onnv-gate/usr/src/lib/gss_mechs/mech_krb5/support/utf8.c (revision 10598:6f30db2c2cd0)
1*10598SGlenn.Barry@Sun.COM /*
2*10598SGlenn.Barry@Sun.COM  * util/support/utf8.c
3*10598SGlenn.Barry@Sun.COM  *
4*10598SGlenn.Barry@Sun.COM  * Copyright 2008 by the Massachusetts Institute of Technology.
5*10598SGlenn.Barry@Sun.COM  * All Rights Reserved.
6*10598SGlenn.Barry@Sun.COM  *
7*10598SGlenn.Barry@Sun.COM  * Export of this software from the United States of America may
8*10598SGlenn.Barry@Sun.COM  *   require a specific license from the United States Government.
9*10598SGlenn.Barry@Sun.COM  *   It is the responsibility of any person or organization contemplating
10*10598SGlenn.Barry@Sun.COM  *   export to obtain such a license before exporting.
11*10598SGlenn.Barry@Sun.COM  *
12*10598SGlenn.Barry@Sun.COM  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*10598SGlenn.Barry@Sun.COM  * distribute this software and its documentation for any purpose and
14*10598SGlenn.Barry@Sun.COM  * without fee is hereby granted, provided that the above copyright
15*10598SGlenn.Barry@Sun.COM  * notice appear in all copies and that both that copyright notice and
16*10598SGlenn.Barry@Sun.COM  * this permission notice appear in supporting documentation, and that
17*10598SGlenn.Barry@Sun.COM  * the name of M.I.T. not be used in advertising or publicity pertaining
18*10598SGlenn.Barry@Sun.COM  * to distribution of the software without specific, written prior
19*10598SGlenn.Barry@Sun.COM  * permission.  Furthermore if you modify this software you must label
20*10598SGlenn.Barry@Sun.COM  * your software as modified software and not distribute it in such a
21*10598SGlenn.Barry@Sun.COM  * fashion that it might be confused with the original M.I.T. software.
22*10598SGlenn.Barry@Sun.COM  * M.I.T. makes no representations about the suitability of
23*10598SGlenn.Barry@Sun.COM  * this software for any purpose.  It is provided "as is" without express
24*10598SGlenn.Barry@Sun.COM  * or implied warranty.
25*10598SGlenn.Barry@Sun.COM  */
26*10598SGlenn.Barry@Sun.COM /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
27*10598SGlenn.Barry@Sun.COM  *
28*10598SGlenn.Barry@Sun.COM  * Copyright 1998-2008 The OpenLDAP Foundation.
29*10598SGlenn.Barry@Sun.COM  * All rights reserved.
30*10598SGlenn.Barry@Sun.COM  *
31*10598SGlenn.Barry@Sun.COM  * Redistribution and use in source and binary forms, with or without
32*10598SGlenn.Barry@Sun.COM  * modification, are permitted only as authorized by the OpenLDAP
33*10598SGlenn.Barry@Sun.COM  * Public License.
34*10598SGlenn.Barry@Sun.COM  *
35*10598SGlenn.Barry@Sun.COM  * A copy of this license is available in the file LICENSE in the
36*10598SGlenn.Barry@Sun.COM  * top-level directory of the distribution or, alternatively, at
37*10598SGlenn.Barry@Sun.COM  * <http://www.OpenLDAP.org/license.html>.
38*10598SGlenn.Barry@Sun.COM  */
39*10598SGlenn.Barry@Sun.COM /* Basic UTF-8 routines
40*10598SGlenn.Barry@Sun.COM  *
41*10598SGlenn.Barry@Sun.COM  * These routines are "dumb".  Though they understand UTF-8,
42*10598SGlenn.Barry@Sun.COM  * they don't grok Unicode.  That is, they can push bits,
43*10598SGlenn.Barry@Sun.COM  * but don't have a clue what the bits represent.  That's
44*10598SGlenn.Barry@Sun.COM  * good enough for use with the KRB5 Client SDK.
45*10598SGlenn.Barry@Sun.COM  *
46*10598SGlenn.Barry@Sun.COM  * These routines are not optimized.
47*10598SGlenn.Barry@Sun.COM  */
48*10598SGlenn.Barry@Sun.COM 
49*10598SGlenn.Barry@Sun.COM #include "k5-platform.h"
50*10598SGlenn.Barry@Sun.COM #include "k5-utf8.h"
51*10598SGlenn.Barry@Sun.COM #include "supp-int.h"
52*10598SGlenn.Barry@Sun.COM 
53*10598SGlenn.Barry@Sun.COM /*
54*10598SGlenn.Barry@Sun.COM  * return the number of bytes required to hold the
55*10598SGlenn.Barry@Sun.COM  * NULL-terminated UTF-8 string NOT INCLUDING the
56*10598SGlenn.Barry@Sun.COM  * termination.
57*10598SGlenn.Barry@Sun.COM  */
krb5int_utf8_bytes(const char * p)58*10598SGlenn.Barry@Sun.COM size_t krb5int_utf8_bytes(const char *p)
59*10598SGlenn.Barry@Sun.COM {
60*10598SGlenn.Barry@Sun.COM     size_t bytes;
61*10598SGlenn.Barry@Sun.COM 
62*10598SGlenn.Barry@Sun.COM     for (bytes = 0; p[bytes]; bytes++)
63*10598SGlenn.Barry@Sun.COM 	;
64*10598SGlenn.Barry@Sun.COM 
65*10598SGlenn.Barry@Sun.COM     return bytes;
66*10598SGlenn.Barry@Sun.COM }
67*10598SGlenn.Barry@Sun.COM 
krb5int_utf8_chars(const char * p)68*10598SGlenn.Barry@Sun.COM size_t krb5int_utf8_chars(const char *p)
69*10598SGlenn.Barry@Sun.COM {
70*10598SGlenn.Barry@Sun.COM     /* could be optimized and could check for invalid sequences */
71*10598SGlenn.Barry@Sun.COM     size_t chars = 0;
72*10598SGlenn.Barry@Sun.COM 
73*10598SGlenn.Barry@Sun.COM     for ( ; *p ; KRB5_UTF8_INCR(p))
74*10598SGlenn.Barry@Sun.COM 	chars++;
75*10598SGlenn.Barry@Sun.COM 
76*10598SGlenn.Barry@Sun.COM     return chars;
77*10598SGlenn.Barry@Sun.COM }
78*10598SGlenn.Barry@Sun.COM 
krb5int_utf8c_chars(const char * p,size_t length)79*10598SGlenn.Barry@Sun.COM size_t krb5int_utf8c_chars(const char *p, size_t length)
80*10598SGlenn.Barry@Sun.COM {
81*10598SGlenn.Barry@Sun.COM     /* could be optimized and could check for invalid sequences */
82*10598SGlenn.Barry@Sun.COM     size_t chars = 0;
83*10598SGlenn.Barry@Sun.COM     const char *end = p + length;
84*10598SGlenn.Barry@Sun.COM 
85*10598SGlenn.Barry@Sun.COM     for ( ; p < end; KRB5_UTF8_INCR(p))
86*10598SGlenn.Barry@Sun.COM 	chars++;
87*10598SGlenn.Barry@Sun.COM 
88*10598SGlenn.Barry@Sun.COM     return chars;
89*10598SGlenn.Barry@Sun.COM }
90*10598SGlenn.Barry@Sun.COM 
91*10598SGlenn.Barry@Sun.COM /* return offset to next character */
krb5int_utf8_offset(const char * p)92*10598SGlenn.Barry@Sun.COM int krb5int_utf8_offset(const char *p)
93*10598SGlenn.Barry@Sun.COM {
94*10598SGlenn.Barry@Sun.COM     return KRB5_UTF8_NEXT(p) - p;
95*10598SGlenn.Barry@Sun.COM }
96*10598SGlenn.Barry@Sun.COM 
97*10598SGlenn.Barry@Sun.COM /*
98*10598SGlenn.Barry@Sun.COM  * Returns length indicated by first byte.
99*10598SGlenn.Barry@Sun.COM  */
100*10598SGlenn.Barry@Sun.COM const char krb5int_utf8_lentab[] = {
101*10598SGlenn.Barry@Sun.COM     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102*10598SGlenn.Barry@Sun.COM     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103*10598SGlenn.Barry@Sun.COM     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104*10598SGlenn.Barry@Sun.COM     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105*10598SGlenn.Barry@Sun.COM     0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
106*10598SGlenn.Barry@Sun.COM     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
107*10598SGlenn.Barry@Sun.COM     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
108*10598SGlenn.Barry@Sun.COM     4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 };
109*10598SGlenn.Barry@Sun.COM 
krb5int_utf8_charlen(const char * p)110*10598SGlenn.Barry@Sun.COM int krb5int_utf8_charlen(const char *p)
111*10598SGlenn.Barry@Sun.COM {
112*10598SGlenn.Barry@Sun.COM     if (!(*p & 0x80))
113*10598SGlenn.Barry@Sun.COM 	return 1;
114*10598SGlenn.Barry@Sun.COM 
115*10598SGlenn.Barry@Sun.COM     return krb5int_utf8_lentab[*(const unsigned char *)p ^ 0x80];
116*10598SGlenn.Barry@Sun.COM }
117*10598SGlenn.Barry@Sun.COM 
118*10598SGlenn.Barry@Sun.COM /*
119*10598SGlenn.Barry@Sun.COM  * Make sure the UTF-8 char used the shortest possible encoding
120*10598SGlenn.Barry@Sun.COM  * returns charlen if valid, 0 if not.
121*10598SGlenn.Barry@Sun.COM  *
122*10598SGlenn.Barry@Sun.COM  * Here are the valid UTF-8 encodings, taken from RFC 2279 page 4.
123*10598SGlenn.Barry@Sun.COM  * The table is slightly modified from that of the RFC.
124*10598SGlenn.Barry@Sun.COM  *
125*10598SGlenn.Barry@Sun.COM  * UCS-4 range (hex)      UTF-8 sequence (binary)
126*10598SGlenn.Barry@Sun.COM  * 0000 0000-0000 007F   0.......
127*10598SGlenn.Barry@Sun.COM  * 0000 0080-0000 07FF   110++++. 10......
128*10598SGlenn.Barry@Sun.COM  * 0000 0800-0000 FFFF   1110++++ 10+..... 10......
129*10598SGlenn.Barry@Sun.COM  * 0001 0000-001F FFFF   11110+++ 10++.... 10...... 10......
130*10598SGlenn.Barry@Sun.COM  * 0020 0000-03FF FFFF   111110++ 10+++... 10...... 10...... 10......
131*10598SGlenn.Barry@Sun.COM  * 0400 0000-7FFF FFFF   1111110+ 10++++.. 10...... 10...... 10...... 10......
132*10598SGlenn.Barry@Sun.COM  *
133*10598SGlenn.Barry@Sun.COM  * The '.' bits are "don't cares". When validating a UTF-8 sequence,
134*10598SGlenn.Barry@Sun.COM  * at least one of the '+' bits must be set, otherwise the character
135*10598SGlenn.Barry@Sun.COM  * should have been encoded in fewer octets. Note that in the two-octet
136*10598SGlenn.Barry@Sun.COM  * case, only the first octet needs to be validated, and this is done
137*10598SGlenn.Barry@Sun.COM  * in the krb5int_utf8_lentab[] above.
138*10598SGlenn.Barry@Sun.COM  */
139*10598SGlenn.Barry@Sun.COM 
140*10598SGlenn.Barry@Sun.COM /* mask of required bits in second octet */
141*10598SGlenn.Barry@Sun.COM #undef c
142*10598SGlenn.Barry@Sun.COM #define c const char
143*10598SGlenn.Barry@Sun.COM c krb5int_utf8_mintab[] = {
144*10598SGlenn.Barry@Sun.COM     (c)0x20, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80,
145*10598SGlenn.Barry@Sun.COM     (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80,
146*10598SGlenn.Barry@Sun.COM     (c)0x30, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80, (c)0x80,
147*10598SGlenn.Barry@Sun.COM     (c)0x38, (c)0x80, (c)0x80, (c)0x80, (c)0x3c, (c)0x80, (c)0x00, (c)0x00 };
148*10598SGlenn.Barry@Sun.COM #undef c
149*10598SGlenn.Barry@Sun.COM 
krb5int_utf8_charlen2(const char * p)150*10598SGlenn.Barry@Sun.COM int krb5int_utf8_charlen2(const char *p)
151*10598SGlenn.Barry@Sun.COM {
152*10598SGlenn.Barry@Sun.COM     int i = KRB5_UTF8_CHARLEN(p);
153*10598SGlenn.Barry@Sun.COM 
154*10598SGlenn.Barry@Sun.COM     if (i > 2) {
155*10598SGlenn.Barry@Sun.COM 	if (!(krb5int_utf8_mintab[*p & 0x1f] & p[1]))
156*10598SGlenn.Barry@Sun.COM 	    i = 0;
157*10598SGlenn.Barry@Sun.COM     }
158*10598SGlenn.Barry@Sun.COM 
159*10598SGlenn.Barry@Sun.COM     return i;
160*10598SGlenn.Barry@Sun.COM }
161*10598SGlenn.Barry@Sun.COM 
162*10598SGlenn.Barry@Sun.COM /*
163*10598SGlenn.Barry@Sun.COM  * Convert a UTF8 character to a UCS4 character.  Return 0 on success,
164*10598SGlenn.Barry@Sun.COM  * -1 on failure.
165*10598SGlenn.Barry@Sun.COM  */
krb5int_utf8_to_ucs4(const char * p,krb5_ucs4 * out)166*10598SGlenn.Barry@Sun.COM int krb5int_utf8_to_ucs4(const char *p, krb5_ucs4 *out)
167*10598SGlenn.Barry@Sun.COM {
168*10598SGlenn.Barry@Sun.COM     const unsigned char *c = (const unsigned char *) p;
169*10598SGlenn.Barry@Sun.COM     krb5_ucs4 ch;
170*10598SGlenn.Barry@Sun.COM     int len, i;
171*10598SGlenn.Barry@Sun.COM     static unsigned char mask[] = {
172*10598SGlenn.Barry@Sun.COM 	0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
173*10598SGlenn.Barry@Sun.COM 
174*10598SGlenn.Barry@Sun.COM     *out = 0;
175*10598SGlenn.Barry@Sun.COM     len = KRB5_UTF8_CHARLEN2(p, len);
176*10598SGlenn.Barry@Sun.COM 
177*10598SGlenn.Barry@Sun.COM     if (len == 0)
178*10598SGlenn.Barry@Sun.COM 	return -1;
179*10598SGlenn.Barry@Sun.COM 
180*10598SGlenn.Barry@Sun.COM     ch = c[0] & mask[len];
181*10598SGlenn.Barry@Sun.COM 
182*10598SGlenn.Barry@Sun.COM     for (i = 1; i < len; i++) {
183*10598SGlenn.Barry@Sun.COM 	if ((c[i] & 0xc0) != 0x80)
184*10598SGlenn.Barry@Sun.COM 	    return -1;
185*10598SGlenn.Barry@Sun.COM 
186*10598SGlenn.Barry@Sun.COM 	ch <<= 6;
187*10598SGlenn.Barry@Sun.COM 	ch |= c[i] & 0x3f;
188*10598SGlenn.Barry@Sun.COM     }
189*10598SGlenn.Barry@Sun.COM 
190*10598SGlenn.Barry@Sun.COM     *out = ch;
191*10598SGlenn.Barry@Sun.COM     return 0;
192*10598SGlenn.Barry@Sun.COM }
193*10598SGlenn.Barry@Sun.COM 
krb5int_utf8_to_ucs2(const char * p,krb5_ucs2 * out)194*10598SGlenn.Barry@Sun.COM int krb5int_utf8_to_ucs2(const char *p, krb5_ucs2 *out)
195*10598SGlenn.Barry@Sun.COM {
196*10598SGlenn.Barry@Sun.COM     krb5_ucs4 ch;
197*10598SGlenn.Barry@Sun.COM 
198*10598SGlenn.Barry@Sun.COM     *out = 0;
199*10598SGlenn.Barry@Sun.COM     if (krb5int_utf8_to_ucs4(p, &ch) == -1 || ch > 0xFFFF)
200*10598SGlenn.Barry@Sun.COM 	return -1;
201*10598SGlenn.Barry@Sun.COM     *out = (krb5_ucs2) ch;
202*10598SGlenn.Barry@Sun.COM     return 0;
203*10598SGlenn.Barry@Sun.COM }
204*10598SGlenn.Barry@Sun.COM 
205*10598SGlenn.Barry@Sun.COM /* conv UCS-2 to UTF-8, not used */
krb5int_ucs4_to_utf8(krb5_ucs4 c,char * buf)206*10598SGlenn.Barry@Sun.COM size_t krb5int_ucs4_to_utf8(krb5_ucs4 c, char *buf)
207*10598SGlenn.Barry@Sun.COM {
208*10598SGlenn.Barry@Sun.COM     size_t len = 0;
209*10598SGlenn.Barry@Sun.COM     unsigned char *p = (unsigned char *) buf;
210*10598SGlenn.Barry@Sun.COM 
211*10598SGlenn.Barry@Sun.COM     /* not a valid Unicode character */
212*10598SGlenn.Barry@Sun.COM     if (c < 0)
213*10598SGlenn.Barry@Sun.COM 	return 0;
214*10598SGlenn.Barry@Sun.COM 
215*10598SGlenn.Barry@Sun.COM     /* Just return length, don't convert */
216*10598SGlenn.Barry@Sun.COM     if (buf == NULL) {
217*10598SGlenn.Barry@Sun.COM 	if (c < 0x80) return 1;
218*10598SGlenn.Barry@Sun.COM 	else if (c < 0x800) return 2;
219*10598SGlenn.Barry@Sun.COM 	else if (c < 0x10000) return 3;
220*10598SGlenn.Barry@Sun.COM 	else if (c < 0x200000) return 4;
221*10598SGlenn.Barry@Sun.COM 	else if (c < 0x4000000) return 5;
222*10598SGlenn.Barry@Sun.COM 	else return 6;
223*10598SGlenn.Barry@Sun.COM     }
224*10598SGlenn.Barry@Sun.COM 
225*10598SGlenn.Barry@Sun.COM     if (c < 0x80) {
226*10598SGlenn.Barry@Sun.COM 	p[len++] = c;
227*10598SGlenn.Barry@Sun.COM     } else if (c < 0x800) {
228*10598SGlenn.Barry@Sun.COM 	p[len++] = 0xc0 | ( c >> 6 );
229*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( c & 0x3f );
230*10598SGlenn.Barry@Sun.COM     } else if (c < 0x10000) {
231*10598SGlenn.Barry@Sun.COM 	p[len++] = 0xe0 | ( c >> 12 );
232*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 6) & 0x3f );
233*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( c & 0x3f );
234*10598SGlenn.Barry@Sun.COM     } else if (c < 0x200000) {
235*10598SGlenn.Barry@Sun.COM 	p[len++] = 0xf0 | ( c >> 18 );
236*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 12) & 0x3f );
237*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 6) & 0x3f );
238*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( c & 0x3f );
239*10598SGlenn.Barry@Sun.COM     } else if (c < 0x4000000) {
240*10598SGlenn.Barry@Sun.COM 	p[len++] = 0xf8 | ( c >> 24 );
241*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 18) & 0x3f );
242*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 12) & 0x3f );
243*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 6) & 0x3f );
244*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( c & 0x3f );
245*10598SGlenn.Barry@Sun.COM     } else /* if( c < 0x80000000 ) */ {
246*10598SGlenn.Barry@Sun.COM 	p[len++] = 0xfc | ( c >> 30 );
247*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 24) & 0x3f );
248*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 18) & 0x3f );
249*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 12) & 0x3f );
250*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( (c >> 6) & 0x3f );
251*10598SGlenn.Barry@Sun.COM 	p[len++] = 0x80 | ( c & 0x3f );
252*10598SGlenn.Barry@Sun.COM     }
253*10598SGlenn.Barry@Sun.COM 
254*10598SGlenn.Barry@Sun.COM     return len;
255*10598SGlenn.Barry@Sun.COM }
256*10598SGlenn.Barry@Sun.COM 
krb5int_ucs2_to_utf8(krb5_ucs2 c,char * buf)257*10598SGlenn.Barry@Sun.COM size_t krb5int_ucs2_to_utf8(krb5_ucs2 c, char *buf)
258*10598SGlenn.Barry@Sun.COM {
259*10598SGlenn.Barry@Sun.COM     return krb5int_ucs4_to_utf8((krb5_ucs4)c, buf);
260*10598SGlenn.Barry@Sun.COM }
261*10598SGlenn.Barry@Sun.COM 
262*10598SGlenn.Barry@Sun.COM #define KRB5_UCS_UTF8LEN(c)	\
263*10598SGlenn.Barry@Sun.COM     c < 0 ? 0 : (c < 0x80 ? 1 : (c < 0x800 ? 2 : (c < 0x10000 ? 3 : \
264*10598SGlenn.Barry@Sun.COM     (c < 0x200000 ? 4 : (c < 0x4000000 ? 5 : 6)))))
265*10598SGlenn.Barry@Sun.COM 
266*10598SGlenn.Barry@Sun.COM /*
267*10598SGlenn.Barry@Sun.COM  * Advance to the next UTF-8 character
268*10598SGlenn.Barry@Sun.COM  *
269*10598SGlenn.Barry@Sun.COM  * Ignores length of multibyte character, instead rely on
270*10598SGlenn.Barry@Sun.COM  * continuation markers to find start of next character.
271*10598SGlenn.Barry@Sun.COM  * This allows for "resyncing" of when invalid characters
272*10598SGlenn.Barry@Sun.COM  * are provided provided the start of the next character
273*10598SGlenn.Barry@Sun.COM  * is appears within the 6 bytes examined.
274*10598SGlenn.Barry@Sun.COM  */
krb5int_utf8_next(const char * p)275*10598SGlenn.Barry@Sun.COM char *krb5int_utf8_next(const char *p)
276*10598SGlenn.Barry@Sun.COM {
277*10598SGlenn.Barry@Sun.COM     int i;
278*10598SGlenn.Barry@Sun.COM     const unsigned char *u = (const unsigned char *) p;
279*10598SGlenn.Barry@Sun.COM 
280*10598SGlenn.Barry@Sun.COM     if (KRB5_UTF8_ISASCII(u)) {
281*10598SGlenn.Barry@Sun.COM 	return (char *) &p[1];
282*10598SGlenn.Barry@Sun.COM     }
283*10598SGlenn.Barry@Sun.COM 
284*10598SGlenn.Barry@Sun.COM     for (i = 1; i < 6; i++) {
285*10598SGlenn.Barry@Sun.COM 	if ((u[i] & 0xc0) != 0x80) {
286*10598SGlenn.Barry@Sun.COM 	    return (char *) &p[i];
287*10598SGlenn.Barry@Sun.COM 	}
288*10598SGlenn.Barry@Sun.COM     }
289*10598SGlenn.Barry@Sun.COM 
290*10598SGlenn.Barry@Sun.COM     return (char *) &p[i];
291*10598SGlenn.Barry@Sun.COM }
292*10598SGlenn.Barry@Sun.COM 
293*10598SGlenn.Barry@Sun.COM /*
294*10598SGlenn.Barry@Sun.COM  * Advance to the previous UTF-8 character
295*10598SGlenn.Barry@Sun.COM  *
296*10598SGlenn.Barry@Sun.COM  * Ignores length of multibyte character, instead rely on
297*10598SGlenn.Barry@Sun.COM  * continuation markers to find start of next character.
298*10598SGlenn.Barry@Sun.COM  * This allows for "resyncing" of when invalid characters
299*10598SGlenn.Barry@Sun.COM  * are provided provided the start of the next character
300*10598SGlenn.Barry@Sun.COM  * is appears within the 6 bytes examined.
301*10598SGlenn.Barry@Sun.COM  */
krb5int_utf8_prev(const char * p)302*10598SGlenn.Barry@Sun.COM char *krb5int_utf8_prev(const char *p)
303*10598SGlenn.Barry@Sun.COM {
304*10598SGlenn.Barry@Sun.COM     int i;
305*10598SGlenn.Barry@Sun.COM     const unsigned char *u = (const unsigned char *) p;
306*10598SGlenn.Barry@Sun.COM 
307*10598SGlenn.Barry@Sun.COM     for (i = -1; i>-6 ; i--) {
308*10598SGlenn.Barry@Sun.COM 	if ((u[i] & 0xc0 ) != 0x80) {
309*10598SGlenn.Barry@Sun.COM 	    return (char *) &p[i];
310*10598SGlenn.Barry@Sun.COM 	}
311*10598SGlenn.Barry@Sun.COM     }
312*10598SGlenn.Barry@Sun.COM 
313*10598SGlenn.Barry@Sun.COM     return (char *) &p[i];
314*10598SGlenn.Barry@Sun.COM }
315*10598SGlenn.Barry@Sun.COM 
316*10598SGlenn.Barry@Sun.COM /*
317*10598SGlenn.Barry@Sun.COM  * Copy one UTF-8 character from src to dst returning
318*10598SGlenn.Barry@Sun.COM  * number of bytes copied.
319*10598SGlenn.Barry@Sun.COM  *
320*10598SGlenn.Barry@Sun.COM  * Ignores length of multibyte character, instead rely on
321*10598SGlenn.Barry@Sun.COM  * continuation markers to find start of next character.
322*10598SGlenn.Barry@Sun.COM  * This allows for "resyncing" of when invalid characters
323*10598SGlenn.Barry@Sun.COM  * are provided provided the start of the next character
324*10598SGlenn.Barry@Sun.COM  * is appears within the 6 bytes examined.
325*10598SGlenn.Barry@Sun.COM  */
krb5int_utf8_copy(char * dst,const char * src)326*10598SGlenn.Barry@Sun.COM int krb5int_utf8_copy(char* dst, const char *src)
327*10598SGlenn.Barry@Sun.COM {
328*10598SGlenn.Barry@Sun.COM     int i;
329*10598SGlenn.Barry@Sun.COM     const unsigned char *u = (const unsigned char *) src;
330*10598SGlenn.Barry@Sun.COM 
331*10598SGlenn.Barry@Sun.COM     dst[0] = src[0];
332*10598SGlenn.Barry@Sun.COM 
333*10598SGlenn.Barry@Sun.COM     if (KRB5_UTF8_ISASCII(u)) {
334*10598SGlenn.Barry@Sun.COM 	return 1;
335*10598SGlenn.Barry@Sun.COM     }
336*10598SGlenn.Barry@Sun.COM 
337*10598SGlenn.Barry@Sun.COM     for (i=1; i<6; i++) {
338*10598SGlenn.Barry@Sun.COM 	if ((u[i] & 0xc0) != 0x80) {
339*10598SGlenn.Barry@Sun.COM 	    return i;
340*10598SGlenn.Barry@Sun.COM 	}
341*10598SGlenn.Barry@Sun.COM 	dst[i] = src[i];
342*10598SGlenn.Barry@Sun.COM     }
343*10598SGlenn.Barry@Sun.COM 
344*10598SGlenn.Barry@Sun.COM     return i;
345*10598SGlenn.Barry@Sun.COM }
346*10598SGlenn.Barry@Sun.COM 
347*10598SGlenn.Barry@Sun.COM #ifndef UTF8_ALPHA_CTYPE
348*10598SGlenn.Barry@Sun.COM /*
349*10598SGlenn.Barry@Sun.COM  * UTF-8 ctype routines
350*10598SGlenn.Barry@Sun.COM  * Only deals with characters < 0x80 (ie: US-ASCII)
351*10598SGlenn.Barry@Sun.COM  */
352*10598SGlenn.Barry@Sun.COM 
krb5int_utf8_isascii(const char * p)353*10598SGlenn.Barry@Sun.COM int krb5int_utf8_isascii(const char * p)
354*10598SGlenn.Barry@Sun.COM {
355*10598SGlenn.Barry@Sun.COM     unsigned c = * (const unsigned char *) p;
356*10598SGlenn.Barry@Sun.COM 
357*10598SGlenn.Barry@Sun.COM     return KRB5_ASCII(c);
358*10598SGlenn.Barry@Sun.COM }
359*10598SGlenn.Barry@Sun.COM 
krb5int_utf8_isdigit(const char * p)360*10598SGlenn.Barry@Sun.COM int krb5int_utf8_isdigit(const char * p)
361*10598SGlenn.Barry@Sun.COM {
362*10598SGlenn.Barry@Sun.COM     unsigned c = * (const unsigned char *) p;
363*10598SGlenn.Barry@Sun.COM 
364*10598SGlenn.Barry@Sun.COM     if (!KRB5_ASCII(c))
365*10598SGlenn.Barry@Sun.COM 	return 0;
366*10598SGlenn.Barry@Sun.COM 
367*10598SGlenn.Barry@Sun.COM     return KRB5_DIGIT( c );
368*10598SGlenn.Barry@Sun.COM }
369*10598SGlenn.Barry@Sun.COM 
krb5int_utf8_isxdigit(const char * p)370*10598SGlenn.Barry@Sun.COM int krb5int_utf8_isxdigit(const char * p)
371*10598SGlenn.Barry@Sun.COM {
372*10598SGlenn.Barry@Sun.COM     unsigned c = * (const unsigned char *) p;
373*10598SGlenn.Barry@Sun.COM 
374*10598SGlenn.Barry@Sun.COM     if (!KRB5_ASCII(c))
375*10598SGlenn.Barry@Sun.COM 	return 0;
376*10598SGlenn.Barry@Sun.COM 
377*10598SGlenn.Barry@Sun.COM     return KRB5_HEX(c);
378*10598SGlenn.Barry@Sun.COM }
379*10598SGlenn.Barry@Sun.COM 
krb5int_utf8_isspace(const char * p)380*10598SGlenn.Barry@Sun.COM int krb5int_utf8_isspace(const char * p)
381*10598SGlenn.Barry@Sun.COM {
382*10598SGlenn.Barry@Sun.COM     unsigned c = * (const unsigned char *) p;
383*10598SGlenn.Barry@Sun.COM 
384*10598SGlenn.Barry@Sun.COM     if (!KRB5_ASCII(c))
385*10598SGlenn.Barry@Sun.COM 	return 0;
386*10598SGlenn.Barry@Sun.COM 
387*10598SGlenn.Barry@Sun.COM     switch(c) {
388*10598SGlenn.Barry@Sun.COM     case ' ':
389*10598SGlenn.Barry@Sun.COM     case '\t':
390*10598SGlenn.Barry@Sun.COM     case '\n':
391*10598SGlenn.Barry@Sun.COM     case '\r':
392*10598SGlenn.Barry@Sun.COM     case '\v':
393*10598SGlenn.Barry@Sun.COM     case '\f':
394*10598SGlenn.Barry@Sun.COM 	return 1;
395*10598SGlenn.Barry@Sun.COM     }
396*10598SGlenn.Barry@Sun.COM 
397*10598SGlenn.Barry@Sun.COM     return 0;
398*10598SGlenn.Barry@Sun.COM }
399*10598SGlenn.Barry@Sun.COM 
400*10598SGlenn.Barry@Sun.COM /*
401*10598SGlenn.Barry@Sun.COM  * These are not needed by the C SDK and are
402*10598SGlenn.Barry@Sun.COM  * not "good enough" for general use.
403*10598SGlenn.Barry@Sun.COM  */
krb5int_utf8_isalpha(const char * p)404*10598SGlenn.Barry@Sun.COM int krb5int_utf8_isalpha(const char * p)
405*10598SGlenn.Barry@Sun.COM {
406*10598SGlenn.Barry@Sun.COM     unsigned c = * (const unsigned char *) p;
407*10598SGlenn.Barry@Sun.COM 
408*10598SGlenn.Barry@Sun.COM     if (!KRB5_ASCII(c))
409*10598SGlenn.Barry@Sun.COM 	return 0;
410*10598SGlenn.Barry@Sun.COM 
411*10598SGlenn.Barry@Sun.COM     return KRB5_ALPHA(c);
412*10598SGlenn.Barry@Sun.COM }
413*10598SGlenn.Barry@Sun.COM 
krb5int_utf8_isalnum(const char * p)414*10598SGlenn.Barry@Sun.COM int krb5int_utf8_isalnum(const char * p)
415*10598SGlenn.Barry@Sun.COM {
416*10598SGlenn.Barry@Sun.COM     unsigned c = * (const unsigned char *) p;
417*10598SGlenn.Barry@Sun.COM 
418*10598SGlenn.Barry@Sun.COM     if (!KRB5_ASCII(c))
419*10598SGlenn.Barry@Sun.COM 	return 0;
420*10598SGlenn.Barry@Sun.COM 
421*10598SGlenn.Barry@Sun.COM     return KRB5_ALNUM(c);
422*10598SGlenn.Barry@Sun.COM }
423*10598SGlenn.Barry@Sun.COM 
424*10598SGlenn.Barry@Sun.COM #if 0
425*10598SGlenn.Barry@Sun.COM int krb5int_utf8_islower(const char * p)
426*10598SGlenn.Barry@Sun.COM {
427*10598SGlenn.Barry@Sun.COM     unsigned c = * (const unsigned char *) p;
428*10598SGlenn.Barry@Sun.COM 
429*10598SGlenn.Barry@Sun.COM     if (!KRB5_ASCII(c))
430*10598SGlenn.Barry@Sun.COM 	return 0;
431*10598SGlenn.Barry@Sun.COM 
432*10598SGlenn.Barry@Sun.COM     return KRB5_LOWER(c);
433*10598SGlenn.Barry@Sun.COM }
434*10598SGlenn.Barry@Sun.COM 
435*10598SGlenn.Barry@Sun.COM int krb5int_utf8_isupper(const char * p)
436*10598SGlenn.Barry@Sun.COM {
437*10598SGlenn.Barry@Sun.COM     unsigned c = * (const unsigned char *) p;
438*10598SGlenn.Barry@Sun.COM 
439*10598SGlenn.Barry@Sun.COM     if (!KRB5_ASCII(c))
440*10598SGlenn.Barry@Sun.COM 	return 0;
441*10598SGlenn.Barry@Sun.COM 
442*10598SGlenn.Barry@Sun.COM     return KRB5_UPPER(c);
443*10598SGlenn.Barry@Sun.COM }
444*10598SGlenn.Barry@Sun.COM #endif
445*10598SGlenn.Barry@Sun.COM #endif
446*10598SGlenn.Barry@Sun.COM 
447*10598SGlenn.Barry@Sun.COM 
448*10598SGlenn.Barry@Sun.COM /*
449*10598SGlenn.Barry@Sun.COM  * UTF-8 string routines
450*10598SGlenn.Barry@Sun.COM  */
451*10598SGlenn.Barry@Sun.COM 
452*10598SGlenn.Barry@Sun.COM /* like strchr() */
krb5int_utf8_strchr(const char * str,const char * chr)453*10598SGlenn.Barry@Sun.COM char *krb5int_utf8_strchr(const char *str, const char *chr)
454*10598SGlenn.Barry@Sun.COM {
455*10598SGlenn.Barry@Sun.COM     krb5_ucs4 chs, ch;
456*10598SGlenn.Barry@Sun.COM 
457*10598SGlenn.Barry@Sun.COM     if (krb5int_utf8_to_ucs4(chr, &ch) == -1)
458*10598SGlenn.Barry@Sun.COM 	return NULL;
459*10598SGlenn.Barry@Sun.COM     for ( ; *str != '\0'; KRB5_UTF8_INCR(str)) {
460*10598SGlenn.Barry@Sun.COM 	if (krb5int_utf8_to_ucs4(str, &chs) == 0 && chs == ch)
461*10598SGlenn.Barry@Sun.COM 	    return (char *)str;
462*10598SGlenn.Barry@Sun.COM     }
463*10598SGlenn.Barry@Sun.COM 
464*10598SGlenn.Barry@Sun.COM     return NULL;
465*10598SGlenn.Barry@Sun.COM }
466*10598SGlenn.Barry@Sun.COM 
467*10598SGlenn.Barry@Sun.COM /* like strcspn() but returns number of bytes, not characters */
krb5int_utf8_strcspn(const char * str,const char * set)468*10598SGlenn.Barry@Sun.COM size_t krb5int_utf8_strcspn(const char *str, const char *set)
469*10598SGlenn.Barry@Sun.COM {
470*10598SGlenn.Barry@Sun.COM     const char *cstr, *cset;
471*10598SGlenn.Barry@Sun.COM     krb5_ucs4 chstr, chset;
472*10598SGlenn.Barry@Sun.COM 
473*10598SGlenn.Barry@Sun.COM     for (cstr = str; *cstr != '\0'; KRB5_UTF8_INCR(cstr)) {
474*10598SGlenn.Barry@Sun.COM 	for (cset = set; *cset != '\0'; KRB5_UTF8_INCR(cset)) {
475*10598SGlenn.Barry@Sun.COM 	    if (krb5int_utf8_to_ucs4(cstr, &chstr) == 0
476*10598SGlenn.Barry@Sun.COM 		&& krb5int_utf8_to_ucs4(cset, &chset) == 0 && chstr == chset)
477*10598SGlenn.Barry@Sun.COM 		return cstr - str;
478*10598SGlenn.Barry@Sun.COM 	}
479*10598SGlenn.Barry@Sun.COM     }
480*10598SGlenn.Barry@Sun.COM 
481*10598SGlenn.Barry@Sun.COM     return cstr - str;
482*10598SGlenn.Barry@Sun.COM }
483*10598SGlenn.Barry@Sun.COM 
484*10598SGlenn.Barry@Sun.COM /* like strspn() but returns number of bytes, not characters */
krb5int_utf8_strspn(const char * str,const char * set)485*10598SGlenn.Barry@Sun.COM size_t krb5int_utf8_strspn(const char *str, const char *set)
486*10598SGlenn.Barry@Sun.COM {
487*10598SGlenn.Barry@Sun.COM     const char *cstr, *cset;
488*10598SGlenn.Barry@Sun.COM     krb5_ucs4 chstr, chset;
489*10598SGlenn.Barry@Sun.COM 
490*10598SGlenn.Barry@Sun.COM     for (cstr = str; *cstr != '\0'; KRB5_UTF8_INCR(cstr)) {
491*10598SGlenn.Barry@Sun.COM 	for (cset = set; ; KRB5_UTF8_INCR(cset)) {
492*10598SGlenn.Barry@Sun.COM 	    if (*cset == '\0')
493*10598SGlenn.Barry@Sun.COM 		return cstr - str;
494*10598SGlenn.Barry@Sun.COM 	    if (krb5int_utf8_to_ucs4(cstr, &chstr) == 0
495*10598SGlenn.Barry@Sun.COM 		&& krb5int_utf8_to_ucs4(cset, &chset) == 0 && chstr == chset)
496*10598SGlenn.Barry@Sun.COM 		break;
497*10598SGlenn.Barry@Sun.COM 	}
498*10598SGlenn.Barry@Sun.COM     }
499*10598SGlenn.Barry@Sun.COM 
500*10598SGlenn.Barry@Sun.COM     return cstr - str;
501*10598SGlenn.Barry@Sun.COM }
502*10598SGlenn.Barry@Sun.COM 
503*10598SGlenn.Barry@Sun.COM /* like strpbrk(), replaces strchr() as well */
krb5int_utf8_strpbrk(const char * str,const char * set)504*10598SGlenn.Barry@Sun.COM char *krb5int_utf8_strpbrk(const char *str, const char *set)
505*10598SGlenn.Barry@Sun.COM {
506*10598SGlenn.Barry@Sun.COM     const char *cset;
507*10598SGlenn.Barry@Sun.COM     krb5_ucs4 chstr, chset;
508*10598SGlenn.Barry@Sun.COM 
509*10598SGlenn.Barry@Sun.COM     for ( ; *str != '\0'; KRB5_UTF8_INCR(str)) {
510*10598SGlenn.Barry@Sun.COM 	for (cset = set; *cset != '\0'; KRB5_UTF8_INCR(cset)) {
511*10598SGlenn.Barry@Sun.COM 	    if (krb5int_utf8_to_ucs4(str, &chstr) == 0
512*10598SGlenn.Barry@Sun.COM 		&& krb5int_utf8_to_ucs4(cset, &chset) == 0 && chstr == chset)
513*10598SGlenn.Barry@Sun.COM 		return (char *)str;
514*10598SGlenn.Barry@Sun.COM 	}
515*10598SGlenn.Barry@Sun.COM     }
516*10598SGlenn.Barry@Sun.COM 
517*10598SGlenn.Barry@Sun.COM     return NULL;
518*10598SGlenn.Barry@Sun.COM }
519*10598SGlenn.Barry@Sun.COM 
520*10598SGlenn.Barry@Sun.COM /* like strtok_r(), not strtok() */
krb5int_utf8_strtok(char * str,const char * sep,char ** last)521*10598SGlenn.Barry@Sun.COM char *krb5int_utf8_strtok(char *str, const char *sep, char **last)
522*10598SGlenn.Barry@Sun.COM {
523*10598SGlenn.Barry@Sun.COM     char *begin;
524*10598SGlenn.Barry@Sun.COM     char *end;
525*10598SGlenn.Barry@Sun.COM 
526*10598SGlenn.Barry@Sun.COM     if (last == NULL)
527*10598SGlenn.Barry@Sun.COM 	return NULL;
528*10598SGlenn.Barry@Sun.COM 
529*10598SGlenn.Barry@Sun.COM     begin = str ? str : *last;
530*10598SGlenn.Barry@Sun.COM 
531*10598SGlenn.Barry@Sun.COM     begin += krb5int_utf8_strspn(begin, sep);
532*10598SGlenn.Barry@Sun.COM 
533*10598SGlenn.Barry@Sun.COM     if (*begin == '\0') {
534*10598SGlenn.Barry@Sun.COM 	*last = NULL;
535*10598SGlenn.Barry@Sun.COM 	return NULL;
536*10598SGlenn.Barry@Sun.COM     }
537*10598SGlenn.Barry@Sun.COM 
538*10598SGlenn.Barry@Sun.COM     end = &begin[krb5int_utf8_strcspn(begin, sep)];
539*10598SGlenn.Barry@Sun.COM 
540*10598SGlenn.Barry@Sun.COM     if (*end != '\0') {
541*10598SGlenn.Barry@Sun.COM 	char *next = KRB5_UTF8_NEXT(end);
542*10598SGlenn.Barry@Sun.COM 	*end = '\0';
543*10598SGlenn.Barry@Sun.COM 	end = next;
544*10598SGlenn.Barry@Sun.COM     }
545*10598SGlenn.Barry@Sun.COM 
546*10598SGlenn.Barry@Sun.COM     *last = end;
547*10598SGlenn.Barry@Sun.COM 
548*10598SGlenn.Barry@Sun.COM     return begin;
549*10598SGlenn.Barry@Sun.COM }
550