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