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