1 1.3 christos /* $NetBSD: utf-8-conv.c,v 1.4 2025/09/05 21:16:22 christos Exp $ */ 2 1.2 christos 3 1.2 christos /* $OpenLDAP$ */ 4 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 1.1 lukem * 6 1.4 christos * Copyright 1998-2024 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.2 christos #include <sys/cdefs.h> 44 1.3 christos __RCSID("$NetBSD: utf-8-conv.c,v 1.4 2025/09/05 21:16:22 christos Exp $"); 45 1.2 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.2 christos #if SIZEOF_WCHAR_T > 4 200 1.2 christos /* UL is not strictly needed by ANSI C */ 201 1.2 christos if( wchar < (wchar_t)0x80000000UL ) 202 1.2 christos #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.2 christos } else 247 1.2 christos #if SIZEOF_WCHAR_T > 4 248 1.2 christos /* UL is not strictly needed by ANSI C */ 249 1.2 christos if( wchar < (wchar_t)0x80000000UL ) 250 1.2 christos #endif /* SIZEOF_WCHAR_T > 4 */ 251 1.2 christos { 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.2 christos #if SIZEOF_WCHAR_T > 4 262 1.2 christos } else { 263 1.1 lukem len = -1; 264 1.2 christos #endif /* SIZEOF_WCHAR_T > 4 */ 265 1.2 christos } 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.2 christos #ifdef ANDROID 337 1.2 christos int wctomb(char *s, wchar_t wc) { return wcrtomb(s,wc,NULL); } 338 1.2 christos int mbtowc(wchar_t *pwc, const char *s, size_t n) { return mbrtowc(pwc, s, n, NULL); } 339 1.2 christos #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.2 christos #endif /* SIZEOF_WCHAR_T >= 4 */ 491