xref: /freebsd-src/lib/libc/iconv/bsd_iconv.c (revision 559a218c9b257775fb249b67945fe4a05b7a6b9f)
1db2af393SPeter Wemm /* $NetBSD: iconv.c,v 1.11 2009/03/03 16:22:33 explorer Exp $ */
2db2af393SPeter Wemm 
3db2af393SPeter Wemm /*-
4*d915a14eSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause
5*d915a14eSPedro F. Giffuni  *
6db2af393SPeter Wemm  * Copyright (c) 2003 Citrus Project,
7db2af393SPeter Wemm  * Copyright (c) 2009, 2010 Gabor Kovesdan <gabor@FreeBSD.org>,
8db2af393SPeter Wemm  * All rights reserved.
9db2af393SPeter Wemm  *
10db2af393SPeter Wemm  * Redistribution and use in source and binary forms, with or without
11db2af393SPeter Wemm  * modification, are permitted provided that the following conditions
12db2af393SPeter Wemm  * are met:
13db2af393SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
14db2af393SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
15db2af393SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
16db2af393SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
17db2af393SPeter Wemm  *    documentation and/or other materials provided with the distribution.
18db2af393SPeter Wemm  *
19db2af393SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20db2af393SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21db2af393SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22db2af393SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23db2af393SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24db2af393SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25db2af393SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26db2af393SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27db2af393SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28db2af393SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29db2af393SPeter Wemm  * SUCH DAMAGE.
30db2af393SPeter Wemm  */
31db2af393SPeter Wemm 
32db2af393SPeter Wemm #include <sys/queue.h>
33db2af393SPeter Wemm #include <sys/types.h>
34db2af393SPeter Wemm 
35db2af393SPeter Wemm #include <assert.h>
36db2af393SPeter Wemm #include <errno.h>
37db2af393SPeter Wemm #include <iconv.h>
38db2af393SPeter Wemm #include <limits.h>
39db2af393SPeter Wemm #include <paths.h>
40db2af393SPeter Wemm #include <stdbool.h>
41db2af393SPeter Wemm #include <stdlib.h>
42db2af393SPeter Wemm #include <string.h>
43db2af393SPeter Wemm 
44db2af393SPeter Wemm #include "citrus_types.h"
45db2af393SPeter Wemm #include "citrus_module.h"
46db2af393SPeter Wemm #include "citrus_esdb.h"
47db2af393SPeter Wemm #include "citrus_hash.h"
48db2af393SPeter Wemm #include "citrus_iconv.h"
49db2af393SPeter Wemm 
50db2af393SPeter Wemm #include "iconv-internal.h"
51db2af393SPeter Wemm 
52db2af393SPeter Wemm #define ISBADF(_h_)	(!(_h_) || (_h_) == (iconv_t)-1)
53db2af393SPeter Wemm 
54db2af393SPeter Wemm static iconv_t
__bsd___iconv_open(const char * out,const char * in,struct _citrus_iconv * handle)55db2af393SPeter Wemm __bsd___iconv_open(const char *out, const char *in, struct _citrus_iconv *handle)
56db2af393SPeter Wemm {
57db2af393SPeter Wemm 	int ret;
58db2af393SPeter Wemm 
59db2af393SPeter Wemm 	/*
60db2af393SPeter Wemm 	 * Remove anything following a //, as these are options (like
61db2af393SPeter Wemm 	 * //ignore, //translate, etc) and we just don't handle them.
62db2af393SPeter Wemm 	 * This is for compatibility with software that uses these
63db2af393SPeter Wemm 	 * blindly.
64db2af393SPeter Wemm 	 */
65db2af393SPeter Wemm 	ret = _citrus_iconv_open(&handle, in, out);
66db2af393SPeter Wemm 	if (ret) {
67db2af393SPeter Wemm 		errno = ret == ENOENT ? EINVAL : ret;
68db2af393SPeter Wemm 		return ((iconv_t)-1);
69db2af393SPeter Wemm 	}
70db2af393SPeter Wemm 
71db2af393SPeter Wemm 	handle->cv_shared->ci_discard_ilseq = strcasestr(out, "//IGNORE");
72db2af393SPeter Wemm 
73db2af393SPeter Wemm 	return ((iconv_t)(void *)handle);
74db2af393SPeter Wemm }
75db2af393SPeter Wemm 
76db2af393SPeter Wemm iconv_t
__bsd_iconv_open(const char * out,const char * in)77db2af393SPeter Wemm __bsd_iconv_open(const char *out, const char *in)
78db2af393SPeter Wemm {
79db2af393SPeter Wemm 
80db2af393SPeter Wemm 	return (__bsd___iconv_open(out, in, NULL));
81db2af393SPeter Wemm }
82db2af393SPeter Wemm 
83db2af393SPeter Wemm int
__bsd_iconv_open_into(const char * out,const char * in,iconv_allocation_t * ptr)84db2af393SPeter Wemm __bsd_iconv_open_into(const char *out, const char *in, iconv_allocation_t *ptr)
85db2af393SPeter Wemm {
86db2af393SPeter Wemm 	struct _citrus_iconv *handle;
87db2af393SPeter Wemm 
88db2af393SPeter Wemm 	handle = (struct _citrus_iconv *)ptr;
89db2af393SPeter Wemm 	return ((__bsd___iconv_open(out, in, handle) == (iconv_t)-1) ? -1 : 0);
90db2af393SPeter Wemm }
91db2af393SPeter Wemm 
92db2af393SPeter Wemm int
__bsd_iconv_close(iconv_t handle)93db2af393SPeter Wemm __bsd_iconv_close(iconv_t handle)
94db2af393SPeter Wemm {
95db2af393SPeter Wemm 
96db2af393SPeter Wemm 	if (ISBADF(handle)) {
97db2af393SPeter Wemm 		errno = EBADF;
98db2af393SPeter Wemm 		return (-1);
99db2af393SPeter Wemm 	}
100db2af393SPeter Wemm 
101db2af393SPeter Wemm 	_citrus_iconv_close((struct _citrus_iconv *)(void *)handle);
102db2af393SPeter Wemm 
103db2af393SPeter Wemm 	return (0);
104db2af393SPeter Wemm }
105db2af393SPeter Wemm 
106db2af393SPeter Wemm size_t
__bsd_iconv(iconv_t handle,char ** in,size_t * szin,char ** out,size_t * szout)1071243a98eSTijl Coosemans __bsd_iconv(iconv_t handle, char **in, size_t *szin, char **out, size_t *szout)
108db2af393SPeter Wemm {
109db2af393SPeter Wemm 	size_t ret;
110db2af393SPeter Wemm 	int err;
111db2af393SPeter Wemm 
112db2af393SPeter Wemm 	if (ISBADF(handle)) {
113db2af393SPeter Wemm 		errno = EBADF;
114db2af393SPeter Wemm 		return ((size_t)-1);
115db2af393SPeter Wemm 	}
116db2af393SPeter Wemm 
117db2af393SPeter Wemm 	err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle,
118db2af393SPeter Wemm 	    in, szin, out, szout, 0, &ret);
119db2af393SPeter Wemm 	if (err) {
120db2af393SPeter Wemm 		errno = err;
121db2af393SPeter Wemm 		ret = (size_t)-1;
122db2af393SPeter Wemm 	}
123db2af393SPeter Wemm 
124db2af393SPeter Wemm 	return (ret);
125db2af393SPeter Wemm }
126db2af393SPeter Wemm 
127db2af393SPeter Wemm size_t
__bsd___iconv(iconv_t handle,char ** in,size_t * szin,char ** out,size_t * szout,uint32_t flags,size_t * invalids)1281243a98eSTijl Coosemans __bsd___iconv(iconv_t handle, char **in, size_t *szin, char **out,
129db2af393SPeter Wemm     size_t *szout, uint32_t flags, size_t *invalids)
130db2af393SPeter Wemm {
131db2af393SPeter Wemm 	size_t ret;
132db2af393SPeter Wemm 	int err;
133db2af393SPeter Wemm 
134db2af393SPeter Wemm 	if (ISBADF(handle)) {
135db2af393SPeter Wemm 		errno = EBADF;
136db2af393SPeter Wemm 		return ((size_t)-1);
137db2af393SPeter Wemm 	}
138db2af393SPeter Wemm 
139db2af393SPeter Wemm 	err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle,
140db2af393SPeter Wemm 	    in, szin, out, szout, flags, &ret);
141db2af393SPeter Wemm 	if (invalids)
142db2af393SPeter Wemm 		*invalids = ret;
143db2af393SPeter Wemm 	if (err) {
144db2af393SPeter Wemm 		errno = err;
145db2af393SPeter Wemm 		ret = (size_t)-1;
146db2af393SPeter Wemm 	}
147db2af393SPeter Wemm 
148db2af393SPeter Wemm 	return (ret);
149db2af393SPeter Wemm }
150db2af393SPeter Wemm 
151db2af393SPeter Wemm int
__bsd___iconv_get_list(char *** rlist,size_t * rsz,bool sorted)152db2af393SPeter Wemm __bsd___iconv_get_list(char ***rlist, size_t *rsz, bool sorted)
153db2af393SPeter Wemm {
154db2af393SPeter Wemm 	int ret;
155db2af393SPeter Wemm 
156db2af393SPeter Wemm 	ret = _citrus_esdb_get_list(rlist, rsz, sorted);
157db2af393SPeter Wemm 	if (ret) {
158db2af393SPeter Wemm 		errno = ret;
159db2af393SPeter Wemm 		return (-1);
160db2af393SPeter Wemm 	}
161db2af393SPeter Wemm 
162db2af393SPeter Wemm 	return (0);
163db2af393SPeter Wemm }
164db2af393SPeter Wemm 
165db2af393SPeter Wemm void
__bsd___iconv_free_list(char ** list,size_t sz)166db2af393SPeter Wemm __bsd___iconv_free_list(char **list, size_t sz)
167db2af393SPeter Wemm {
168db2af393SPeter Wemm 
169db2af393SPeter Wemm 	_citrus_esdb_free_list(list, sz);
170db2af393SPeter Wemm }
171db2af393SPeter Wemm 
172db2af393SPeter Wemm /*
173db2af393SPeter Wemm  * GNU-compatibile non-standard interfaces.
174db2af393SPeter Wemm  */
175db2af393SPeter Wemm static int
qsort_helper(const void * first,const void * second)176db2af393SPeter Wemm qsort_helper(const void *first, const void *second)
177db2af393SPeter Wemm {
178db2af393SPeter Wemm 	const char * const *s1;
179db2af393SPeter Wemm 	const char * const *s2;
180db2af393SPeter Wemm 
181db2af393SPeter Wemm 	s1 = first;
182db2af393SPeter Wemm 	s2 = second;
183db2af393SPeter Wemm 	return (strcmp(*s1, *s2));
184db2af393SPeter Wemm }
185db2af393SPeter Wemm 
186db2af393SPeter Wemm void
__bsd_iconvlist(int (* do_one)(unsigned int,const char * const *,void *),void * data)187db2af393SPeter Wemm __bsd_iconvlist(int (*do_one) (unsigned int, const char * const *,
188db2af393SPeter Wemm     void *), void *data)
189db2af393SPeter Wemm {
190db2af393SPeter Wemm 	char **list, **names;
191db2af393SPeter Wemm 	const char * const *np;
192db2af393SPeter Wemm 	char *curitem, *curkey, *slashpos;
193db2af393SPeter Wemm 	size_t sz;
194d8a7885bSBryan Drewery 	unsigned int i, j, n;
195db2af393SPeter Wemm 
196db2af393SPeter Wemm 	i = 0;
197d8a7885bSBryan Drewery 	names = NULL;
198db2af393SPeter Wemm 
199d8a7885bSBryan Drewery 	if (__bsd___iconv_get_list(&list, &sz, true)) {
200db2af393SPeter Wemm 		list = NULL;
201d8a7885bSBryan Drewery 		goto out;
202d8a7885bSBryan Drewery 	}
203db2af393SPeter Wemm 	qsort((void *)list, sz, sizeof(char *), qsort_helper);
204db2af393SPeter Wemm 	while (i < sz) {
205db2af393SPeter Wemm 		j = 0;
206db2af393SPeter Wemm 		slashpos = strchr(list[i], '/');
207d8a7885bSBryan Drewery 		names = malloc(sz * sizeof(char *));
208d8a7885bSBryan Drewery 		if (names == NULL)
209d8a7885bSBryan Drewery 			goto out;
210d8a7885bSBryan Drewery 		curkey = strndup(list[i], slashpos - list[i]);
211d8a7885bSBryan Drewery 		if (curkey == NULL)
212d8a7885bSBryan Drewery 			goto out;
213cdd0ebc9STijl Coosemans 		names[j++] = curkey;
214db2af393SPeter Wemm 		for (; (i < sz) && (memcmp(curkey, list[i], strlen(curkey)) == 0); i++) {
215db2af393SPeter Wemm 			slashpos = strchr(list[i], '/');
216d8a7885bSBryan Drewery 			if (strcmp(curkey, &slashpos[1]) == 0)
217db2af393SPeter Wemm 				continue;
218d8a7885bSBryan Drewery 			curitem = strdup(&slashpos[1]);
219d8a7885bSBryan Drewery 			if (curitem == NULL)
220d8a7885bSBryan Drewery 				goto out;
221cdd0ebc9STijl Coosemans 			names[j++] = curitem;
222db2af393SPeter Wemm 		}
223db2af393SPeter Wemm 		np = (const char * const *)names;
224db2af393SPeter Wemm 		do_one(j, np, data);
225d8a7885bSBryan Drewery 		for (n = 0; n < j; n++)
226d8a7885bSBryan Drewery 			free(names[n]);
227db2af393SPeter Wemm 		free(names);
228d8a7885bSBryan Drewery 		names = NULL;
229db2af393SPeter Wemm 	}
230db2af393SPeter Wemm 
231d8a7885bSBryan Drewery out:
232d8a7885bSBryan Drewery 	if (names != NULL) {
233d8a7885bSBryan Drewery 		for (n = 0; n < j; n++)
234d8a7885bSBryan Drewery 			free(names[n]);
235d8a7885bSBryan Drewery 		free(names);
236d8a7885bSBryan Drewery 	}
237d8a7885bSBryan Drewery 	if (list != NULL)
238db2af393SPeter Wemm 		__bsd___iconv_free_list(list, sz);
239db2af393SPeter Wemm }
240db2af393SPeter Wemm 
241db2af393SPeter Wemm __inline const char *
__bsd_iconv_canonicalize(const char * name)242db2af393SPeter Wemm __bsd_iconv_canonicalize(const char *name)
243db2af393SPeter Wemm {
244db2af393SPeter Wemm 
245db2af393SPeter Wemm 	return (_citrus_iconv_canonicalize(name));
246db2af393SPeter Wemm }
247db2af393SPeter Wemm 
248db2af393SPeter Wemm int
__bsd_iconvctl(iconv_t cd,int request,void * argument)249db2af393SPeter Wemm __bsd_iconvctl(iconv_t cd, int request, void *argument)
250db2af393SPeter Wemm {
251db2af393SPeter Wemm 	struct _citrus_iconv *cv;
252db2af393SPeter Wemm 	struct iconv_hooks *hooks;
253db2af393SPeter Wemm 	const char *convname;
25407917187SEric van Gyzen 	char *dst;
255db2af393SPeter Wemm 	int *i;
25607917187SEric van Gyzen 	size_t srclen;
257db2af393SPeter Wemm 
258db2af393SPeter Wemm 	cv = (struct _citrus_iconv *)(void *)cd;
259db2af393SPeter Wemm 	hooks = (struct iconv_hooks *)argument;
260db2af393SPeter Wemm 	i = (int *)argument;
261db2af393SPeter Wemm 
262db2af393SPeter Wemm 	if (ISBADF(cd)) {
263db2af393SPeter Wemm 		errno = EBADF;
264db2af393SPeter Wemm 		return (-1);
265db2af393SPeter Wemm 	}
266db2af393SPeter Wemm 
267db2af393SPeter Wemm 	switch (request) {
268db2af393SPeter Wemm 	case ICONV_TRIVIALP:
269db2af393SPeter Wemm 		convname = cv->cv_shared->ci_convname;
270db2af393SPeter Wemm 		dst = strchr(convname, '/');
27107917187SEric van Gyzen 		srclen = dst - convname;
272db2af393SPeter Wemm 		dst++;
27307917187SEric van Gyzen 		*i = (srclen == strlen(dst)) && !memcmp(convname, dst, srclen);
274db2af393SPeter Wemm 		return (0);
275db2af393SPeter Wemm 	case ICONV_GET_TRANSLITERATE:
276db2af393SPeter Wemm 		*i = 1;
277db2af393SPeter Wemm 		return (0);
278db2af393SPeter Wemm 	case ICONV_SET_TRANSLITERATE:
279db2af393SPeter Wemm 		return  ((*i == 1) ? 0 : -1);
280db2af393SPeter Wemm 	case ICONV_GET_DISCARD_ILSEQ:
281db2af393SPeter Wemm 		*i = cv->cv_shared->ci_discard_ilseq ? 1 : 0;
282db2af393SPeter Wemm 		return (0);
283db2af393SPeter Wemm 	case ICONV_SET_DISCARD_ILSEQ:
284db2af393SPeter Wemm 		cv->cv_shared->ci_discard_ilseq = *i;
285db2af393SPeter Wemm 		return (0);
286db2af393SPeter Wemm 	case ICONV_SET_HOOKS:
287db2af393SPeter Wemm 		cv->cv_shared->ci_hooks = hooks;
288db2af393SPeter Wemm 		return (0);
289db2af393SPeter Wemm 	case ICONV_SET_FALLBACKS:
290db2af393SPeter Wemm 		errno = EOPNOTSUPP;
291db2af393SPeter Wemm 		return (-1);
292db2af393SPeter Wemm 	case ICONV_GET_ILSEQ_INVALID:
293db2af393SPeter Wemm 		*i = cv->cv_shared->ci_ilseq_invalid ? 1 : 0;
294db2af393SPeter Wemm 		return (0);
295db2af393SPeter Wemm 	case ICONV_SET_ILSEQ_INVALID:
296db2af393SPeter Wemm 		cv->cv_shared->ci_ilseq_invalid = *i;
297db2af393SPeter Wemm 		return (0);
298db2af393SPeter Wemm 	default:
299db2af393SPeter Wemm 		errno = EINVAL;
300db2af393SPeter Wemm 		return (-1);
301db2af393SPeter Wemm 	}
302db2af393SPeter Wemm }
303db2af393SPeter Wemm 
304db2af393SPeter Wemm void
__bsd_iconv_set_relocation_prefix(const char * orig_prefix __unused,const char * curr_prefix __unused)305db2af393SPeter Wemm __bsd_iconv_set_relocation_prefix(const char *orig_prefix __unused,
306db2af393SPeter Wemm     const char *curr_prefix __unused)
307db2af393SPeter Wemm {
308db2af393SPeter Wemm 
309db2af393SPeter Wemm }
310