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