utf-8-conv.c revision 1.1.1.8 1 1.1.1.6 christos /* $NetBSD: utf-8-conv.c,v 1.1.1.8 2020/08/11 13:12:05 christos Exp $ */
2 1.1.1.2 lukem
3 1.1.1.4 tron /* $OpenLDAP$ */
4 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 1.1 lukem *
6 1.1.1.8 christos * Copyright 1998-2020 The OpenLDAP Foundation.
7 1.1 lukem * All rights reserved.
8 1.1 lukem *
9 1.1 lukem * Redistribution and use in source and binary forms, with or without
10 1.1 lukem * modification, are permitted only as authorized by the OpenLDAP
11 1.1 lukem * Public License.
12 1.1 lukem *
13 1.1 lukem * A copy of this license is available in the file LICENSE in the
14 1.1 lukem * top-level directory of the distribution or, alternatively, at
15 1.1 lukem * <http://www.OpenLDAP.org/license.html>.
16 1.1 lukem */
17 1.1 lukem /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
18 1.1 lukem *
19 1.1 lukem * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
20 1.1 lukem * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
21 1.1 lukem * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
22 1.1 lukem * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
23 1.1 lukem * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
24 1.1 lukem * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
25 1.1 lukem * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
26 1.1 lukem * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
27 1.1 lukem *---
28 1.1 lukem * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
29 1.1 lukem * can be found in the file "build/LICENSE-2.0.1" in this distribution
30 1.1 lukem * of OpenLDAP Software.
31 1.1 lukem */
32 1.1 lukem
33 1.1 lukem /*
34 1.1 lukem * UTF-8 Conversion Routines
35 1.1 lukem *
36 1.1 lukem * These routines convert between Wide Character and UTF-8,
37 1.1 lukem * or between MultiByte and UTF-8 encodings.
38 1.1 lukem *
39 1.1 lukem * Both single character and string versions of the functions are provided.
40 1.1 lukem * All functions return -1 if the character or string cannot be converted.
41 1.1 lukem */
42 1.1 lukem
43 1.1.1.5 christos #include <sys/cdefs.h>
44 1.1.1.6 christos __RCSID("$NetBSD: utf-8-conv.c,v 1.1.1.8 2020/08/11 13:12:05 christos Exp $");
45 1.1.1.5 christos
46 1.1 lukem #include "portable.h"
47 1.1 lukem
48 1.1 lukem #if SIZEOF_WCHAR_T >= 4
49 1.1 lukem /* These routines assume ( sizeof(wchar_t) >= 4 ) */
50 1.1 lukem
51 1.1 lukem #include <stdio.h>
52 1.1 lukem #include <ac/stdlib.h> /* For wctomb, wcstombs, mbtowc, mbstowcs */
53 1.1 lukem #include <ac/string.h>
54 1.1 lukem #include <ac/time.h> /* for time_t */
55 1.1 lukem
56 1.1 lukem #include "ldap-int.h"
57 1.1 lukem
58 1.1 lukem #include <ldap_utf8.h>
59 1.1 lukem
60 1.1 lukem static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
61 1.1 lukem
62 1.1 lukem
63 1.1 lukem /*-----------------------------------------------------------------------------
64 1.1 lukem UTF-8 Format Summary
65 1.1 lukem
66 1.1 lukem ASCII chars 7 bits
67 1.1 lukem 0xxxxxxx
68 1.1 lukem
69 1.1 lukem 2-character UTF-8 sequence: 11 bits
70 1.1 lukem 110xxxxx 10xxxxxx
71 1.1 lukem
72 1.1 lukem 3-character UTF-8 16 bits
73 1.1 lukem 1110xxxx 10xxxxxx 10xxxxxx
74 1.1 lukem
75 1.1 lukem 4-char UTF-8 21 bits
76 1.1 lukem 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
77 1.1 lukem
78 1.1 lukem 5-char UTF-8 26 bits
79 1.1 lukem 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
80 1.1 lukem
81 1.1 lukem 6-char UTF-8 31 bits
82 1.1 lukem 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
83 1.1 lukem
84 1.1 lukem Unicode address space (0 - 0x10FFFF) 21 bits
85 1.1 lukem ISO-10646 address space (0 - 0x7FFFFFFF) 31 bits
86 1.1 lukem
87 1.1 lukem Note: This code does not prevent UTF-8 sequences which are longer than
88 1.1 lukem necessary from being decoded.
89 1.1 lukem */
90 1.1 lukem
91 1.1 lukem /*-----------------------------------------------------------------------------
92 1.1 lukem Convert a UTF-8 character to a wide char.
93 1.1 lukem Return the length of the UTF-8 input character in bytes.
94 1.1 lukem */
95 1.1 lukem int
96 1.1 lukem ldap_x_utf8_to_wc ( wchar_t *wchar, const char *utf8char )
97 1.1 lukem {
98 1.1 lukem int utflen, i;
99 1.1 lukem wchar_t ch;
100 1.1 lukem
101 1.1 lukem if (utf8char == NULL) return -1;
102 1.1 lukem
103 1.1 lukem /* Get UTF-8 sequence length from 1st byte */
104 1.1 lukem utflen = LDAP_UTF8_CHARLEN2(utf8char, utflen);
105 1.1 lukem
106 1.1 lukem if( utflen==0 || utflen > (int)LDAP_MAX_UTF8_LEN ) return -1;
107 1.1 lukem
108 1.1 lukem /* First byte minus length tag */
109 1.1 lukem ch = (wchar_t)(utf8char[0] & mask[utflen]);
110 1.1 lukem
111 1.1 lukem for(i=1; i < utflen; i++) {
112 1.1 lukem /* Subsequent bytes must start with 10 */
113 1.1 lukem if ((utf8char[i] & 0xc0) != 0x80) return -1;
114 1.1 lukem
115 1.1 lukem ch <<= 6; /* 6 bits of data in each subsequent byte */
116 1.1 lukem ch |= (wchar_t)(utf8char[i] & 0x3f);
117 1.1 lukem }
118 1.1 lukem
119 1.1 lukem if (wchar) *wchar = ch;
120 1.1 lukem
121 1.1 lukem return utflen;
122 1.1 lukem }
123 1.1 lukem
124 1.1 lukem /*-----------------------------------------------------------------------------
125 1.1 lukem Convert a UTF-8 string to a wide char string.
126 1.1 lukem No more than 'count' wide chars will be written to the output buffer.
127 1.1 lukem Return the size of the converted string in wide chars, excl null terminator.
128 1.1 lukem */
129 1.1 lukem int
130 1.1 lukem ldap_x_utf8s_to_wcs ( wchar_t *wcstr, const char *utf8str, size_t count )
131 1.1 lukem {
132 1.1 lukem size_t wclen = 0;
133 1.1 lukem int utflen, i;
134 1.1 lukem wchar_t ch;
135 1.1 lukem
136 1.1 lukem
137 1.1 lukem /* If input ptr is NULL or empty... */
138 1.1 lukem if (utf8str == NULL || !*utf8str) {
139 1.1 lukem if ( wcstr )
140 1.1 lukem *wcstr = 0;
141 1.1 lukem return 0;
142 1.1 lukem }
143 1.1 lukem
144 1.1 lukem /* Examine next UTF-8 character. If output buffer is NULL, ignore count */
145 1.1 lukem while ( *utf8str && (wcstr==NULL || wclen<count) ) {
146 1.1 lukem /* Get UTF-8 sequence length from 1st byte */
147 1.1 lukem utflen = LDAP_UTF8_CHARLEN2(utf8str, utflen);
148 1.1 lukem
149 1.1 lukem if( utflen==0 || utflen > (int)LDAP_MAX_UTF8_LEN ) return -1;
150 1.1 lukem
151 1.1 lukem /* First byte minus length tag */
152 1.1 lukem ch = (wchar_t)(utf8str[0] & mask[utflen]);
153 1.1 lukem
154 1.1 lukem for(i=1; i < utflen; i++) {
155 1.1 lukem /* Subsequent bytes must start with 10 */
156 1.1 lukem if ((utf8str[i] & 0xc0) != 0x80) return -1;
157 1.1 lukem
158 1.1 lukem ch <<= 6; /* 6 bits of data in each subsequent byte */
159 1.1 lukem ch |= (wchar_t)(utf8str[i] & 0x3f);
160 1.1 lukem }
161 1.1 lukem
162 1.1 lukem if (wcstr) wcstr[wclen] = ch;
163 1.1 lukem
164 1.1 lukem utf8str += utflen; /* Move to next UTF-8 character */
165 1.1 lukem wclen++; /* Count number of wide chars stored/required */
166 1.1 lukem }
167 1.1 lukem
168 1.1 lukem /* Add null terminator if there's room in the buffer. */
169 1.1 lukem if (wcstr && wclen < count) wcstr[wclen] = 0;
170 1.1 lukem
171 1.1 lukem return wclen;
172 1.1 lukem }
173 1.1 lukem
174 1.1 lukem
175 1.1 lukem /*-----------------------------------------------------------------------------
176 1.1 lukem Convert one wide char to a UTF-8 character.
177 1.1 lukem Return the length of the converted UTF-8 character in bytes.
178 1.1 lukem No more than 'count' bytes will be written to the output buffer.
179 1.1 lukem */
180 1.1 lukem int
181 1.1 lukem ldap_x_wc_to_utf8 ( char *utf8char, wchar_t wchar, size_t count )
182 1.1 lukem {
183 1.1 lukem int len=0;
184 1.1 lukem
185 1.1 lukem if (utf8char == NULL) /* Just determine the required UTF-8 char length. */
186 1.1 lukem { /* Ignore count */
187 1.1 lukem if( wchar < 0 )
188 1.1 lukem return -1;
189 1.1 lukem if( wchar < 0x80 )
190 1.1 lukem return 1;
191 1.1 lukem if( wchar < 0x800 )
192 1.1 lukem return 2;
193 1.1 lukem if( wchar < 0x10000 )
194 1.1 lukem return 3;
195 1.1 lukem if( wchar < 0x200000 )
196 1.1 lukem return 4;
197 1.1 lukem if( wchar < 0x4000000 )
198 1.1 lukem return 5;
199 1.1.1.2 lukem #if SIZEOF_WCHAR_T > 4
200 1.1.1.2 lukem /* UL is not strictly needed by ANSI C */
201 1.1.1.2 lukem if( wchar < (wchar_t)0x80000000UL )
202 1.1.1.2 lukem #endif /* SIZEOF_WCHAR_T > 4 */
203 1.1 lukem return 6;
204 1.1 lukem return -1;
205 1.1 lukem }
206 1.1 lukem
207 1.1 lukem
208 1.1 lukem if ( wchar < 0 ) { /* Invalid wide character */
209 1.1 lukem len = -1;
210 1.1 lukem
211 1.1 lukem } else if( wchar < 0x80 ) {
212 1.1 lukem if (count >= 1) {
213 1.1 lukem utf8char[len++] = (char)wchar;
214 1.1 lukem }
215 1.1 lukem
216 1.1 lukem } else if( wchar < 0x800 ) {
217 1.1 lukem if (count >=2) {
218 1.1 lukem utf8char[len++] = 0xc0 | ( wchar >> 6 );
219 1.1 lukem utf8char[len++] = 0x80 | ( wchar & 0x3f );
220 1.1 lukem }
221 1.1 lukem
222 1.1 lukem } else if( wchar < 0x10000 ) {
223 1.1 lukem if (count >= 3) {
224 1.1 lukem utf8char[len++] = 0xe0 | ( wchar >> 12 );
225 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
226 1.1 lukem utf8char[len++] = 0x80 | ( wchar & 0x3f );
227 1.1 lukem }
228 1.1 lukem
229 1.1 lukem } else if( wchar < 0x200000 ) {
230 1.1 lukem if (count >= 4) {
231 1.1 lukem utf8char[len++] = 0xf0 | ( wchar >> 18 );
232 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f );
233 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
234 1.1 lukem utf8char[len++] = 0x80 | ( wchar & 0x3f );
235 1.1 lukem }
236 1.1 lukem
237 1.1 lukem } else if( wchar < 0x4000000 ) {
238 1.1 lukem if (count >= 5) {
239 1.1 lukem utf8char[len++] = 0xf8 | ( wchar >> 24 );
240 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 18) & 0x3f );
241 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f );
242 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
243 1.1 lukem utf8char[len++] = 0x80 | ( wchar & 0x3f );
244 1.1 lukem }
245 1.1 lukem
246 1.1.1.2 lukem } else
247 1.1.1.2 lukem #if SIZEOF_WCHAR_T > 4
248 1.1.1.2 lukem /* UL is not strictly needed by ANSI C */
249 1.1.1.2 lukem if( wchar < (wchar_t)0x80000000UL )
250 1.1.1.2 lukem #endif /* SIZEOF_WCHAR_T > 4 */
251 1.1.1.2 lukem {
252 1.1 lukem if (count >= 6) {
253 1.1 lukem utf8char[len++] = 0xfc | ( wchar >> 30 );
254 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 24) & 0x3f );
255 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 18) & 0x3f );
256 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 12) & 0x3f );
257 1.1 lukem utf8char[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
258 1.1 lukem utf8char[len++] = 0x80 | ( wchar & 0x3f );
259 1.1 lukem }
260 1.1 lukem
261 1.1.1.2 lukem #if SIZEOF_WCHAR_T > 4
262 1.1.1.2 lukem } else {
263 1.1 lukem len = -1;
264 1.1.1.2 lukem #endif /* SIZEOF_WCHAR_T > 4 */
265 1.1.1.2 lukem }
266 1.1 lukem
267 1.1 lukem return len;
268 1.1 lukem
269 1.1 lukem }
270 1.1 lukem
271 1.1 lukem
272 1.1 lukem /*-----------------------------------------------------------------------------
273 1.1 lukem Convert a wide char string to a UTF-8 string.
274 1.1 lukem No more than 'count' bytes will be written to the output buffer.
275 1.1 lukem Return the # of bytes written to the output buffer, excl null terminator.
276 1.1 lukem */
277 1.1 lukem int
278 1.1 lukem ldap_x_wcs_to_utf8s ( char *utf8str, const wchar_t *wcstr, size_t count )
279 1.1 lukem {
280 1.1 lukem int len = 0;
281 1.1 lukem int n;
282 1.1 lukem char *p = utf8str;
283 1.1 lukem wchar_t empty = 0; /* To avoid use of L"" construct */
284 1.1 lukem
285 1.1 lukem if (wcstr == NULL) /* Treat input ptr NULL as an empty string */
286 1.1 lukem wcstr = ∅
287 1.1 lukem
288 1.1 lukem if (utf8str == NULL) /* Just compute size of output, excl null */
289 1.1 lukem {
290 1.1 lukem while (*wcstr)
291 1.1 lukem {
292 1.1 lukem /* Get UTF-8 size of next wide char */
293 1.1 lukem n = ldap_x_wc_to_utf8( NULL, *wcstr++, LDAP_MAX_UTF8_LEN);
294 1.1 lukem if (n == -1)
295 1.1 lukem return -1;
296 1.1 lukem len += n;
297 1.1 lukem }
298 1.1 lukem
299 1.1 lukem return len;
300 1.1 lukem }
301 1.1 lukem
302 1.1 lukem
303 1.1 lukem /* Do the actual conversion. */
304 1.1 lukem
305 1.1 lukem n = 1; /* In case of empty wcstr */
306 1.1 lukem while (*wcstr)
307 1.1 lukem {
308 1.1 lukem n = ldap_x_wc_to_utf8( p, *wcstr++, count);
309 1.1 lukem
310 1.1 lukem if (n <= 0) /* If encoding error (-1) or won't fit (0), quit */
311 1.1 lukem break;
312 1.1 lukem
313 1.1 lukem p += n;
314 1.1 lukem count -= n; /* Space left in output buffer */
315 1.1 lukem }
316 1.1 lukem
317 1.1 lukem /* If not enough room for last character, pad remainder with null
318 1.1 lukem so that return value = original count, indicating buffer full. */
319 1.1 lukem if (n == 0)
320 1.1 lukem {
321 1.1 lukem while (count--)
322 1.1 lukem *p++ = 0;
323 1.1 lukem }
324 1.1 lukem
325 1.1 lukem /* Add a null terminator if there's room. */
326 1.1 lukem else if (count)
327 1.1 lukem *p = 0;
328 1.1 lukem
329 1.1 lukem if (n == -1) /* Conversion encountered invalid wide char. */
330 1.1 lukem return -1;
331 1.1 lukem
332 1.1 lukem /* Return the number of bytes written to output buffer, excl null. */
333 1.1 lukem return (p - utf8str);
334 1.1 lukem }
335 1.1 lukem
336 1.1.1.4 tron #ifdef ANDROID
337 1.1.1.4 tron int wctomb(char *s, wchar_t wc) { return wcrtomb(s,wc,NULL); }
338 1.1.1.4 tron int mbtowc(wchar_t *pwc, const char *s, size_t n) { return mbrtowc(pwc, s, n, NULL); }
339 1.1.1.4 tron #endif
340 1.1 lukem
341 1.1 lukem /*-----------------------------------------------------------------------------
342 1.1 lukem Convert a UTF-8 character to a MultiByte character.
343 1.1 lukem Return the size of the converted character in bytes.
344 1.1 lukem */
345 1.1 lukem int
346 1.1 lukem ldap_x_utf8_to_mb ( char *mbchar, const char *utf8char,
347 1.1 lukem int (*f_wctomb)(char *mbchar, wchar_t wchar) )
348 1.1 lukem {
349 1.1 lukem wchar_t wchar;
350 1.1 lukem int n;
351 1.1 lukem char tmp[6]; /* Large enough for biggest multibyte char */
352 1.1 lukem
353 1.1 lukem if (f_wctomb == NULL) /* If no conversion function was given... */
354 1.1 lukem f_wctomb = wctomb; /* use the local ANSI C function */
355 1.1 lukem
356 1.1 lukem /* First convert UTF-8 char to a wide char */
357 1.1 lukem n = ldap_x_utf8_to_wc( &wchar, utf8char);
358 1.1 lukem
359 1.1 lukem if (n == -1)
360 1.1 lukem return -1; /* Invalid UTF-8 character */
361 1.1 lukem
362 1.1 lukem if (mbchar == NULL)
363 1.1 lukem n = f_wctomb( tmp, wchar );
364 1.1 lukem else
365 1.1 lukem n = f_wctomb( mbchar, wchar);
366 1.1 lukem
367 1.1 lukem return n;
368 1.1 lukem }
369 1.1 lukem
370 1.1 lukem /*-----------------------------------------------------------------------------
371 1.1 lukem Convert a UTF-8 string to a MultiByte string.
372 1.1 lukem No more than 'count' bytes will be written to the output buffer.
373 1.1 lukem Return the size of the converted string in bytes, excl null terminator.
374 1.1 lukem */
375 1.1 lukem int
376 1.1 lukem ldap_x_utf8s_to_mbs ( char *mbstr, const char *utf8str, size_t count,
377 1.1 lukem size_t (*f_wcstombs)(char *mbstr, const wchar_t *wcstr, size_t count) )
378 1.1 lukem {
379 1.1 lukem wchar_t *wcs;
380 1.1 lukem size_t wcsize;
381 1.1 lukem int n;
382 1.1 lukem
383 1.1 lukem if (f_wcstombs == NULL) /* If no conversion function was given... */
384 1.1 lukem f_wcstombs = wcstombs; /* use the local ANSI C function */
385 1.1 lukem
386 1.1 lukem if (utf8str == NULL || *utf8str == 0) /* NULL or empty input string */
387 1.1 lukem {
388 1.1 lukem if (mbstr)
389 1.1 lukem *mbstr = 0;
390 1.1 lukem return 0;
391 1.1 lukem }
392 1.1 lukem
393 1.1 lukem /* Allocate memory for the maximum size wchar string that we could get. */
394 1.1 lukem wcsize = strlen(utf8str) + 1;
395 1.1 lukem wcs = (wchar_t *)LDAP_MALLOC(wcsize * sizeof(wchar_t));
396 1.1 lukem if (wcs == NULL)
397 1.1 lukem return -1; /* Memory allocation failure. */
398 1.1 lukem
399 1.1 lukem /* First convert the UTF-8 string to a wide char string */
400 1.1 lukem n = ldap_x_utf8s_to_wcs( wcs, utf8str, wcsize);
401 1.1 lukem
402 1.1 lukem /* Then convert wide char string to multi-byte string */
403 1.1 lukem if (n != -1)
404 1.1 lukem {
405 1.1 lukem n = f_wcstombs(mbstr, wcs, count);
406 1.1 lukem }
407 1.1 lukem
408 1.1 lukem LDAP_FREE(wcs);
409 1.1 lukem
410 1.1 lukem return n;
411 1.1 lukem }
412 1.1 lukem
413 1.1 lukem /*-----------------------------------------------------------------------------
414 1.1 lukem Convert a MultiByte character to a UTF-8 character.
415 1.1 lukem 'mbsize' indicates the number of bytes of 'mbchar' to check.
416 1.1 lukem Returns the number of bytes written to the output character.
417 1.1 lukem */
418 1.1 lukem int
419 1.1 lukem ldap_x_mb_to_utf8 ( char *utf8char, const char *mbchar, size_t mbsize,
420 1.1 lukem int (*f_mbtowc)(wchar_t *wchar, const char *mbchar, size_t count) )
421 1.1 lukem {
422 1.1 lukem wchar_t wchar;
423 1.1 lukem int n;
424 1.1 lukem
425 1.1 lukem if (f_mbtowc == NULL) /* If no conversion function was given... */
426 1.1 lukem f_mbtowc = mbtowc; /* use the local ANSI C function */
427 1.1 lukem
428 1.1 lukem if (mbsize == 0) /* 0 is not valid. */
429 1.1 lukem return -1;
430 1.1 lukem
431 1.1 lukem if (mbchar == NULL || *mbchar == 0)
432 1.1 lukem {
433 1.1 lukem if (utf8char)
434 1.1 lukem *utf8char = 0;
435 1.1 lukem return 1;
436 1.1 lukem }
437 1.1 lukem
438 1.1 lukem /* First convert the MB char to a Wide Char */
439 1.1 lukem n = f_mbtowc( &wchar, mbchar, mbsize);
440 1.1 lukem
441 1.1 lukem if (n == -1)
442 1.1 lukem return -1;
443 1.1 lukem
444 1.1 lukem /* Convert the Wide Char to a UTF-8 character. */
445 1.1 lukem n = ldap_x_wc_to_utf8( utf8char, wchar, LDAP_MAX_UTF8_LEN);
446 1.1 lukem
447 1.1 lukem return n;
448 1.1 lukem }
449 1.1 lukem
450 1.1 lukem
451 1.1 lukem /*-----------------------------------------------------------------------------
452 1.1 lukem Convert a MultiByte string to a UTF-8 string.
453 1.1 lukem No more than 'count' bytes will be written to the output buffer.
454 1.1 lukem Return the size of the converted string in bytes, excl null terminator.
455 1.1 lukem */
456 1.1 lukem int
457 1.1 lukem ldap_x_mbs_to_utf8s ( char *utf8str, const char *mbstr, size_t count,
458 1.1 lukem size_t (*f_mbstowcs)(wchar_t *wcstr, const char *mbstr, size_t count) )
459 1.1 lukem {
460 1.1 lukem wchar_t *wcs;
461 1.1 lukem int n;
462 1.1 lukem size_t wcsize;
463 1.1 lukem
464 1.1 lukem if (mbstr == NULL) /* Treat NULL input string as an empty string */
465 1.1 lukem mbstr = "";
466 1.1 lukem
467 1.1 lukem if (f_mbstowcs == NULL) /* If no conversion function was given... */
468 1.1 lukem f_mbstowcs = mbstowcs; /* use the local ANSI C function */
469 1.1 lukem
470 1.1 lukem /* Allocate memory for the maximum size wchar string that we could get. */
471 1.1 lukem wcsize = strlen(mbstr) + 1;
472 1.1 lukem wcs = (wchar_t *)LDAP_MALLOC( wcsize * sizeof(wchar_t) );
473 1.1 lukem if (wcs == NULL)
474 1.1 lukem return -1;
475 1.1 lukem
476 1.1 lukem /* First convert multi-byte string to a wide char string */
477 1.1 lukem n = f_mbstowcs(wcs, mbstr, wcsize);
478 1.1 lukem
479 1.1 lukem /* Convert wide char string to UTF-8 string */
480 1.1 lukem if (n != -1)
481 1.1 lukem {
482 1.1 lukem n = ldap_x_wcs_to_utf8s( utf8str, wcs, count);
483 1.1 lukem }
484 1.1 lukem
485 1.1 lukem LDAP_FREE(wcs);
486 1.1 lukem
487 1.1 lukem return n;
488 1.1 lukem }
489 1.1 lukem
490 1.1.1.2 lukem #endif /* SIZEOF_WCHAR_T >= 4 */
491