xref: /illumos-gate/usr/src/lib/iconv_modules/utf-8/common/ace_utf8.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <dlfcn.h>
30 #include <link.h>
31 #include <sys/utsname.h>
32 #include <ctype.h>
33 #include <strings.h>
34 #include <string.h>
35 #include <idn/api.h>
36 #include <idn/version.h>
37 #include "ace.h"
38 
39 
40 void *
41 _icv_open()
42 {
43 	ace_state_t *cd;
44 
45 	cd = (ace_state_t *)calloc(1, sizeof(ace_state_t));
46 	if (cd == (ace_state_t *)NULL) {
47 		errno = ENOMEM;
48 		return ((void *)-1);
49 	}
50 
51 	cd->libidnkit = dlopen(ICV_LIBIDNKITPATH, RTLD_LAZY);
52 	if (cd->libidnkit == (void *)NULL) {
53 		free((void *)cd);
54 		errno = EINVAL;
55 		return ((void *)-1);
56 	}
57 
58 	cd->idn_function = (idn_result_t(*)(int, const char *, char *,
59 #if defined(ICV_ACE_TO_UTF8)
60 		size_t))dlsym(cd->libidnkit, "idn_decodename");
61 #else
62 		size_t))dlsym(cd->libidnkit, "idn_encodename");
63 #endif	/* defined(ICV_ACE_TO_UTF8) */
64 	if (cd->idn_function ==
65 	    (idn_result_t(*)(int, const char *, char *, size_t))NULL) {
66 		(void) dlclose(cd->libidnkit);
67 		free((void *)cd);
68 		errno = EINVAL;
69 		return ((void *)-1);
70 	}
71 
72 	cd->ib = (uchar_t *)malloc(_SYS_NMLN);
73 	if (cd->ib == (uchar_t *)NULL) {
74 		(void) dlclose(cd->libidnkit);
75 		free((void *)cd);
76 		errno = ENOMEM;
77 		return ((void *)-1);
78 	}
79 
80 	cd->ob = (uchar_t *)malloc(_SYS_NMLN);
81 	if (cd->ob == (uchar_t *)NULL) {
82 		(void) dlclose(cd->libidnkit);
83 		free((void *)cd->ib);
84 		free((void *)cd);
85 		errno = ENOMEM;
86 		return ((void *)-1);
87 	}
88 
89 	cd->ibl = cd->obl = _SYS_NMLN;
90 	cd->iblconsumed = cd->oblremaining = 0;
91 
92 	return ((void *)cd);
93 }
94 
95 
96 void
97 _icv_close(ace_state_t *cd)
98 {
99 	if (! cd)
100 		errno = EBADF;
101 	else {
102 		(void) dlclose(cd->libidnkit);
103 		free((void *)cd->ib);
104 		free((void *)cd->ob);
105 		free((void *)cd);
106 	}
107 }
108 
109 
110 size_t
111 _icv_iconv(ace_state_t *cd, char **inbuf, size_t *inbufleft, char **outbuf,
112                 size_t *outbufleft)
113 {
114 	size_t ret_val = 0;
115 	uchar_t *ib;
116 	uchar_t *ob;
117 	uchar_t *ibtail;
118 	uchar_t *obtail;
119 	uchar_t *tmps;
120 	idn_result_t idnres;
121 	idn_action_t actions;
122 	int i;
123 
124 
125 	if (! cd) {
126 		errno = EBADF;
127 		return((size_t)-1);
128 	}
129 
130 	/*
131 	 * We need an output buffer in pretty much anycase and so we check it
132 	 * here and issue E2BIG if there the output buffer isn't supplied
133 	 * properly.
134 	 */
135 	if (!outbuf || !(*outbuf)) {
136 		errno = E2BIG;
137 		return ((size_t)-1);
138 	}
139 
140 	ob = (uchar_t *)*outbuf;
141 	obtail = ob + *outbufleft;
142 
143 	/*
144 	 * Always flush first any previously remaining output buffer at
145 	 * the conversion descriptor.
146 	 */
147 	for (i = 0; i < cd->oblremaining; i++) {
148 		if (ob >= obtail) {
149 			errno = E2BIG;
150 			cd->oblremaining -= i;
151 			(void) memmove((void *)cd->ob,
152 				(const void *)(cd->ob + i), cd->oblremaining);
153 			ret_val = (size_t)-1;
154 			goto ICV_ICONV_RETURN_TWO;
155 		}
156 		*ob++ = cd->ob[i];
157 	}
158 	cd->oblremaining = 0;
159 
160 #ifdef IDNKIT_VERSION_LIBIDN
161 
162 	/* IDNkit v2 */
163 
164 	actions =
165 		 IDN_RTCONV
166 		|IDN_PROHCHECK
167 		|IDN_NFCCHECK
168 		|IDN_PREFCHECK
169 		|IDN_COMBCHECK
170 		|IDN_CTXOLITECHECK
171 		|IDN_BIDICHECK
172 		|IDN_LOCALCHECK
173 		|IDN_IDNCONV
174 		|IDN_LENCHECK;
175 
176 # if defined(ICV_ACE_TO_UTF8)
177 	actions |= IDN_RTCHECK;
178 # else
179 	actions |= IDN_MAP;
180 # endif
181 
182 #else
183 
184 	/* IDNkit v1 */
185 	actions =
186 		 IDN_DELIMMAP
187 		|IDN_NAMEPREP
188 		|IDN_IDNCONV
189 		|IDN_ASCCHECK;
190 
191 # if defined(ICV_ACE_TO_UTF8)
192 	actions |= IDN_RTCHECK;
193 # else
194 	actions |= IDN_LOCALMAP;
195 # endif
196 
197 #endif
198 
199 #if !defined(ICV_IDN_ALLOW_UNASSIGNED)
200 	actions |= IDN_UNASCHECK;
201 #endif
202 
203 	/* Process reset request. */
204 	if (!inbuf || !(*inbuf)) {
205 		if (cd->iblconsumed > 0) {
206 			if (cd->iblconsumed >= cd->ibl) {
207 				cd->ibl += _SYS_NMLN;
208 				tmps = (uchar_t *)realloc((void *)cd->ib,
209 							cd->ibl);
210 				if (tmps == (uchar_t *)NULL) {
211 					/*
212 					 * We couldn't allocate any more;
213 					 * return with realloc()'s errno.
214 					 */
215 					cd->ibl -= _SYS_NMLN;
216 					ret_val = (size_t)-1;
217 					goto ICV_ICONV_RETURN_TWO;
218 				}
219 				cd->ib = tmps;
220 			}
221 
222 			*(cd->ib + cd->iblconsumed++) = '\0';
223 
224 			i = 0;
225 ICV_ICONV_LOOP_ONE:
226 			idnres = (*(cd->idn_function))(actions,
227 			    (const char *)cd->ib, (char *)cd->ob,
228 				cd->obl);
229 			switch (idnres) {
230 			case idn_success:
231 				break;
232 			case idn_buffer_overflow:
233 				if (++i >= 2) {
234 					errno = EILSEQ;
235 					ret_val = (size_t)-1;
236 					goto ICV_ICONV_RETURN_TWO;
237 				}
238 				cd->obl += _SYS_NMLN;
239 				tmps = (uchar_t *)realloc((void *)cd->ob,
240 							cd->obl);
241 				if (tmps == (uchar_t *)NULL) {
242 					/*
243 					 * We couldn't allocate any more;
244 					 * return with realloc()'s errno.
245 					 */
246 					cd->obl -= _SYS_NMLN;
247 					ret_val = (size_t)-1;
248 					goto ICV_ICONV_RETURN_TWO;
249 				}
250 				cd->ob = tmps;
251 				goto ICV_ICONV_LOOP_ONE;
252 			default:
253 				/*
254 				 * Anything else we just treat
255 				 * as illegal sequence error.
256 				 */
257 				errno = EILSEQ;
258 				ret_val = (size_t)-1;
259 				goto ICV_ICONV_RETURN_TWO;
260 			}
261 
262 			cd->iblconsumed = 0;
263 
264 			cd->oblremaining = strlen((const char *)cd->ob);
265 			for (i = 0; i < cd->oblremaining; i++) {
266 				if (ob >= obtail) {
267 					errno = E2BIG;
268 					cd->oblremaining -= i;
269 					(void) memmove((void *)cd->ob,
270 					    (const void *)(cd->ob + i),
271 						cd->oblremaining);
272 					ret_val = (size_t)-1;
273 					goto ICV_ICONV_RETURN_TWO;
274 				}
275 				*ob++ = cd->ob[i];
276 			}
277 			cd->oblremaining = 0;
278 		}
279 
280 		ret_val = (size_t)0;
281 		goto ICV_ICONV_RETURN_TWO;
282 	}
283 
284 	ib = (uchar_t *)*inbuf;
285 	ibtail = ib + *inbufleft;
286 
287 	while (ib < ibtail) {
288 		/*
289 		 * We only use bare minimum single byte space class characters
290 		 * as delimiters between names.
291 		 */
292 		if (isspace(*ib)) {
293 			if (cd->iblconsumed > 0) {
294 				if (cd->iblconsumed >= cd->ibl) {
295 					cd->ibl += _SYS_NMLN;
296 					tmps = (uchar_t *)realloc(
297 						(void *)cd->ib, cd->ibl);
298 					if (tmps == (uchar_t *)NULL) {
299 						/*
300 						 * We couldn't allocate any
301 						 * more; return with
302 						 * realloc()'s errno.
303 						 */
304 						cd->ibl -= _SYS_NMLN;
305 						ret_val = (size_t)-1;
306 						break;
307 					}
308 					cd->ib = tmps;
309 				}
310 				*(cd->ib + cd->iblconsumed) = '\0';
311 				i = 0;
312 ICV_ICONV_LOOP:
313 				idnres = (*(cd->idn_function))(actions,
314 				    (const char *)cd->ib, (char *)cd->ob,
315 					cd->obl);
316 				switch (idnres) {
317 				case idn_success:
318 					break;
319 				case idn_buffer_overflow:
320 					if (++i >= 2) {
321 						errno = EILSEQ;
322 						ret_val = (size_t)-1;
323 						goto ICV_ICONV_RETURN;
324 					}
325 					cd->obl += _SYS_NMLN;
326 					tmps = (uchar_t *)realloc(
327 						(void *)cd->ob, cd->obl);
328 					if (tmps == (uchar_t *)NULL) {
329 						/*
330 						 * We couldn't allocate any
331 						 * more; return with
332 						 * realloc()'s errno.
333 						 */
334 						cd->obl -= _SYS_NMLN;
335 						ret_val = (size_t)-1;
336 						goto ICV_ICONV_RETURN;
337 					}
338 					cd->ob = tmps;
339 					goto ICV_ICONV_LOOP;
340 				default:
341 					/*
342 					 * Anything else we just treat
343 					 * as illegal sequence error.
344 					 */
345 					errno = EILSEQ;
346 					ret_val = (size_t)-1;
347 					goto ICV_ICONV_RETURN;
348 				}
349 
350 				cd->iblconsumed = 0;
351 
352 				cd->oblremaining = strlen((const char *)cd->ob);
353 				for (i = 0; i < cd->oblremaining; i++) {
354 					if (ob >= obtail) {
355 						errno = E2BIG;
356 						ret_val = (size_t)-1;
357 						cd->oblremaining -= i;
358 						(void) memmove((void *)cd->ob,
359 						    (const void *)(cd->ob + i),
360 							cd->oblremaining);
361 						goto ICV_ICONV_RETURN;
362 					}
363 					*ob++ = cd->ob[i];
364 				}
365 				cd->oblremaining = 0;
366 			}
367 			if (ob >= obtail) {
368 				errno = E2BIG;
369 				ret_val = (size_t)-1;
370 				break;
371 			}
372 			*ob++ = *ib++;
373 		} else {
374 			if (cd->iblconsumed >= cd->ibl) {
375 				cd->ibl += _SYS_NMLN;
376 				tmps = (uchar_t *)realloc((void *)cd->ib,
377 						cd->ibl);
378 				if (tmps == (uchar_t *)NULL) {
379 					/*
380 					 * We couldn't allocate any more;
381 					 * return with realloc()'s errno.
382 					 */
383 					cd->ibl -= _SYS_NMLN;
384 					ret_val = (size_t)-1;
385 					break;
386 				}
387 				cd->ib = tmps;
388 			}
389 			*(cd->ib + cd->iblconsumed++) = *ib++;
390 		}
391 	} /* while (ib < ibtail) */
392 
393 ICV_ICONV_RETURN:
394 	*inbuf = (char *)ib;
395 	*inbufleft = ibtail - ib;
396 ICV_ICONV_RETURN_TWO:
397 	*outbuf = (char *)ob;
398 	*outbufleft = obtail - ob;
399 
400 	return(ret_val);
401 }
402