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