1ba7b222eSGlenn Barry /*
2ba7b222eSGlenn Barry  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3ba7b222eSGlenn Barry  * Use is subject to license terms.
4ba7b222eSGlenn Barry  */
5ba7b222eSGlenn Barry 
6ba7b222eSGlenn Barry /*
7ba7b222eSGlenn Barry  * util/support/utf8_conv.c
8ba7b222eSGlenn Barry  *
9ba7b222eSGlenn Barry  * Copyright 2008 by the Massachusetts Institute of Technology.
10ba7b222eSGlenn Barry  * All Rights Reserved.
11ba7b222eSGlenn Barry  *
12ba7b222eSGlenn Barry  * Export of this software from the United States of America may
13ba7b222eSGlenn Barry  *   require a specific license from the United States Government.
14ba7b222eSGlenn Barry  *   It is the responsibility of any person or organization contemplating
15ba7b222eSGlenn Barry  *   export to obtain such a license before exporting.
16*55fea89dSDan Cross  *
17ba7b222eSGlenn Barry  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18ba7b222eSGlenn Barry  * distribute this software and its documentation for any purpose and
19ba7b222eSGlenn Barry  * without fee is hereby granted, provided that the above copyright
20ba7b222eSGlenn Barry  * notice appear in all copies and that both that copyright notice and
21ba7b222eSGlenn Barry  * this permission notice appear in supporting documentation, and that
22ba7b222eSGlenn Barry  * the name of M.I.T. not be used in advertising or publicity pertaining
23ba7b222eSGlenn Barry  * to distribution of the software without specific, written prior
24ba7b222eSGlenn Barry  * permission.  Furthermore if you modify this software you must label
25ba7b222eSGlenn Barry  * your software as modified software and not distribute it in such a
26ba7b222eSGlenn Barry  * fashion that it might be confused with the original M.I.T. software.
27ba7b222eSGlenn Barry  * M.I.T. makes no representations about the suitability of
28ba7b222eSGlenn Barry  * this software for any purpose.  It is provided "as is" without express
29ba7b222eSGlenn Barry  * or implied warranty.
30ba7b222eSGlenn Barry  */
31ba7b222eSGlenn Barry /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
32ba7b222eSGlenn Barry  *
33ba7b222eSGlenn Barry  * Copyright 1998-2008 The OpenLDAP Foundation.
34ba7b222eSGlenn Barry  * All rights reserved.
35ba7b222eSGlenn Barry  *
36ba7b222eSGlenn Barry  * Redistribution and use in source and binary forms, with or without
37ba7b222eSGlenn Barry  * modification, are permitted only as authorized by the OpenLDAP
38ba7b222eSGlenn Barry  * Public License.
39ba7b222eSGlenn Barry  *
40ba7b222eSGlenn Barry  * A copy of this license is available in the file LICENSE in the
41ba7b222eSGlenn Barry  * top-level directory of the distribution or, alternatively, at
42ba7b222eSGlenn Barry  * <http://www.OpenLDAP.org/license.html>.
43ba7b222eSGlenn Barry  */
44ba7b222eSGlenn Barry /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
45*55fea89dSDan Cross  *
46ba7b222eSGlenn Barry  * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
47ba7b222eSGlenn Barry  * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
48ba7b222eSGlenn Barry  * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
49ba7b222eSGlenn Barry  * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
50ba7b222eSGlenn Barry  * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
51ba7b222eSGlenn Barry  * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
52ba7b222eSGlenn Barry  * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
53*55fea89dSDan Cross  * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
54ba7b222eSGlenn Barry  */
55ba7b222eSGlenn Barry 
56ba7b222eSGlenn Barry /*
57ba7b222eSGlenn Barry  * UTF-8 Conversion Routines
58ba7b222eSGlenn Barry  *
59ba7b222eSGlenn Barry  * These routines convert between Wide Character and UTF-8,
60ba7b222eSGlenn Barry  * or between MultiByte and UTF-8 encodings.
61ba7b222eSGlenn Barry  *
62ba7b222eSGlenn Barry  * Both single character and string versions of the functions are provided.
63ba7b222eSGlenn Barry  * All functions return -1 if the character or string cannot be converted.
64ba7b222eSGlenn Barry  */
65ba7b222eSGlenn Barry 
66ba7b222eSGlenn Barry #include "k5-platform.h"
67ba7b222eSGlenn Barry #include "k5-utf8.h"
68ba7b222eSGlenn Barry #include "supp-int.h"
69ba7b222eSGlenn Barry #include "errno.h"  /* SUNW17PACresync */
70ba7b222eSGlenn Barry 
71ba7b222eSGlenn Barry static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
72ba7b222eSGlenn Barry 
73ba7b222eSGlenn Barry static ssize_t
k5_utf8s_to_ucs2s(krb5_ucs2 * ucs2str,const char * utf8str,size_t count,int little_endian)74ba7b222eSGlenn Barry k5_utf8s_to_ucs2s(krb5_ucs2 *ucs2str,
75ba7b222eSGlenn Barry 		  const char *utf8str,
76ba7b222eSGlenn Barry 		  size_t count,
77ba7b222eSGlenn Barry 		  int little_endian)
78ba7b222eSGlenn Barry {
79ba7b222eSGlenn Barry     size_t ucs2len = 0;
80ba7b222eSGlenn Barry     size_t utflen, i;
81ba7b222eSGlenn Barry     krb5_ucs2 ch;
82ba7b222eSGlenn Barry 
83ba7b222eSGlenn Barry     /* If input ptr is NULL or empty... */
84ba7b222eSGlenn Barry     if (utf8str == NULL || *utf8str == '\0') {
85ba7b222eSGlenn Barry 	*ucs2str = 0;
86ba7b222eSGlenn Barry 
87ba7b222eSGlenn Barry 	return 0;
88ba7b222eSGlenn Barry     }
89ba7b222eSGlenn Barry 
90ba7b222eSGlenn Barry     /* Examine next UTF-8 character.  */
91ba7b222eSGlenn Barry     while (*utf8str && ucs2len < count) {
92ba7b222eSGlenn Barry 	/* Get UTF-8 sequence length from 1st byte */
93ba7b222eSGlenn Barry 	utflen = KRB5_UTF8_CHARLEN2(utf8str, utflen);
94*55fea89dSDan Cross 
95ba7b222eSGlenn Barry 	if (utflen == 0 || utflen > KRB5_MAX_UTF8_LEN)
96ba7b222eSGlenn Barry 	    return -1;
97ba7b222eSGlenn Barry 
98ba7b222eSGlenn Barry 	/* First byte minus length tag */
99ba7b222eSGlenn Barry 	ch = (krb5_ucs2)(utf8str[0] & mask[utflen]);
100*55fea89dSDan Cross 
101ba7b222eSGlenn Barry 	for (i = 1; i < utflen; i++) {
102ba7b222eSGlenn Barry 	    /* Subsequent bytes must start with 10 */
103ba7b222eSGlenn Barry 	    if ((utf8str[i] & 0xc0) != 0x80)
104ba7b222eSGlenn Barry 		return -1;
105*55fea89dSDan Cross 
106ba7b222eSGlenn Barry 	    ch <<= 6;			/* 6 bits of data in each subsequent byte */
107ba7b222eSGlenn Barry 	    ch |= (krb5_ucs2)(utf8str[i] & 0x3f);
108ba7b222eSGlenn Barry 	}
109*55fea89dSDan Cross 
110ba7b222eSGlenn Barry 	if (ucs2str != NULL) {
111ba7b222eSGlenn Barry #ifdef K5_BE
112ba7b222eSGlenn Barry #ifndef SWAP16
113ba7b222eSGlenn Barry #define SWAP16(X)	((((X) << 8) | ((X) >> 8)) & 0xFFFF)
114ba7b222eSGlenn Barry #endif
115ba7b222eSGlenn Barry 	    if (little_endian)
116ba7b222eSGlenn Barry 		ucs2str[ucs2len] = SWAP16(ch);
117ba7b222eSGlenn Barry 	    else
118ba7b222eSGlenn Barry #endif
119ba7b222eSGlenn Barry 		ucs2str[ucs2len] = ch;
120ba7b222eSGlenn Barry 	}
121ba7b222eSGlenn Barry 
122ba7b222eSGlenn Barry 	utf8str += utflen;	/* Move to next UTF-8 character */
123ba7b222eSGlenn Barry 	ucs2len++;		/* Count number of wide chars stored/required */
124ba7b222eSGlenn Barry     }
125ba7b222eSGlenn Barry 
126ba7b222eSGlenn Barry     assert(ucs2len < count);
127*55fea89dSDan Cross 
128ba7b222eSGlenn Barry     if (ucs2str != NULL) {
129ba7b222eSGlenn Barry 	/* Add null terminator if there's room in the buffer. */
130ba7b222eSGlenn Barry 	ucs2str[ucs2len] = 0;
131ba7b222eSGlenn Barry     }
132ba7b222eSGlenn Barry 
133ba7b222eSGlenn Barry     return ucs2len;
134ba7b222eSGlenn Barry }
135ba7b222eSGlenn Barry 
136ba7b222eSGlenn Barry int
krb5int_utf8s_to_ucs2s(const char * utf8s,krb5_ucs2 ** ucs2s,size_t * ucs2chars)137ba7b222eSGlenn Barry krb5int_utf8s_to_ucs2s(const char *utf8s,
138ba7b222eSGlenn Barry 		       krb5_ucs2 **ucs2s,
139ba7b222eSGlenn Barry 		       size_t *ucs2chars)
140ba7b222eSGlenn Barry {
141ba7b222eSGlenn Barry     ssize_t len;
142ba7b222eSGlenn Barry     size_t chars;
143ba7b222eSGlenn Barry 
144ba7b222eSGlenn Barry     chars = krb5int_utf8_chars(utf8s);
145ba7b222eSGlenn Barry     *ucs2s = (krb5_ucs2 *)malloc((chars + 1) * sizeof(krb5_ucs2));
146ba7b222eSGlenn Barry     if (*ucs2s == NULL) {
147ba7b222eSGlenn Barry 	return ENOMEM;
148ba7b222eSGlenn Barry     }
149ba7b222eSGlenn Barry 
150ba7b222eSGlenn Barry     len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars + 1, 0);
151ba7b222eSGlenn Barry     if (len < 0) {
152ba7b222eSGlenn Barry 	free(*ucs2s);
153ba7b222eSGlenn Barry 	*ucs2s = NULL;
154ba7b222eSGlenn Barry 	return EINVAL;
155ba7b222eSGlenn Barry     }
156ba7b222eSGlenn Barry 
157ba7b222eSGlenn Barry     if (ucs2chars != NULL) {
158ba7b222eSGlenn Barry 	*ucs2chars = chars;
159ba7b222eSGlenn Barry     }
160ba7b222eSGlenn Barry 
161ba7b222eSGlenn Barry     return 0;
162ba7b222eSGlenn Barry }
163ba7b222eSGlenn Barry 
164ba7b222eSGlenn Barry int
krb5int_utf8cs_to_ucs2s(const char * utf8s,size_t utf8slen,krb5_ucs2 ** ucs2s,size_t * ucs2chars)165ba7b222eSGlenn Barry krb5int_utf8cs_to_ucs2s(const char *utf8s,
166ba7b222eSGlenn Barry 			size_t utf8slen,
167ba7b222eSGlenn Barry 			krb5_ucs2 **ucs2s,
168ba7b222eSGlenn Barry 			size_t *ucs2chars)
169ba7b222eSGlenn Barry {
170ba7b222eSGlenn Barry     ssize_t len;
171ba7b222eSGlenn Barry     size_t chars;
172ba7b222eSGlenn Barry 
173ba7b222eSGlenn Barry     chars = krb5int_utf8c_chars(utf8s, utf8slen);
174ba7b222eSGlenn Barry     *ucs2s = (krb5_ucs2 *)malloc((chars + 1) * sizeof(krb5_ucs2));
175ba7b222eSGlenn Barry     if (*ucs2s == NULL) {
176ba7b222eSGlenn Barry 	return ENOMEM;
177ba7b222eSGlenn Barry     }
178ba7b222eSGlenn Barry 
179ba7b222eSGlenn Barry     len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars + 1, 0);
180ba7b222eSGlenn Barry     if (len < 0) {
181ba7b222eSGlenn Barry 	free(*ucs2s);
182ba7b222eSGlenn Barry 	*ucs2s = NULL;
183ba7b222eSGlenn Barry 	return EINVAL;
184ba7b222eSGlenn Barry     }
185ba7b222eSGlenn Barry 
186ba7b222eSGlenn Barry     if (ucs2chars != NULL) {
187ba7b222eSGlenn Barry 	*ucs2chars = chars;
188ba7b222eSGlenn Barry     }
189ba7b222eSGlenn Barry 
190ba7b222eSGlenn Barry     return 0;
191ba7b222eSGlenn Barry }
192ba7b222eSGlenn Barry 
193ba7b222eSGlenn Barry int
krb5int_utf8s_to_ucs2les(const char * utf8s,unsigned char ** ucs2les,size_t * ucs2leslen)194ba7b222eSGlenn Barry krb5int_utf8s_to_ucs2les(const char *utf8s,
195ba7b222eSGlenn Barry                          unsigned char **ucs2les,
196ba7b222eSGlenn Barry 			 size_t *ucs2leslen)
197ba7b222eSGlenn Barry {
198ba7b222eSGlenn Barry     ssize_t len;
199ba7b222eSGlenn Barry     size_t chars;
200ba7b222eSGlenn Barry 
201ba7b222eSGlenn Barry     chars = krb5int_utf8_chars(utf8s);
202ba7b222eSGlenn Barry 
203ba7b222eSGlenn Barry     *ucs2les = (unsigned char *)malloc((chars + 1) * sizeof(krb5_ucs2));
204ba7b222eSGlenn Barry     if (*ucs2les == NULL) {
205ba7b222eSGlenn Barry 	return ENOMEM;
206ba7b222eSGlenn Barry     }
207ba7b222eSGlenn Barry 
208ba7b222eSGlenn Barry     len = k5_utf8s_to_ucs2s((krb5_ucs2 *)*ucs2les, utf8s, chars + 1, 1);
209ba7b222eSGlenn Barry     if (len < 0) {
210ba7b222eSGlenn Barry 	free(*ucs2les);
211ba7b222eSGlenn Barry 	*ucs2les = NULL;
212ba7b222eSGlenn Barry 	return EINVAL;
213ba7b222eSGlenn Barry     }
214ba7b222eSGlenn Barry 
215ba7b222eSGlenn Barry     if (ucs2leslen != NULL) {
216ba7b222eSGlenn Barry 	*ucs2leslen = chars * sizeof(krb5_ucs2);
217ba7b222eSGlenn Barry     }
218ba7b222eSGlenn Barry 
219ba7b222eSGlenn Barry     return 0;
220ba7b222eSGlenn Barry }
221ba7b222eSGlenn Barry 
222ba7b222eSGlenn Barry int
krb5int_utf8cs_to_ucs2les(const char * utf8s,size_t utf8slen,unsigned char ** ucs2les,size_t * ucs2leslen)223ba7b222eSGlenn Barry krb5int_utf8cs_to_ucs2les(const char *utf8s,
224ba7b222eSGlenn Barry 			  size_t utf8slen,
225ba7b222eSGlenn Barry 			  unsigned char **ucs2les,
226ba7b222eSGlenn Barry 			  size_t *ucs2leslen)
227ba7b222eSGlenn Barry {
228ba7b222eSGlenn Barry     ssize_t len;
229ba7b222eSGlenn Barry     size_t chars;
230ba7b222eSGlenn Barry 
231ba7b222eSGlenn Barry     chars = krb5int_utf8c_chars(utf8s, utf8slen);
232ba7b222eSGlenn Barry 
233ba7b222eSGlenn Barry     *ucs2les = (unsigned char *)malloc((chars + 1) * sizeof(krb5_ucs2));
234ba7b222eSGlenn Barry     if (*ucs2les == NULL) {
235ba7b222eSGlenn Barry 	return ENOMEM;
236ba7b222eSGlenn Barry     }
237ba7b222eSGlenn Barry 
238ba7b222eSGlenn Barry     len = k5_utf8s_to_ucs2s((krb5_ucs2 *)*ucs2les, utf8s, chars + 1, 1);
239ba7b222eSGlenn Barry     if (len < 0) {
240ba7b222eSGlenn Barry 	free(*ucs2les);
241ba7b222eSGlenn Barry 	*ucs2les = NULL;
242ba7b222eSGlenn Barry 	return EINVAL;
243ba7b222eSGlenn Barry     }
244ba7b222eSGlenn Barry 
245ba7b222eSGlenn Barry     if (ucs2leslen != NULL) {
246ba7b222eSGlenn Barry 	*ucs2leslen = chars * sizeof(krb5_ucs2);
247ba7b222eSGlenn Barry     }
248ba7b222eSGlenn Barry 
249ba7b222eSGlenn Barry     return 0;
250ba7b222eSGlenn Barry }
251ba7b222eSGlenn Barry 
252ba7b222eSGlenn Barry /*-----------------------------------------------------------------------------
253ba7b222eSGlenn Barry    Convert a wide char string to a UTF-8 string.
254ba7b222eSGlenn Barry    No more than 'count' bytes will be written to the output buffer.
255ba7b222eSGlenn Barry    Return the # of bytes written to the output buffer, excl null terminator.
256ba7b222eSGlenn Barry 
257ba7b222eSGlenn Barry    ucs2len is -1 if the UCS-2 string is NUL terminated, otherwise it is the
258ba7b222eSGlenn Barry    length of the UCS-2 string in characters
259ba7b222eSGlenn Barry */
260ba7b222eSGlenn Barry static ssize_t
k5_ucs2s_to_utf8s(char * utf8str,const krb5_ucs2 * ucs2str,size_t count,ssize_t ucs2len,int little_endian)261ba7b222eSGlenn Barry k5_ucs2s_to_utf8s(char *utf8str, const krb5_ucs2 *ucs2str,
262ba7b222eSGlenn Barry 		  size_t count, ssize_t ucs2len, int little_endian)
263ba7b222eSGlenn Barry {
264ba7b222eSGlenn Barry     int len = 0;
265ba7b222eSGlenn Barry     int n;
266ba7b222eSGlenn Barry     char *p = utf8str;
267ba7b222eSGlenn Barry     krb5_ucs2 empty = 0, ch;
268ba7b222eSGlenn Barry 
269ba7b222eSGlenn Barry     if (ucs2str == NULL)	/* Treat input ptr NULL as an empty string */
270ba7b222eSGlenn Barry 	ucs2str = &empty;
271ba7b222eSGlenn Barry 
272ba7b222eSGlenn Barry     if (utf8str == NULL)	/* Just compute size of output, excl null */
273ba7b222eSGlenn Barry     {
274ba7b222eSGlenn Barry 	while (ucs2len == -1 ? *ucs2str : --ucs2len >= 0) {
275ba7b222eSGlenn Barry 	    /* Get UTF-8 size of next wide char */
276ba7b222eSGlenn Barry 	  ch = *ucs2str++;
277ba7b222eSGlenn Barry #ifdef K5_BE
278ba7b222eSGlenn Barry 	    if (little_endian)
279ba7b222eSGlenn Barry 		ch = SWAP16(ch);
280ba7b222eSGlenn Barry #endif
281ba7b222eSGlenn Barry 
282ba7b222eSGlenn Barry 	    n = krb5int_ucs2_to_utf8(ch, NULL);
283ba7b222eSGlenn Barry 	    if (n < 1)
284ba7b222eSGlenn Barry 		return -1;
285ba7b222eSGlenn Barry 	    if (len + n < len)
286ba7b222eSGlenn Barry 		return -1; /* overflow */
287ba7b222eSGlenn Barry 	    len += n;
288ba7b222eSGlenn Barry 	}
289ba7b222eSGlenn Barry 
290ba7b222eSGlenn Barry 	return len;
291ba7b222eSGlenn Barry     }
292*55fea89dSDan Cross 
293ba7b222eSGlenn Barry     /* Do the actual conversion. */
294ba7b222eSGlenn Barry 
295ba7b222eSGlenn Barry     n = 1;					/* In case of empty ucs2str */
296ba7b222eSGlenn Barry     while (ucs2len == -1 ? *ucs2str != 0 : --ucs2len >= 0) {
297ba7b222eSGlenn Barry       ch = *ucs2str++;
298ba7b222eSGlenn Barry #ifdef K5_BE
299ba7b222eSGlenn Barry 	if (little_endian)
300ba7b222eSGlenn Barry 	    ch = SWAP16(ch);
301ba7b222eSGlenn Barry #endif
302ba7b222eSGlenn Barry 
303ba7b222eSGlenn Barry 	n = krb5int_ucs2_to_utf8(ch, p);
304*55fea89dSDan Cross 
305ba7b222eSGlenn Barry 	if (n < 1)
306ba7b222eSGlenn Barry 	    break;
307*55fea89dSDan Cross 
308ba7b222eSGlenn Barry 	p += n;
309ba7b222eSGlenn Barry 	count -= n;			/* Space left in output buffer */
310ba7b222eSGlenn Barry     }
311ba7b222eSGlenn Barry 
312ba7b222eSGlenn Barry     /* If not enough room for last character, pad remainder with null
313ba7b222eSGlenn Barry        so that return value = original count, indicating buffer full. */
314ba7b222eSGlenn Barry     if (n == 0) {
315ba7b222eSGlenn Barry 	while (count--)
316ba7b222eSGlenn Barry 	    *p++ = 0;
317ba7b222eSGlenn Barry     }
318ba7b222eSGlenn Barry     /* Add a null terminator if there's room. */
319ba7b222eSGlenn Barry     else if (count)
320ba7b222eSGlenn Barry 	*p = 0;
321ba7b222eSGlenn Barry 
322ba7b222eSGlenn Barry     if (n == -1)			/* Conversion encountered invalid wide char. */
323ba7b222eSGlenn Barry 	return -1;
324ba7b222eSGlenn Barry 
325*55fea89dSDan Cross     /* Return the number of bytes written to output buffer, excl null. */
326ba7b222eSGlenn Barry     return (p - utf8str);
327ba7b222eSGlenn Barry }
328ba7b222eSGlenn Barry 
329ba7b222eSGlenn Barry int
krb5int_ucs2s_to_utf8s(const krb5_ucs2 * ucs2s,char ** utf8s,size_t * utf8slen)330ba7b222eSGlenn Barry krb5int_ucs2s_to_utf8s(const krb5_ucs2 *ucs2s,
331ba7b222eSGlenn Barry 		       char **utf8s,
332ba7b222eSGlenn Barry 		       size_t *utf8slen)
333ba7b222eSGlenn Barry {
334ba7b222eSGlenn Barry     ssize_t len;
335ba7b222eSGlenn Barry 
336ba7b222eSGlenn Barry     len = k5_ucs2s_to_utf8s(NULL, ucs2s, 0, -1, 0);
337ba7b222eSGlenn Barry     if (len < 0) {
338ba7b222eSGlenn Barry 	return EINVAL;
339ba7b222eSGlenn Barry     }
340ba7b222eSGlenn Barry 
341ba7b222eSGlenn Barry     *utf8s = (char *)malloc((size_t)len + 1);
342ba7b222eSGlenn Barry     if (*utf8s == NULL) {
343ba7b222eSGlenn Barry 	return ENOMEM;
344ba7b222eSGlenn Barry     }
345ba7b222eSGlenn Barry 
346ba7b222eSGlenn Barry     len = k5_ucs2s_to_utf8s(*utf8s, ucs2s, (size_t)len + 1, -1, 0);
347ba7b222eSGlenn Barry     if (len < 0) {
348ba7b222eSGlenn Barry 	free(*utf8s);
349ba7b222eSGlenn Barry 	*utf8s = NULL;
350ba7b222eSGlenn Barry 	return EINVAL;
351ba7b222eSGlenn Barry     }
352ba7b222eSGlenn Barry 
353ba7b222eSGlenn Barry     if (utf8slen != NULL) {
354ba7b222eSGlenn Barry 	*utf8slen = len;
355ba7b222eSGlenn Barry     }
356ba7b222eSGlenn Barry 
357ba7b222eSGlenn Barry     return 0;
358ba7b222eSGlenn Barry }
359ba7b222eSGlenn Barry 
360ba7b222eSGlenn Barry int
krb5int_ucs2les_to_utf8s(const unsigned char * ucs2les,char ** utf8s,size_t * utf8slen)361ba7b222eSGlenn Barry krb5int_ucs2les_to_utf8s(const unsigned char *ucs2les,
362ba7b222eSGlenn Barry 			 char **utf8s,
363ba7b222eSGlenn Barry 			 size_t *utf8slen)
364ba7b222eSGlenn Barry {
365ba7b222eSGlenn Barry     ssize_t len;
366ba7b222eSGlenn Barry 
367ba7b222eSGlenn Barry     len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2les, 0, -1, 1);
368ba7b222eSGlenn Barry     if (len < 0)
369ba7b222eSGlenn Barry 	return EINVAL;
370ba7b222eSGlenn Barry 
371ba7b222eSGlenn Barry     *utf8s = (char *)malloc((size_t)len + 1);
372ba7b222eSGlenn Barry     if (*utf8s == NULL) {
373ba7b222eSGlenn Barry 	return ENOMEM;
374ba7b222eSGlenn Barry     }
375ba7b222eSGlenn Barry 
376ba7b222eSGlenn Barry     len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les, (size_t)len + 1, -1, 1);
377ba7b222eSGlenn Barry     if (len < 0) {
378ba7b222eSGlenn Barry 	free(*utf8s);
379ba7b222eSGlenn Barry 	*utf8s = NULL;
380ba7b222eSGlenn Barry 	return EINVAL;
381ba7b222eSGlenn Barry     }
382ba7b222eSGlenn Barry 
383ba7b222eSGlenn Barry     if (utf8slen != NULL) {
384ba7b222eSGlenn Barry 	*utf8slen = len;
385ba7b222eSGlenn Barry     }
386ba7b222eSGlenn Barry 
387ba7b222eSGlenn Barry     return 0;
388ba7b222eSGlenn Barry }
389ba7b222eSGlenn Barry 
390ba7b222eSGlenn Barry int
krb5int_ucs2cs_to_utf8s(const krb5_ucs2 * ucs2s,size_t ucs2slen,char ** utf8s,size_t * utf8slen)391ba7b222eSGlenn Barry krb5int_ucs2cs_to_utf8s(const krb5_ucs2 *ucs2s,
392ba7b222eSGlenn Barry                         size_t ucs2slen,
393ba7b222eSGlenn Barry                         char **utf8s,
394ba7b222eSGlenn Barry                         size_t *utf8slen)
395ba7b222eSGlenn Barry {
396ba7b222eSGlenn Barry     ssize_t len;
397ba7b222eSGlenn Barry 
398ba7b222eSGlenn Barry     if (ucs2slen > SSIZE_MAX)
399ba7b222eSGlenn Barry 	return ERANGE;
400ba7b222eSGlenn Barry 
401ba7b222eSGlenn Barry     len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2s, 0,
402ba7b222eSGlenn Barry 			    (ssize_t)ucs2slen, 0);
403ba7b222eSGlenn Barry     if (len < 0)
404ba7b222eSGlenn Barry 	return EINVAL;
405ba7b222eSGlenn Barry 
406ba7b222eSGlenn Barry     *utf8s = (char *)malloc((size_t)len + 1);
407ba7b222eSGlenn Barry     if (*utf8s == NULL) {
408ba7b222eSGlenn Barry 	return ENOMEM;
409ba7b222eSGlenn Barry     }
410ba7b222eSGlenn Barry 
411ba7b222eSGlenn Barry     len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2s,
412ba7b222eSGlenn Barry 			    (size_t)len + 1, (ssize_t)ucs2slen, 0);
413ba7b222eSGlenn Barry     if (len < 0) {
414ba7b222eSGlenn Barry 	free(*utf8s);
415ba7b222eSGlenn Barry 	*utf8s = NULL;
416ba7b222eSGlenn Barry 	return EINVAL;
417ba7b222eSGlenn Barry     }
418ba7b222eSGlenn Barry 
419ba7b222eSGlenn Barry     if (utf8slen != NULL) {
420ba7b222eSGlenn Barry 	*utf8slen = len;
421ba7b222eSGlenn Barry     }
422ba7b222eSGlenn Barry 
423ba7b222eSGlenn Barry     return 0;
424ba7b222eSGlenn Barry }
425ba7b222eSGlenn Barry 
426ba7b222eSGlenn Barry int
krb5int_ucs2lecs_to_utf8s(const unsigned char * ucs2les,size_t ucs2leslen,char ** utf8s,size_t * utf8slen)427ba7b222eSGlenn Barry krb5int_ucs2lecs_to_utf8s(const unsigned char *ucs2les,
428ba7b222eSGlenn Barry                           size_t ucs2leslen,
429ba7b222eSGlenn Barry                           char **utf8s,
430ba7b222eSGlenn Barry                           size_t *utf8slen)
431ba7b222eSGlenn Barry {
432ba7b222eSGlenn Barry     ssize_t len;
433ba7b222eSGlenn Barry 
434ba7b222eSGlenn Barry     if (ucs2leslen > SSIZE_MAX)
435ba7b222eSGlenn Barry 	return ERANGE;
436ba7b222eSGlenn Barry 
437ba7b222eSGlenn Barry     len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2les, 0,
438ba7b222eSGlenn Barry 			    (ssize_t)ucs2leslen, 1);
439ba7b222eSGlenn Barry     if (len < 0)
440ba7b222eSGlenn Barry 	return EINVAL;
441ba7b222eSGlenn Barry 
442ba7b222eSGlenn Barry     *utf8s = (char *)malloc((size_t)len + 1);
443ba7b222eSGlenn Barry     if (*utf8s == NULL) {
444ba7b222eSGlenn Barry 	return ENOMEM;
445ba7b222eSGlenn Barry     }
446ba7b222eSGlenn Barry 
447ba7b222eSGlenn Barry     len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les,
448ba7b222eSGlenn Barry 			    (size_t)len + 1, (ssize_t)ucs2leslen, 1);
449ba7b222eSGlenn Barry     if (len < 0) {
450ba7b222eSGlenn Barry 	free(*utf8s);
451ba7b222eSGlenn Barry 	*utf8s = NULL;
452ba7b222eSGlenn Barry 	return EINVAL;
453ba7b222eSGlenn Barry     }
454ba7b222eSGlenn Barry 
455ba7b222eSGlenn Barry     if (utf8slen != NULL) {
456ba7b222eSGlenn Barry 	*utf8slen = len;
457ba7b222eSGlenn Barry     }
458ba7b222eSGlenn Barry 
459ba7b222eSGlenn Barry     return 0;
460ba7b222eSGlenn Barry }
461ba7b222eSGlenn Barry 
462