1*6234e98dSwiz /* $NetBSD: citrus_iconv_std.c,v 1.16 2012/02/12 13:51:29 wiz Exp $ */
204e58308Stshiozak
304e58308Stshiozak /*-
404e58308Stshiozak * Copyright (c)2003 Citrus Project,
504e58308Stshiozak * All rights reserved.
604e58308Stshiozak *
704e58308Stshiozak * Redistribution and use in source and binary forms, with or without
804e58308Stshiozak * modification, are permitted provided that the following conditions
904e58308Stshiozak * are met:
1004e58308Stshiozak * 1. Redistributions of source code must retain the above copyright
1104e58308Stshiozak * notice, this list of conditions and the following disclaimer.
1204e58308Stshiozak * 2. Redistributions in binary form must reproduce the above copyright
1304e58308Stshiozak * notice, this list of conditions and the following disclaimer in the
1404e58308Stshiozak * documentation and/or other materials provided with the distribution.
1504e58308Stshiozak *
1604e58308Stshiozak * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1704e58308Stshiozak * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1804e58308Stshiozak * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1904e58308Stshiozak * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2004e58308Stshiozak * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2104e58308Stshiozak * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2204e58308Stshiozak * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2304e58308Stshiozak * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2404e58308Stshiozak * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2504e58308Stshiozak * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2604e58308Stshiozak * SUCH DAMAGE.
2704e58308Stshiozak */
2804e58308Stshiozak
2904e58308Stshiozak #include <sys/cdefs.h>
3004e58308Stshiozak #if defined(LIBC_SCCS) && !defined(lint)
31*6234e98dSwiz __RCSID("$NetBSD: citrus_iconv_std.c,v 1.16 2012/02/12 13:51:29 wiz Exp $");
3204e58308Stshiozak #endif /* LIBC_SCCS and not lint */
3304e58308Stshiozak
3404e58308Stshiozak #include <assert.h>
3504e58308Stshiozak #include <errno.h>
3604e58308Stshiozak #include <limits.h>
3704e58308Stshiozak #include <stdio.h>
3804e58308Stshiozak #include <stdlib.h>
3904e58308Stshiozak #include <string.h>
4086811edbSdogcow #include <machine/endian.h>
4104e58308Stshiozak #include <sys/queue.h>
4204e58308Stshiozak
4304e58308Stshiozak #include "citrus_namespace.h"
4404e58308Stshiozak #include "citrus_types.h"
4504e58308Stshiozak #include "citrus_module.h"
4604e58308Stshiozak #include "citrus_region.h"
4704e58308Stshiozak #include "citrus_mmap.h"
4858db2e99Stshiozak #include "citrus_hash.h"
4904e58308Stshiozak #include "citrus_iconv.h"
5004e58308Stshiozak #include "citrus_stdenc.h"
5104e58308Stshiozak #include "citrus_mapper.h"
5204e58308Stshiozak #include "citrus_csmapper.h"
5304e58308Stshiozak #include "citrus_memstream.h"
5404e58308Stshiozak #include "citrus_iconv_std.h"
5504e58308Stshiozak #include "citrus_esdb.h"
5604e58308Stshiozak
5704e58308Stshiozak /* ---------------------------------------------------------------------- */
5804e58308Stshiozak
5904e58308Stshiozak _CITRUS_ICONV_DECLS(iconv_std);
6004e58308Stshiozak _CITRUS_ICONV_DEF_OPS(iconv_std);
6104e58308Stshiozak
6204e58308Stshiozak
6304e58308Stshiozak /* ---------------------------------------------------------------------- */
6404e58308Stshiozak
6504e58308Stshiozak int
_citrus_iconv_std_iconv_getops(struct _citrus_iconv_ops * ops,size_t lenops,u_int32_t expected_version)6604e58308Stshiozak _citrus_iconv_std_iconv_getops(struct _citrus_iconv_ops *ops, size_t lenops,
6704e58308Stshiozak u_int32_t expected_version)
6804e58308Stshiozak {
6904e58308Stshiozak if (expected_version<_CITRUS_ICONV_ABI_VERSION || lenops<sizeof(*ops))
7004e58308Stshiozak return (EINVAL);
7104e58308Stshiozak
7204e58308Stshiozak memcpy(ops, &_citrus_iconv_std_iconv_ops,
7304e58308Stshiozak sizeof(_citrus_iconv_std_iconv_ops));
7404e58308Stshiozak
7504e58308Stshiozak return (0);
7604e58308Stshiozak }
7704e58308Stshiozak
7804e58308Stshiozak /* ---------------------------------------------------------------------- */
7904e58308Stshiozak
8004e58308Stshiozak /*
8104e58308Stshiozak * convenience routines for stdenc.
8204e58308Stshiozak */
8304e58308Stshiozak static __inline void
save_encoding_state(struct _citrus_iconv_std_encoding * se)8404e58308Stshiozak save_encoding_state(struct _citrus_iconv_std_encoding *se)
8504e58308Stshiozak {
8604e58308Stshiozak if (se->se_ps)
8704e58308Stshiozak memcpy(se->se_pssaved, se->se_ps,
8804e58308Stshiozak _stdenc_get_state_size(se->se_handle));
8904e58308Stshiozak }
9004e58308Stshiozak
9104e58308Stshiozak static __inline void
restore_encoding_state(struct _citrus_iconv_std_encoding * se)9204e58308Stshiozak restore_encoding_state(struct _citrus_iconv_std_encoding *se)
9304e58308Stshiozak {
9404e58308Stshiozak if (se->se_ps)
9504e58308Stshiozak memcpy(se->se_ps, se->se_pssaved,
9604e58308Stshiozak _stdenc_get_state_size(se->se_handle));
9704e58308Stshiozak }
9804e58308Stshiozak
9904e58308Stshiozak static __inline void
init_encoding_state(struct _citrus_iconv_std_encoding * se)10004e58308Stshiozak init_encoding_state(struct _citrus_iconv_std_encoding *se)
10104e58308Stshiozak {
10204e58308Stshiozak if (se->se_ps)
10304e58308Stshiozak _stdenc_init_state(se->se_handle, se->se_ps);
10404e58308Stshiozak }
10504e58308Stshiozak
10604e58308Stshiozak static __inline int
mbtocsx(struct _citrus_iconv_std_encoding * se,_csid_t * csid,_index_t * idx,const char ** s,size_t n,size_t * nresult)10704e58308Stshiozak mbtocsx(struct _citrus_iconv_std_encoding *se,
10804e58308Stshiozak _csid_t *csid, _index_t *idx, const char **s, size_t n,
10904e58308Stshiozak size_t *nresult)
11004e58308Stshiozak {
11104e58308Stshiozak return _stdenc_mbtocs(se->se_handle, csid, idx, s, n, se->se_ps,
11204e58308Stshiozak nresult);
11304e58308Stshiozak }
11404e58308Stshiozak
11504e58308Stshiozak static __inline int
cstombx(struct _citrus_iconv_std_encoding * se,char * s,size_t n,_csid_t csid,_index_t idx,size_t * nresult)11604e58308Stshiozak cstombx(struct _citrus_iconv_std_encoding *se,
11704e58308Stshiozak char *s, size_t n, _csid_t csid, _index_t idx, size_t *nresult)
11804e58308Stshiozak {
11904e58308Stshiozak return _stdenc_cstomb(se->se_handle, s, n, csid, idx, se->se_ps,
12004e58308Stshiozak nresult);
12104e58308Stshiozak }
12204e58308Stshiozak
12304e58308Stshiozak static __inline int
wctombx(struct _citrus_iconv_std_encoding * se,char * s,size_t n,_wc_t wc,size_t * nresult)12404e58308Stshiozak wctombx(struct _citrus_iconv_std_encoding *se,
12504e58308Stshiozak char *s, size_t n, _wc_t wc, size_t *nresult)
12604e58308Stshiozak {
12704e58308Stshiozak return _stdenc_wctomb(se->se_handle, s, n, wc, se->se_ps, nresult);
12804e58308Stshiozak }
12904e58308Stshiozak
130f3995f1aStshiozak static __inline int
put_state_resetx(struct _citrus_iconv_std_encoding * se,char * s,size_t n,size_t * nresult)131f3995f1aStshiozak put_state_resetx(struct _citrus_iconv_std_encoding *se,
132f3995f1aStshiozak char *s, size_t n, size_t *nresult)
133f3995f1aStshiozak {
134f3995f1aStshiozak return _stdenc_put_state_reset(se->se_handle, s, n, se->se_ps, nresult);
135f3995f1aStshiozak }
136f3995f1aStshiozak
1371beef8feStshiozak static __inline int
get_state_desc_gen(struct _citrus_iconv_std_encoding * se,int * rstate)1381beef8feStshiozak get_state_desc_gen(struct _citrus_iconv_std_encoding *se, int *rstate)
1391beef8feStshiozak {
1401beef8feStshiozak int ret;
1411beef8feStshiozak struct _stdenc_state_desc ssd;
1421beef8feStshiozak
1431beef8feStshiozak ret = _stdenc_get_state_desc(se->se_handle, se->se_ps,
1441beef8feStshiozak _STDENC_SDID_GENERIC, &ssd);
1451beef8feStshiozak if (!ret)
1461beef8feStshiozak *rstate = ssd.u.generic.state;
1471beef8feStshiozak
1481beef8feStshiozak return ret;
1491beef8feStshiozak }
1501beef8feStshiozak
15104e58308Stshiozak /*
15258db2e99Stshiozak * init encoding context
15304e58308Stshiozak */
15458db2e99Stshiozak static int
init_encoding(struct _citrus_iconv_std_encoding * se,struct _stdenc * cs,void * ps1,void * ps2)15558db2e99Stshiozak init_encoding(struct _citrus_iconv_std_encoding *se, struct _stdenc *cs,
15658db2e99Stshiozak void *ps1, void *ps2)
15704e58308Stshiozak {
158f174420eSchristos int ret = -1;
15904e58308Stshiozak
16058db2e99Stshiozak se->se_handle = cs;
16158db2e99Stshiozak se->se_ps = ps1;
16258db2e99Stshiozak se->se_pssaved = ps2;
16304e58308Stshiozak
16458db2e99Stshiozak if (se->se_ps)
16558db2e99Stshiozak ret = _stdenc_init_state(cs, se->se_ps);
16658db2e99Stshiozak if (!ret && se->se_pssaved)
16758db2e99Stshiozak ret = _stdenc_init_state(cs, se->se_pssaved);
16804e58308Stshiozak
16904e58308Stshiozak return ret;
17004e58308Stshiozak }
17104e58308Stshiozak
17204e58308Stshiozak static int
open_csmapper(struct _csmapper ** rcm,const char * src,const char * dst,unsigned long * rnorm)17304e58308Stshiozak open_csmapper(struct _csmapper **rcm, const char *src, const char *dst,
17404e58308Stshiozak unsigned long *rnorm)
17504e58308Stshiozak {
17604e58308Stshiozak int ret;
17704e58308Stshiozak struct _csmapper *cm;
17804e58308Stshiozak
17904e58308Stshiozak ret = _csmapper_open(&cm, src, dst, 0, rnorm);
18004e58308Stshiozak if (ret)
18104e58308Stshiozak return ret;
18204e58308Stshiozak if (_csmapper_get_src_max(cm) != 1 || _csmapper_get_dst_max(cm) != 1 ||
18304e58308Stshiozak _csmapper_get_state_size(cm) != 0) {
18404e58308Stshiozak _csmapper_close(cm);
18504e58308Stshiozak return EINVAL;
18604e58308Stshiozak }
18704e58308Stshiozak
18804e58308Stshiozak *rcm = cm;
18904e58308Stshiozak
19004e58308Stshiozak return 0;
19104e58308Stshiozak }
19204e58308Stshiozak
19304e58308Stshiozak static void
close_dsts(struct _citrus_iconv_std_dst_list * dl)19404e58308Stshiozak close_dsts(struct _citrus_iconv_std_dst_list *dl)
19504e58308Stshiozak {
19604e58308Stshiozak struct _citrus_iconv_std_dst *sd;
19704e58308Stshiozak
19804e58308Stshiozak while ((sd=TAILQ_FIRST(dl)) != NULL) {
19904e58308Stshiozak TAILQ_REMOVE(dl, sd, sd_entry);
20004e58308Stshiozak _csmapper_close(sd->sd_mapper);
20104e58308Stshiozak free(sd);
20204e58308Stshiozak }
20304e58308Stshiozak }
20404e58308Stshiozak
20504e58308Stshiozak static int
open_dsts(struct _citrus_iconv_std_dst_list * dl,const struct _esdb_charset * ec,const struct _esdb * dbdst)20604e58308Stshiozak open_dsts(struct _citrus_iconv_std_dst_list *dl,
207acdc3d1eSyamt const struct _esdb_charset *ec, const struct _esdb *dbdst)
20804e58308Stshiozak {
20904e58308Stshiozak int i, ret;
21004e58308Stshiozak struct _citrus_iconv_std_dst *sd, *sdtmp;
21104e58308Stshiozak unsigned long norm;
21204e58308Stshiozak
21304e58308Stshiozak sd = malloc(sizeof(*sd));
21404e58308Stshiozak if (sd == NULL)
21504e58308Stshiozak return errno;
21604e58308Stshiozak
21704e58308Stshiozak for (i=0; i<dbdst->db_num_charsets; i++) {
21804e58308Stshiozak ret = open_csmapper(&sd->sd_mapper, ec->ec_csname,
21904e58308Stshiozak dbdst->db_charsets[i].ec_csname, &norm);
22004e58308Stshiozak if (ret == 0) {
22104e58308Stshiozak sd->sd_csid = dbdst->db_charsets[i].ec_csid;
22204e58308Stshiozak sd->sd_norm = norm;
22304e58308Stshiozak /* insert this mapper by sorted order. */
22404e58308Stshiozak TAILQ_FOREACH(sdtmp, dl, sd_entry) {
22504e58308Stshiozak if (sdtmp->sd_norm > norm) {
22604e58308Stshiozak TAILQ_INSERT_BEFORE(sdtmp, sd,
22704e58308Stshiozak sd_entry);
22804e58308Stshiozak sd = NULL;
22904e58308Stshiozak break;
23004e58308Stshiozak }
23104e58308Stshiozak }
23204e58308Stshiozak if (sd)
23304e58308Stshiozak TAILQ_INSERT_TAIL(dl, sd, sd_entry);
23404e58308Stshiozak sd = malloc(sizeof(*sd));
23504e58308Stshiozak if (sd == NULL) {
23604e58308Stshiozak ret = errno;
23704e58308Stshiozak close_dsts(dl);
23804e58308Stshiozak return ret;
23904e58308Stshiozak }
24004e58308Stshiozak } else if (ret != ENOENT) {
24104e58308Stshiozak close_dsts(dl);
24204e58308Stshiozak free(sd);
24304e58308Stshiozak return ret;
24404e58308Stshiozak }
24504e58308Stshiozak }
24604e58308Stshiozak free(sd);
24704e58308Stshiozak return 0;
24804e58308Stshiozak }
24904e58308Stshiozak
25004e58308Stshiozak static void
close_srcs(struct _citrus_iconv_std_src_list * sl)25104e58308Stshiozak close_srcs(struct _citrus_iconv_std_src_list *sl)
25204e58308Stshiozak {
25304e58308Stshiozak struct _citrus_iconv_std_src *ss;
25404e58308Stshiozak
25504e58308Stshiozak while ((ss=TAILQ_FIRST(sl)) != NULL) {
25604e58308Stshiozak TAILQ_REMOVE(sl, ss, ss_entry);
25704e58308Stshiozak close_dsts(&ss->ss_dsts);
25804e58308Stshiozak free(ss);
25904e58308Stshiozak }
26004e58308Stshiozak }
26104e58308Stshiozak
26204e58308Stshiozak static int
open_srcs(struct _citrus_iconv_std_src_list * sl,const struct _esdb * dbsrc,const struct _esdb * dbdst)26304e58308Stshiozak open_srcs(struct _citrus_iconv_std_src_list *sl,
264acdc3d1eSyamt const struct _esdb *dbsrc, const struct _esdb *dbdst)
26504e58308Stshiozak {
26604e58308Stshiozak int i, ret, count = 0;
26704e58308Stshiozak struct _citrus_iconv_std_src *ss;
26804e58308Stshiozak
26904e58308Stshiozak ss = malloc(sizeof(*ss));
27004e58308Stshiozak if (ss == NULL)
27104e58308Stshiozak return errno;
27204e58308Stshiozak
27304e58308Stshiozak TAILQ_INIT(&ss->ss_dsts);
27404e58308Stshiozak
27504e58308Stshiozak for (i=0; i<dbsrc->db_num_charsets; i++) {
27604e58308Stshiozak ret = open_dsts(&ss->ss_dsts, &dbsrc->db_charsets[i], dbdst);
27704e58308Stshiozak if (ret)
27804e58308Stshiozak goto err;
27904e58308Stshiozak if (!TAILQ_EMPTY(&ss->ss_dsts)) {
28004e58308Stshiozak ss->ss_csid = dbsrc->db_charsets[i].ec_csid;
28104e58308Stshiozak TAILQ_INSERT_TAIL(sl, ss, ss_entry);
28204e58308Stshiozak ss = malloc(sizeof(*ss));
28304e58308Stshiozak if (ss == NULL) {
28404e58308Stshiozak ret = errno;
28504e58308Stshiozak goto err;
28604e58308Stshiozak }
28704e58308Stshiozak count++;
28804e58308Stshiozak TAILQ_INIT(&ss->ss_dsts);
28904e58308Stshiozak }
29004e58308Stshiozak }
29104e58308Stshiozak free(ss);
29204e58308Stshiozak
29304e58308Stshiozak return count ? 0 : ENOENT;
29404e58308Stshiozak
29504e58308Stshiozak err:
29604e58308Stshiozak free(ss);
29704e58308Stshiozak close_srcs(sl);
29804e58308Stshiozak return ret;
29904e58308Stshiozak }
30004e58308Stshiozak
30104e58308Stshiozak /* do convert a character */
30204e58308Stshiozak #define E_NO_CORRESPONDING_CHAR ENOENT /* XXX */
30304e58308Stshiozak static int
30458db2e99Stshiozak /*ARGSUSED*/
do_conv(const struct _citrus_iconv_std_shared * is,struct _citrus_iconv_std_context * sc,_csid_t * csid,_index_t * idx)3055b3d2342Syamt do_conv(const struct _citrus_iconv_std_shared *is,
30658db2e99Stshiozak struct _citrus_iconv_std_context *sc, _csid_t *csid, _index_t *idx)
30704e58308Stshiozak {
30804e58308Stshiozak _index_t tmpidx;
30904e58308Stshiozak int ret;
31004e58308Stshiozak struct _citrus_iconv_std_src *ss;
31104e58308Stshiozak struct _citrus_iconv_std_dst *sd;
31204e58308Stshiozak
31304e58308Stshiozak TAILQ_FOREACH(ss, &is->is_srcs, ss_entry) {
31404e58308Stshiozak if (ss->ss_csid == *csid) {
31504e58308Stshiozak TAILQ_FOREACH(sd, &ss->ss_dsts, sd_entry) {
31604e58308Stshiozak ret = _csmapper_convert(sd->sd_mapper,
31704e58308Stshiozak &tmpidx, *idx, NULL);
31804e58308Stshiozak switch (ret) {
319c1e771abStshiozak case _MAPPER_CONVERT_SUCCESS:
32004e58308Stshiozak *csid = sd->sd_csid;
32104e58308Stshiozak *idx = tmpidx;
32204e58308Stshiozak return 0;
323c1e771abStshiozak case _MAPPER_CONVERT_NONIDENTICAL:
32404e58308Stshiozak break;
325c1e771abStshiozak case _MAPPER_CONVERT_SRC_MORE:
32604e58308Stshiozak /*FALLTHROUGH*/
327c1e771abStshiozak case _MAPPER_CONVERT_DST_MORE:
32804e58308Stshiozak /*FALLTHROUGH*/
329c1e771abStshiozak case _MAPPER_CONVERT_FATAL:
33004e58308Stshiozak return EINVAL;
331c1e771abStshiozak case _MAPPER_CONVERT_ILSEQ:
33204e58308Stshiozak return EILSEQ;
33304e58308Stshiozak }
33404e58308Stshiozak }
33504e58308Stshiozak break;
33604e58308Stshiozak }
33704e58308Stshiozak }
33804e58308Stshiozak
33904e58308Stshiozak return E_NO_CORRESPONDING_CHAR;
34004e58308Stshiozak }
34104e58308Stshiozak /* ---------------------------------------------------------------------- */
34204e58308Stshiozak
34304e58308Stshiozak static int
34404e58308Stshiozak /*ARGSUSED*/
_citrus_iconv_std_iconv_init_shared(struct _citrus_iconv_shared * ci,const char * __restrict curdir,const char * __restrict src,const char * __restrict dst,const void * __restrict var,size_t lenvar)34558db2e99Stshiozak _citrus_iconv_std_iconv_init_shared(struct _citrus_iconv_shared *ci,
34604e58308Stshiozak const char * __restrict curdir,
34704e58308Stshiozak const char * __restrict src,
34804e58308Stshiozak const char * __restrict dst,
34904e58308Stshiozak const void * __restrict var, size_t lenvar)
35004e58308Stshiozak {
35104e58308Stshiozak int ret;
35258db2e99Stshiozak struct _citrus_iconv_std_shared *is;
35304e58308Stshiozak struct _citrus_esdb esdbsrc, esdbdst;
35404e58308Stshiozak
35504e58308Stshiozak is = malloc(sizeof(*is));
35604e58308Stshiozak if (is==NULL) {
35704e58308Stshiozak ret = errno;
35804e58308Stshiozak goto err0;
35904e58308Stshiozak }
36004e58308Stshiozak ret = _citrus_esdb_open(&esdbsrc, src);
36104e58308Stshiozak if (ret)
36204e58308Stshiozak goto err1;
36304e58308Stshiozak ret = _citrus_esdb_open(&esdbdst, dst);
36404e58308Stshiozak if (ret)
36504e58308Stshiozak goto err2;
36658db2e99Stshiozak ret = _stdenc_open(&is->is_src_encoding, esdbsrc.db_encname,
36758db2e99Stshiozak esdbsrc.db_variable, esdbsrc.db_len_variable);
36804e58308Stshiozak if (ret)
36904e58308Stshiozak goto err3;
37058db2e99Stshiozak ret = _stdenc_open(&is->is_dst_encoding, esdbdst.db_encname,
37158db2e99Stshiozak esdbdst.db_variable, esdbdst.db_len_variable);
37204e58308Stshiozak if (ret)
37304e58308Stshiozak goto err4;
37404e58308Stshiozak is->is_use_invalid = esdbdst.db_use_invalid;
37504e58308Stshiozak is->is_invalid = esdbdst.db_invalid;
37604e58308Stshiozak
37704e58308Stshiozak TAILQ_INIT(&is->is_srcs);
37804e58308Stshiozak ret = open_srcs(&is->is_srcs, &esdbsrc, &esdbdst);
37904e58308Stshiozak if (ret)
38004e58308Stshiozak goto err5;
38104e58308Stshiozak
38204e58308Stshiozak _esdb_close(&esdbsrc);
38304e58308Stshiozak _esdb_close(&esdbdst);
38404e58308Stshiozak ci->ci_closure = is;
38504e58308Stshiozak
38604e58308Stshiozak return 0;
38704e58308Stshiozak
38804e58308Stshiozak err5:
38958db2e99Stshiozak _stdenc_close(is->is_dst_encoding);
39004e58308Stshiozak err4:
39158db2e99Stshiozak _stdenc_close(is->is_src_encoding);
39204e58308Stshiozak err3:
39304e58308Stshiozak _esdb_close(&esdbdst);
39404e58308Stshiozak err2:
39504e58308Stshiozak _esdb_close(&esdbsrc);
39604e58308Stshiozak err1:
39704e58308Stshiozak free(is);
39804e58308Stshiozak err0:
39904e58308Stshiozak return ret;
40004e58308Stshiozak }
40104e58308Stshiozak
40204e58308Stshiozak static void
_citrus_iconv_std_iconv_uninit_shared(struct _citrus_iconv_shared * ci)40358db2e99Stshiozak _citrus_iconv_std_iconv_uninit_shared(struct _citrus_iconv_shared *ci)
40404e58308Stshiozak {
40558db2e99Stshiozak struct _citrus_iconv_std_shared *is = ci->ci_closure;
40604e58308Stshiozak
40758db2e99Stshiozak if (is == NULL)
40804e58308Stshiozak return;
40904e58308Stshiozak
41058db2e99Stshiozak _stdenc_close(is->is_src_encoding);
41158db2e99Stshiozak _stdenc_close(is->is_dst_encoding);
41204e58308Stshiozak close_srcs(&is->is_srcs);
41304e58308Stshiozak free(is);
41404e58308Stshiozak }
41504e58308Stshiozak
41604e58308Stshiozak static int
_citrus_iconv_std_iconv_init_context(struct _citrus_iconv * cv)41758db2e99Stshiozak _citrus_iconv_std_iconv_init_context(struct _citrus_iconv *cv)
41858db2e99Stshiozak {
4195b3d2342Syamt const struct _citrus_iconv_std_shared *is = cv->cv_shared->ci_closure;
42058db2e99Stshiozak struct _citrus_iconv_std_context *sc;
42158db2e99Stshiozak size_t szpssrc, szpsdst, sz;
42258db2e99Stshiozak char *ptr;
42358db2e99Stshiozak
42458db2e99Stshiozak szpssrc = _stdenc_get_state_size(is->is_src_encoding);
42558db2e99Stshiozak szpsdst = _stdenc_get_state_size(is->is_dst_encoding);
42658db2e99Stshiozak
42758db2e99Stshiozak sz = (szpssrc + szpsdst)*2 + sizeof(struct _citrus_iconv_std_context);
42858db2e99Stshiozak sc = malloc(sz);
42958db2e99Stshiozak if (sc == NULL)
43058db2e99Stshiozak return errno;
43158db2e99Stshiozak
43258db2e99Stshiozak ptr = (char *)&sc[1];
43358db2e99Stshiozak if (szpssrc)
43458db2e99Stshiozak init_encoding(&sc->sc_src_encoding, is->is_src_encoding,
43558db2e99Stshiozak ptr, ptr+szpssrc);
43658db2e99Stshiozak else
43758db2e99Stshiozak init_encoding(&sc->sc_src_encoding, is->is_src_encoding,
43858db2e99Stshiozak NULL, NULL);
43958db2e99Stshiozak ptr += szpssrc*2;
44058db2e99Stshiozak if (szpsdst)
44158db2e99Stshiozak init_encoding(&sc->sc_dst_encoding, is->is_dst_encoding,
44258db2e99Stshiozak ptr, ptr+szpsdst);
44358db2e99Stshiozak else
44458db2e99Stshiozak init_encoding(&sc->sc_dst_encoding, is->is_dst_encoding,
44558db2e99Stshiozak NULL, NULL);
44658db2e99Stshiozak
44758db2e99Stshiozak cv->cv_closure = (void *)sc;
44858db2e99Stshiozak
44958db2e99Stshiozak return 0;
45058db2e99Stshiozak }
45158db2e99Stshiozak
45258db2e99Stshiozak static void
_citrus_iconv_std_iconv_uninit_context(struct _citrus_iconv * cv)45358db2e99Stshiozak _citrus_iconv_std_iconv_uninit_context(struct _citrus_iconv *cv)
45458db2e99Stshiozak {
45558db2e99Stshiozak free(cv->cv_closure);
45658db2e99Stshiozak }
45758db2e99Stshiozak
45858db2e99Stshiozak static int
_citrus_iconv_std_iconv_convert(struct _citrus_iconv * __restrict cv,const char * __restrict * __restrict in,size_t * __restrict inbytes,char * __restrict * __restrict out,size_t * __restrict outbytes,u_int32_t flags,size_t * __restrict invalids)45958db2e99Stshiozak _citrus_iconv_std_iconv_convert(struct _citrus_iconv * __restrict cv,
46004e58308Stshiozak const char * __restrict * __restrict in,
46104e58308Stshiozak size_t * __restrict inbytes,
46204e58308Stshiozak char * __restrict * __restrict out,
46304e58308Stshiozak size_t * __restrict outbytes, u_int32_t flags,
46404e58308Stshiozak size_t * __restrict invalids)
46504e58308Stshiozak {
4665b3d2342Syamt const struct _citrus_iconv_std_shared *is = cv->cv_shared->ci_closure;
46758db2e99Stshiozak struct _citrus_iconv_std_context *sc = cv->cv_closure;
46804e58308Stshiozak _index_t idx;
46904e58308Stshiozak _csid_t csid;
4701beef8feStshiozak int ret, state;
47104e58308Stshiozak size_t szrin, szrout;
47204e58308Stshiozak size_t inval;
47304e58308Stshiozak const char *tmpin;
47404e58308Stshiozak
47504e58308Stshiozak inval = 0;
47604e58308Stshiozak if (in==NULL || *in==NULL) {
47704e58308Stshiozak /* special cases */
47804e58308Stshiozak if (out!=NULL && *out!=NULL) {
479cf33db0fStshiozak /* init output state and store the shift sequence */
48058db2e99Stshiozak save_encoding_state(&sc->sc_src_encoding);
48158db2e99Stshiozak save_encoding_state(&sc->sc_dst_encoding);
48204e58308Stshiozak szrout = 0;
48304e58308Stshiozak
48458db2e99Stshiozak ret = put_state_resetx(&sc->sc_dst_encoding,
48504e58308Stshiozak *out, *outbytes,
486f3995f1aStshiozak &szrout);
48704e58308Stshiozak if (ret)
48804e58308Stshiozak goto err;
48904e58308Stshiozak
49004e58308Stshiozak if (szrout == (size_t)-2) {
49104e58308Stshiozak /* too small to store the character */
49204e58308Stshiozak ret = EINVAL;
49304e58308Stshiozak goto err;
49404e58308Stshiozak }
49504e58308Stshiozak *out += szrout;
49604e58308Stshiozak *outbytes -= szrout;
497cf33db0fStshiozak } else
498cf33db0fStshiozak /* otherwise, discard the shift sequence */
499cf33db0fStshiozak init_encoding_state(&sc->sc_dst_encoding);
50058db2e99Stshiozak init_encoding_state(&sc->sc_src_encoding);
501cf33db0fStshiozak *invalids = 0;
50204e58308Stshiozak return 0;
50304e58308Stshiozak }
50404e58308Stshiozak
50504e58308Stshiozak /* normal case */
50604e58308Stshiozak for (;;) {
50779a70a82Stnozaki if (*inbytes==0) {
50879a70a82Stnozaki ret = get_state_desc_gen(&sc->sc_src_encoding, &state);
50974fca02cStnozaki if (state == _STDENC_SDGEN_INITIAL ||
51074fca02cStnozaki state == _STDENC_SDGEN_STABLE)
5119a4bbff8Syamt break;
51279a70a82Stnozaki }
5139a4bbff8Syamt
51404e58308Stshiozak /* save the encoding states for the error recovery */
51558db2e99Stshiozak save_encoding_state(&sc->sc_src_encoding);
51658db2e99Stshiozak save_encoding_state(&sc->sc_dst_encoding);
51704e58308Stshiozak
51804e58308Stshiozak /* mb -> csid/index */
51904e58308Stshiozak tmpin = *in;
52004e58308Stshiozak szrin = szrout = 0;
52158db2e99Stshiozak ret = mbtocsx(&sc->sc_src_encoding, &csid, &idx,
52204e58308Stshiozak &tmpin, *inbytes, &szrin);
52304e58308Stshiozak if (ret)
52404e58308Stshiozak goto err;
52504e58308Stshiozak
52604e58308Stshiozak if (szrin == (size_t)-2) {
52704e58308Stshiozak /* incompleted character */
5281beef8feStshiozak ret = get_state_desc_gen(&sc->sc_src_encoding, &state);
5291beef8feStshiozak if (ret) {
5301beef8feStshiozak ret = EINVAL;
5311beef8feStshiozak goto err;
5321beef8feStshiozak }
5331beef8feStshiozak switch (state) {
5341beef8feStshiozak case _STDENC_SDGEN_INITIAL:
5351beef8feStshiozak case _STDENC_SDGEN_STABLE:
5361beef8feStshiozak /* fetch shift sequences only. */
5371beef8feStshiozak goto next;
5381beef8feStshiozak }
53904e58308Stshiozak ret = EINVAL;
54004e58308Stshiozak goto err;
54104e58308Stshiozak }
54204e58308Stshiozak /* convert the character */
54358db2e99Stshiozak ret = do_conv(is, sc, &csid, &idx);
54404e58308Stshiozak if (ret) {
54504e58308Stshiozak if (ret == E_NO_CORRESPONDING_CHAR) {
54604e58308Stshiozak inval++;
547f3995f1aStshiozak szrout = 0;
54804e58308Stshiozak if ((flags&_CITRUS_ICONV_F_HIDE_INVALID)==0 &&
54904e58308Stshiozak is->is_use_invalid) {
55058db2e99Stshiozak ret = wctombx(&sc->sc_dst_encoding,
55104e58308Stshiozak *out, *outbytes,
55204e58308Stshiozak is->is_invalid,
55304e58308Stshiozak &szrout);
55404e58308Stshiozak if (ret)
55504e58308Stshiozak goto err;
55604e58308Stshiozak }
55704e58308Stshiozak goto next;
55804e58308Stshiozak } else {
55904e58308Stshiozak goto err;
56004e58308Stshiozak }
56104e58308Stshiozak }
56204e58308Stshiozak /* csid/index -> mb */
56358db2e99Stshiozak ret = cstombx(&sc->sc_dst_encoding,
56404e58308Stshiozak *out, *outbytes, csid, idx, &szrout);
56504e58308Stshiozak if (ret)
56604e58308Stshiozak goto err;
56704e58308Stshiozak next:
56804e58308Stshiozak _DIAGASSERT(*inbytes>=szrin && *outbytes>=szrout);
56904e58308Stshiozak *inbytes -= tmpin-*in; /* szrin is insufficient on \0. */
57004e58308Stshiozak *in = tmpin;
57104e58308Stshiozak *outbytes -= szrout;
57204e58308Stshiozak *out += szrout;
57304e58308Stshiozak }
57404e58308Stshiozak *invalids = inval;
57504e58308Stshiozak
57604e58308Stshiozak return 0;
57704e58308Stshiozak
57804e58308Stshiozak err:
57958db2e99Stshiozak restore_encoding_state(&sc->sc_src_encoding);
58058db2e99Stshiozak restore_encoding_state(&sc->sc_dst_encoding);
58104e58308Stshiozak err_norestore:
58204e58308Stshiozak *invalids = inval;
58304e58308Stshiozak
58404e58308Stshiozak return ret;
58504e58308Stshiozak }
586