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