xref: /minix3/lib/libc/citrus/modules/citrus_iconv_std.c (revision f14fb602092e015ff630df58e17c2a9cd57d29b3)
1*f14fb602SLionel Sambuc /*	$NetBSD: citrus_iconv_std.c,v 1.16 2012/02/12 13:51:29 wiz Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras  * Copyright (c)2003 Citrus Project,
52fe8fb19SBen Gras  * All rights reserved.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
82fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
92fe8fb19SBen Gras  * are met:
102fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
112fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
122fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
132fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
142fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
152fe8fb19SBen Gras  *
162fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172fe8fb19SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182fe8fb19SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192fe8fb19SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202fe8fb19SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212fe8fb19SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222fe8fb19SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232fe8fb19SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242fe8fb19SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252fe8fb19SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262fe8fb19SBen Gras  * SUCH DAMAGE.
272fe8fb19SBen Gras  */
282fe8fb19SBen Gras 
292fe8fb19SBen Gras #include <sys/cdefs.h>
302fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
31*f14fb602SLionel Sambuc __RCSID("$NetBSD: citrus_iconv_std.c,v 1.16 2012/02/12 13:51:29 wiz Exp $");
322fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
332fe8fb19SBen Gras 
342fe8fb19SBen Gras #include <assert.h>
352fe8fb19SBen Gras #include <errno.h>
362fe8fb19SBen Gras #include <limits.h>
372fe8fb19SBen Gras #include <stdio.h>
382fe8fb19SBen Gras #include <stdlib.h>
392fe8fb19SBen Gras #include <string.h>
402fe8fb19SBen Gras #include <machine/endian.h>
412fe8fb19SBen Gras #include <sys/queue.h>
422fe8fb19SBen Gras 
432fe8fb19SBen Gras #include "citrus_namespace.h"
442fe8fb19SBen Gras #include "citrus_types.h"
452fe8fb19SBen Gras #include "citrus_module.h"
462fe8fb19SBen Gras #include "citrus_region.h"
472fe8fb19SBen Gras #include "citrus_mmap.h"
482fe8fb19SBen Gras #include "citrus_hash.h"
492fe8fb19SBen Gras #include "citrus_iconv.h"
502fe8fb19SBen Gras #include "citrus_stdenc.h"
512fe8fb19SBen Gras #include "citrus_mapper.h"
522fe8fb19SBen Gras #include "citrus_csmapper.h"
532fe8fb19SBen Gras #include "citrus_memstream.h"
542fe8fb19SBen Gras #include "citrus_iconv_std.h"
552fe8fb19SBen Gras #include "citrus_esdb.h"
562fe8fb19SBen Gras 
572fe8fb19SBen Gras /* ---------------------------------------------------------------------- */
582fe8fb19SBen Gras 
592fe8fb19SBen Gras _CITRUS_ICONV_DECLS(iconv_std);
602fe8fb19SBen Gras _CITRUS_ICONV_DEF_OPS(iconv_std);
612fe8fb19SBen Gras 
622fe8fb19SBen Gras 
632fe8fb19SBen Gras /* ---------------------------------------------------------------------- */
642fe8fb19SBen Gras 
652fe8fb19SBen Gras int
_citrus_iconv_std_iconv_getops(struct _citrus_iconv_ops * ops,size_t lenops,u_int32_t expected_version)662fe8fb19SBen Gras _citrus_iconv_std_iconv_getops(struct _citrus_iconv_ops *ops, size_t lenops,
672fe8fb19SBen Gras 			       u_int32_t expected_version)
682fe8fb19SBen Gras {
692fe8fb19SBen Gras 	if (expected_version<_CITRUS_ICONV_ABI_VERSION || lenops<sizeof(*ops))
702fe8fb19SBen Gras 		return (EINVAL);
712fe8fb19SBen Gras 
722fe8fb19SBen Gras 	memcpy(ops, &_citrus_iconv_std_iconv_ops,
732fe8fb19SBen Gras 	       sizeof(_citrus_iconv_std_iconv_ops));
742fe8fb19SBen Gras 
752fe8fb19SBen Gras 	return (0);
762fe8fb19SBen Gras }
772fe8fb19SBen Gras 
782fe8fb19SBen Gras /* ---------------------------------------------------------------------- */
792fe8fb19SBen Gras 
802fe8fb19SBen Gras /*
812fe8fb19SBen Gras  * convenience routines for stdenc.
822fe8fb19SBen Gras  */
832fe8fb19SBen Gras static __inline void
save_encoding_state(struct _citrus_iconv_std_encoding * se)842fe8fb19SBen Gras save_encoding_state(struct _citrus_iconv_std_encoding *se)
852fe8fb19SBen Gras {
862fe8fb19SBen Gras 	if (se->se_ps)
872fe8fb19SBen Gras 		memcpy(se->se_pssaved, se->se_ps,
882fe8fb19SBen Gras 		       _stdenc_get_state_size(se->se_handle));
892fe8fb19SBen Gras }
902fe8fb19SBen Gras 
912fe8fb19SBen Gras static __inline void
restore_encoding_state(struct _citrus_iconv_std_encoding * se)922fe8fb19SBen Gras restore_encoding_state(struct _citrus_iconv_std_encoding *se)
932fe8fb19SBen Gras {
942fe8fb19SBen Gras 	if (se->se_ps)
952fe8fb19SBen Gras 		memcpy(se->se_ps, se->se_pssaved,
962fe8fb19SBen Gras 		       _stdenc_get_state_size(se->se_handle));
972fe8fb19SBen Gras }
982fe8fb19SBen Gras 
992fe8fb19SBen Gras static __inline void
init_encoding_state(struct _citrus_iconv_std_encoding * se)1002fe8fb19SBen Gras init_encoding_state(struct _citrus_iconv_std_encoding *se)
1012fe8fb19SBen Gras {
1022fe8fb19SBen Gras 	if (se->se_ps)
1032fe8fb19SBen Gras 		_stdenc_init_state(se->se_handle, se->se_ps);
1042fe8fb19SBen Gras }
1052fe8fb19SBen Gras 
1062fe8fb19SBen Gras 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)1072fe8fb19SBen Gras mbtocsx(struct _citrus_iconv_std_encoding *se,
1082fe8fb19SBen Gras 	_csid_t *csid, _index_t *idx, const char **s, size_t n,
1092fe8fb19SBen Gras 	size_t *nresult)
1102fe8fb19SBen Gras {
1112fe8fb19SBen Gras 	return _stdenc_mbtocs(se->se_handle, csid, idx, s, n, se->se_ps,
1122fe8fb19SBen Gras 			      nresult);
1132fe8fb19SBen Gras }
1142fe8fb19SBen Gras 
1152fe8fb19SBen Gras static __inline int
cstombx(struct _citrus_iconv_std_encoding * se,char * s,size_t n,_csid_t csid,_index_t idx,size_t * nresult)1162fe8fb19SBen Gras cstombx(struct _citrus_iconv_std_encoding *se,
1172fe8fb19SBen Gras 	char *s, size_t n, _csid_t csid, _index_t idx, size_t *nresult)
1182fe8fb19SBen Gras {
1192fe8fb19SBen Gras 	return _stdenc_cstomb(se->se_handle, s, n, csid, idx, se->se_ps,
1202fe8fb19SBen Gras 			      nresult);
1212fe8fb19SBen Gras }
1222fe8fb19SBen Gras 
1232fe8fb19SBen Gras static __inline int
wctombx(struct _citrus_iconv_std_encoding * se,char * s,size_t n,_wc_t wc,size_t * nresult)1242fe8fb19SBen Gras wctombx(struct _citrus_iconv_std_encoding *se,
1252fe8fb19SBen Gras 	char *s, size_t n, _wc_t wc, size_t *nresult)
1262fe8fb19SBen Gras {
1272fe8fb19SBen Gras 	return _stdenc_wctomb(se->se_handle, s, n, wc, se->se_ps, nresult);
1282fe8fb19SBen Gras }
1292fe8fb19SBen Gras 
1302fe8fb19SBen Gras static __inline int
put_state_resetx(struct _citrus_iconv_std_encoding * se,char * s,size_t n,size_t * nresult)1312fe8fb19SBen Gras put_state_resetx(struct _citrus_iconv_std_encoding *se,
1322fe8fb19SBen Gras 		 char *s, size_t n, size_t *nresult)
1332fe8fb19SBen Gras {
1342fe8fb19SBen Gras 	return _stdenc_put_state_reset(se->se_handle, s, n, se->se_ps, nresult);
1352fe8fb19SBen Gras }
1362fe8fb19SBen Gras 
1372fe8fb19SBen Gras static __inline int
get_state_desc_gen(struct _citrus_iconv_std_encoding * se,int * rstate)1382fe8fb19SBen Gras get_state_desc_gen(struct _citrus_iconv_std_encoding *se, int *rstate)
1392fe8fb19SBen Gras {
1402fe8fb19SBen Gras 	int ret;
1412fe8fb19SBen Gras 	struct _stdenc_state_desc ssd;
1422fe8fb19SBen Gras 
1432fe8fb19SBen Gras 	ret = _stdenc_get_state_desc(se->se_handle, se->se_ps,
1442fe8fb19SBen Gras 				     _STDENC_SDID_GENERIC, &ssd);
1452fe8fb19SBen Gras 	if (!ret)
1462fe8fb19SBen Gras 		*rstate = ssd.u.generic.state;
1472fe8fb19SBen Gras 
1482fe8fb19SBen Gras 	return ret;
1492fe8fb19SBen Gras }
1502fe8fb19SBen Gras 
1512fe8fb19SBen Gras /*
1522fe8fb19SBen Gras  * init encoding context
1532fe8fb19SBen Gras  */
1542fe8fb19SBen Gras static int
init_encoding(struct _citrus_iconv_std_encoding * se,struct _stdenc * cs,void * ps1,void * ps2)1552fe8fb19SBen Gras init_encoding(struct _citrus_iconv_std_encoding *se, struct _stdenc *cs,
1562fe8fb19SBen Gras 	      void *ps1, void *ps2)
1572fe8fb19SBen Gras {
1582fe8fb19SBen Gras 	int ret = -1;
1592fe8fb19SBen Gras 
1602fe8fb19SBen Gras 	se->se_handle = cs;
1612fe8fb19SBen Gras 	se->se_ps = ps1;
1622fe8fb19SBen Gras 	se->se_pssaved = ps2;
1632fe8fb19SBen Gras 
1642fe8fb19SBen Gras 	if (se->se_ps)
1652fe8fb19SBen Gras 		ret = _stdenc_init_state(cs, se->se_ps);
1662fe8fb19SBen Gras 	if (!ret && se->se_pssaved)
1672fe8fb19SBen Gras 		ret = _stdenc_init_state(cs, se->se_pssaved);
1682fe8fb19SBen Gras 
1692fe8fb19SBen Gras 	return ret;
1702fe8fb19SBen Gras }
1712fe8fb19SBen Gras 
1722fe8fb19SBen Gras static int
open_csmapper(struct _csmapper ** rcm,const char * src,const char * dst,unsigned long * rnorm)1732fe8fb19SBen Gras open_csmapper(struct _csmapper **rcm, const char *src, const char *dst,
1742fe8fb19SBen Gras 	      unsigned long *rnorm)
1752fe8fb19SBen Gras {
1762fe8fb19SBen Gras 	int ret;
1772fe8fb19SBen Gras 	struct _csmapper *cm;
1782fe8fb19SBen Gras 
1792fe8fb19SBen Gras 	ret = _csmapper_open(&cm, src, dst, 0, rnorm);
1802fe8fb19SBen Gras 	if (ret)
1812fe8fb19SBen Gras 		return ret;
1822fe8fb19SBen Gras 	if (_csmapper_get_src_max(cm) != 1 || _csmapper_get_dst_max(cm) != 1 ||
1832fe8fb19SBen Gras 	    _csmapper_get_state_size(cm) != 0) {
1842fe8fb19SBen Gras 		_csmapper_close(cm);
1852fe8fb19SBen Gras 		return EINVAL;
1862fe8fb19SBen Gras 	}
1872fe8fb19SBen Gras 
1882fe8fb19SBen Gras 	*rcm = cm;
1892fe8fb19SBen Gras 
1902fe8fb19SBen Gras 	return 0;
1912fe8fb19SBen Gras }
1922fe8fb19SBen Gras 
1932fe8fb19SBen Gras static void
close_dsts(struct _citrus_iconv_std_dst_list * dl)1942fe8fb19SBen Gras close_dsts(struct _citrus_iconv_std_dst_list *dl)
1952fe8fb19SBen Gras {
1962fe8fb19SBen Gras 	struct _citrus_iconv_std_dst *sd;
1972fe8fb19SBen Gras 
1982fe8fb19SBen Gras 	while ((sd=TAILQ_FIRST(dl)) != NULL) {
1992fe8fb19SBen Gras 		TAILQ_REMOVE(dl, sd, sd_entry);
2002fe8fb19SBen Gras 		_csmapper_close(sd->sd_mapper);
2012fe8fb19SBen Gras 		free(sd);
2022fe8fb19SBen Gras 	}
2032fe8fb19SBen Gras }
2042fe8fb19SBen Gras 
2052fe8fb19SBen Gras static int
open_dsts(struct _citrus_iconv_std_dst_list * dl,const struct _esdb_charset * ec,const struct _esdb * dbdst)2062fe8fb19SBen Gras open_dsts(struct _citrus_iconv_std_dst_list *dl,
2072fe8fb19SBen Gras 	  const struct _esdb_charset *ec, const struct _esdb *dbdst)
2082fe8fb19SBen Gras {
2092fe8fb19SBen Gras 	int i, ret;
2102fe8fb19SBen Gras 	struct _citrus_iconv_std_dst *sd, *sdtmp;
2112fe8fb19SBen Gras 	unsigned long norm;
2122fe8fb19SBen Gras 
2132fe8fb19SBen Gras 	sd = malloc(sizeof(*sd));
2142fe8fb19SBen Gras 	if (sd == NULL)
2152fe8fb19SBen Gras 		return errno;
2162fe8fb19SBen Gras 
2172fe8fb19SBen Gras 	for (i=0; i<dbdst->db_num_charsets; i++) {
2182fe8fb19SBen Gras 		ret = open_csmapper(&sd->sd_mapper, ec->ec_csname,
2192fe8fb19SBen Gras 				    dbdst->db_charsets[i].ec_csname, &norm);
2202fe8fb19SBen Gras 		if (ret == 0) {
2212fe8fb19SBen Gras 			sd->sd_csid = dbdst->db_charsets[i].ec_csid;
2222fe8fb19SBen Gras 			sd->sd_norm = norm;
2232fe8fb19SBen Gras 			/* insert this mapper by sorted order. */
2242fe8fb19SBen Gras 			TAILQ_FOREACH(sdtmp, dl, sd_entry) {
2252fe8fb19SBen Gras 				if (sdtmp->sd_norm > norm) {
2262fe8fb19SBen Gras 					TAILQ_INSERT_BEFORE(sdtmp, sd,
2272fe8fb19SBen Gras 							    sd_entry);
2282fe8fb19SBen Gras 					sd = NULL;
2292fe8fb19SBen Gras 					break;
2302fe8fb19SBen Gras 				}
2312fe8fb19SBen Gras 			}
2322fe8fb19SBen Gras 			if (sd)
2332fe8fb19SBen Gras 				TAILQ_INSERT_TAIL(dl, sd, sd_entry);
2342fe8fb19SBen Gras 			sd = malloc(sizeof(*sd));
2352fe8fb19SBen Gras 			if (sd == NULL) {
2362fe8fb19SBen Gras 				ret = errno;
2372fe8fb19SBen Gras 				close_dsts(dl);
2382fe8fb19SBen Gras 				return ret;
2392fe8fb19SBen Gras 			}
2402fe8fb19SBen Gras 		} else if (ret != ENOENT) {
2412fe8fb19SBen Gras 			close_dsts(dl);
2422fe8fb19SBen Gras 			free(sd);
2432fe8fb19SBen Gras 			return ret;
2442fe8fb19SBen Gras 		}
2452fe8fb19SBen Gras 	}
2462fe8fb19SBen Gras 	free(sd);
2472fe8fb19SBen Gras 	return 0;
2482fe8fb19SBen Gras }
2492fe8fb19SBen Gras 
2502fe8fb19SBen Gras static void
close_srcs(struct _citrus_iconv_std_src_list * sl)2512fe8fb19SBen Gras close_srcs(struct _citrus_iconv_std_src_list *sl)
2522fe8fb19SBen Gras {
2532fe8fb19SBen Gras 	struct _citrus_iconv_std_src *ss;
2542fe8fb19SBen Gras 
2552fe8fb19SBen Gras 	while ((ss=TAILQ_FIRST(sl)) != NULL) {
2562fe8fb19SBen Gras 		TAILQ_REMOVE(sl, ss, ss_entry);
2572fe8fb19SBen Gras 		close_dsts(&ss->ss_dsts);
2582fe8fb19SBen Gras 		free(ss);
2592fe8fb19SBen Gras 	}
2602fe8fb19SBen Gras }
2612fe8fb19SBen Gras 
2622fe8fb19SBen Gras static int
open_srcs(struct _citrus_iconv_std_src_list * sl,const struct _esdb * dbsrc,const struct _esdb * dbdst)2632fe8fb19SBen Gras open_srcs(struct _citrus_iconv_std_src_list *sl,
2642fe8fb19SBen Gras 	  const struct _esdb *dbsrc, const struct _esdb *dbdst)
2652fe8fb19SBen Gras {
2662fe8fb19SBen Gras 	int i, ret, count = 0;
2672fe8fb19SBen Gras 	struct _citrus_iconv_std_src *ss;
2682fe8fb19SBen Gras 
2692fe8fb19SBen Gras 	ss = malloc(sizeof(*ss));
2702fe8fb19SBen Gras 	if (ss == NULL)
2712fe8fb19SBen Gras 		return errno;
2722fe8fb19SBen Gras 
2732fe8fb19SBen Gras 	TAILQ_INIT(&ss->ss_dsts);
2742fe8fb19SBen Gras 
2752fe8fb19SBen Gras 	for (i=0; i<dbsrc->db_num_charsets; i++) {
2762fe8fb19SBen Gras 		ret = open_dsts(&ss->ss_dsts, &dbsrc->db_charsets[i], dbdst);
2772fe8fb19SBen Gras 		if (ret)
2782fe8fb19SBen Gras 			goto err;
2792fe8fb19SBen Gras 		if (!TAILQ_EMPTY(&ss->ss_dsts)) {
2802fe8fb19SBen Gras 			ss->ss_csid = dbsrc->db_charsets[i].ec_csid;
2812fe8fb19SBen Gras 			TAILQ_INSERT_TAIL(sl, ss, ss_entry);
2822fe8fb19SBen Gras 			ss = malloc(sizeof(*ss));
2832fe8fb19SBen Gras 			if (ss == NULL) {
2842fe8fb19SBen Gras 				ret = errno;
2852fe8fb19SBen Gras 				goto err;
2862fe8fb19SBen Gras 			}
2872fe8fb19SBen Gras 			count++;
2882fe8fb19SBen Gras 			TAILQ_INIT(&ss->ss_dsts);
2892fe8fb19SBen Gras 		}
2902fe8fb19SBen Gras 	}
2912fe8fb19SBen Gras 	free(ss);
2922fe8fb19SBen Gras 
2932fe8fb19SBen Gras 	return count ? 0 : ENOENT;
2942fe8fb19SBen Gras 
2952fe8fb19SBen Gras err:
2962fe8fb19SBen Gras 	free(ss);
2972fe8fb19SBen Gras 	close_srcs(sl);
2982fe8fb19SBen Gras 	return ret;
2992fe8fb19SBen Gras }
3002fe8fb19SBen Gras 
3012fe8fb19SBen Gras /* do convert a character */
3022fe8fb19SBen Gras #define E_NO_CORRESPONDING_CHAR ENOENT /* XXX */
3032fe8fb19SBen Gras static int
3042fe8fb19SBen Gras /*ARGSUSED*/
do_conv(const struct _citrus_iconv_std_shared * is,struct _citrus_iconv_std_context * sc,_csid_t * csid,_index_t * idx)3052fe8fb19SBen Gras do_conv(const struct _citrus_iconv_std_shared *is,
3062fe8fb19SBen Gras 	struct _citrus_iconv_std_context *sc, _csid_t *csid, _index_t *idx)
3072fe8fb19SBen Gras {
3082fe8fb19SBen Gras 	_index_t tmpidx;
3092fe8fb19SBen Gras 	int ret;
3102fe8fb19SBen Gras 	struct _citrus_iconv_std_src *ss;
3112fe8fb19SBen Gras 	struct _citrus_iconv_std_dst *sd;
3122fe8fb19SBen Gras 
3132fe8fb19SBen Gras 	TAILQ_FOREACH(ss, &is->is_srcs, ss_entry) {
3142fe8fb19SBen Gras 		if (ss->ss_csid == *csid) {
3152fe8fb19SBen Gras 			TAILQ_FOREACH(sd, &ss->ss_dsts, sd_entry) {
3162fe8fb19SBen Gras 				ret = _csmapper_convert(sd->sd_mapper,
3172fe8fb19SBen Gras 							&tmpidx, *idx, NULL);
3182fe8fb19SBen Gras 				switch (ret) {
3192fe8fb19SBen Gras 				case _MAPPER_CONVERT_SUCCESS:
3202fe8fb19SBen Gras 					*csid = sd->sd_csid;
3212fe8fb19SBen Gras 					*idx = tmpidx;
3222fe8fb19SBen Gras 					return 0;
3232fe8fb19SBen Gras 				case _MAPPER_CONVERT_NONIDENTICAL:
3242fe8fb19SBen Gras 					break;
3252fe8fb19SBen Gras 				case _MAPPER_CONVERT_SRC_MORE:
3262fe8fb19SBen Gras 					/*FALLTHROUGH*/
3272fe8fb19SBen Gras 				case _MAPPER_CONVERT_DST_MORE:
3282fe8fb19SBen Gras 					/*FALLTHROUGH*/
3292fe8fb19SBen Gras 				case _MAPPER_CONVERT_FATAL:
3302fe8fb19SBen Gras 					return EINVAL;
3312fe8fb19SBen Gras 				case _MAPPER_CONVERT_ILSEQ:
3322fe8fb19SBen Gras 					return EILSEQ;
3332fe8fb19SBen Gras 				}
3342fe8fb19SBen Gras 			}
3352fe8fb19SBen Gras 			break;
3362fe8fb19SBen Gras 		}
3372fe8fb19SBen Gras 	}
3382fe8fb19SBen Gras 
3392fe8fb19SBen Gras 	return E_NO_CORRESPONDING_CHAR;
3402fe8fb19SBen Gras }
3412fe8fb19SBen Gras /* ---------------------------------------------------------------------- */
3422fe8fb19SBen Gras 
3432fe8fb19SBen Gras static int
3442fe8fb19SBen Gras /*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)3452fe8fb19SBen Gras _citrus_iconv_std_iconv_init_shared(struct _citrus_iconv_shared *ci,
3462fe8fb19SBen Gras 				    const char * __restrict curdir,
3472fe8fb19SBen Gras 				    const char * __restrict src,
3482fe8fb19SBen Gras 				    const char * __restrict dst,
3492fe8fb19SBen Gras 				    const void * __restrict var, size_t lenvar)
3502fe8fb19SBen Gras {
3512fe8fb19SBen Gras 	int ret;
3522fe8fb19SBen Gras 	struct _citrus_iconv_std_shared *is;
3532fe8fb19SBen Gras 	struct _citrus_esdb esdbsrc, esdbdst;
3542fe8fb19SBen Gras 
3552fe8fb19SBen Gras 	is = malloc(sizeof(*is));
3562fe8fb19SBen Gras 	if (is==NULL) {
3572fe8fb19SBen Gras 		ret = errno;
3582fe8fb19SBen Gras 		goto err0;
3592fe8fb19SBen Gras 	}
3602fe8fb19SBen Gras 	ret = _citrus_esdb_open(&esdbsrc, src);
3612fe8fb19SBen Gras 	if (ret)
3622fe8fb19SBen Gras 		goto err1;
3632fe8fb19SBen Gras 	ret = _citrus_esdb_open(&esdbdst, dst);
3642fe8fb19SBen Gras 	if (ret)
3652fe8fb19SBen Gras 		goto err2;
3662fe8fb19SBen Gras 	ret = _stdenc_open(&is->is_src_encoding, esdbsrc.db_encname,
3672fe8fb19SBen Gras 			   esdbsrc.db_variable, esdbsrc.db_len_variable);
3682fe8fb19SBen Gras 	if (ret)
3692fe8fb19SBen Gras 		goto err3;
3702fe8fb19SBen Gras 	ret = _stdenc_open(&is->is_dst_encoding, esdbdst.db_encname,
3712fe8fb19SBen Gras 			   esdbdst.db_variable, esdbdst.db_len_variable);
3722fe8fb19SBen Gras 	if (ret)
3732fe8fb19SBen Gras 		goto err4;
3742fe8fb19SBen Gras 	is->is_use_invalid = esdbdst.db_use_invalid;
3752fe8fb19SBen Gras 	is->is_invalid = esdbdst.db_invalid;
3762fe8fb19SBen Gras 
3772fe8fb19SBen Gras 	TAILQ_INIT(&is->is_srcs);
3782fe8fb19SBen Gras 	ret = open_srcs(&is->is_srcs, &esdbsrc, &esdbdst);
3792fe8fb19SBen Gras 	if (ret)
3802fe8fb19SBen Gras 		goto err5;
3812fe8fb19SBen Gras 
3822fe8fb19SBen Gras 	_esdb_close(&esdbsrc);
3832fe8fb19SBen Gras 	_esdb_close(&esdbdst);
3842fe8fb19SBen Gras 	ci->ci_closure = is;
3852fe8fb19SBen Gras 
3862fe8fb19SBen Gras 	return 0;
3872fe8fb19SBen Gras 
3882fe8fb19SBen Gras err5:
3892fe8fb19SBen Gras 	_stdenc_close(is->is_dst_encoding);
3902fe8fb19SBen Gras err4:
3912fe8fb19SBen Gras 	_stdenc_close(is->is_src_encoding);
3922fe8fb19SBen Gras err3:
3932fe8fb19SBen Gras 	_esdb_close(&esdbdst);
3942fe8fb19SBen Gras err2:
3952fe8fb19SBen Gras 	_esdb_close(&esdbsrc);
3962fe8fb19SBen Gras err1:
3972fe8fb19SBen Gras 	free(is);
3982fe8fb19SBen Gras err0:
3992fe8fb19SBen Gras 	return ret;
4002fe8fb19SBen Gras }
4012fe8fb19SBen Gras 
4022fe8fb19SBen Gras static void
_citrus_iconv_std_iconv_uninit_shared(struct _citrus_iconv_shared * ci)4032fe8fb19SBen Gras _citrus_iconv_std_iconv_uninit_shared(struct _citrus_iconv_shared *ci)
4042fe8fb19SBen Gras {
4052fe8fb19SBen Gras 	struct _citrus_iconv_std_shared *is = ci->ci_closure;
4062fe8fb19SBen Gras 
4072fe8fb19SBen Gras 	if (is == NULL)
4082fe8fb19SBen Gras 		return;
4092fe8fb19SBen Gras 
4102fe8fb19SBen Gras 	_stdenc_close(is->is_src_encoding);
4112fe8fb19SBen Gras 	_stdenc_close(is->is_dst_encoding);
4122fe8fb19SBen Gras 	close_srcs(&is->is_srcs);
4132fe8fb19SBen Gras 	free(is);
4142fe8fb19SBen Gras }
4152fe8fb19SBen Gras 
4162fe8fb19SBen Gras static int
_citrus_iconv_std_iconv_init_context(struct _citrus_iconv * cv)4172fe8fb19SBen Gras _citrus_iconv_std_iconv_init_context(struct _citrus_iconv *cv)
4182fe8fb19SBen Gras {
4192fe8fb19SBen Gras 	const struct _citrus_iconv_std_shared *is = cv->cv_shared->ci_closure;
4202fe8fb19SBen Gras 	struct _citrus_iconv_std_context *sc;
4212fe8fb19SBen Gras 	size_t szpssrc, szpsdst, sz;
4222fe8fb19SBen Gras 	char *ptr;
4232fe8fb19SBen Gras 
4242fe8fb19SBen Gras 	szpssrc = _stdenc_get_state_size(is->is_src_encoding);
4252fe8fb19SBen Gras 	szpsdst = _stdenc_get_state_size(is->is_dst_encoding);
4262fe8fb19SBen Gras 
4272fe8fb19SBen Gras 	sz = (szpssrc + szpsdst)*2 + sizeof(struct _citrus_iconv_std_context);
4282fe8fb19SBen Gras 	sc = malloc(sz);
4292fe8fb19SBen Gras 	if (sc == NULL)
4302fe8fb19SBen Gras 		return errno;
4312fe8fb19SBen Gras 
4322fe8fb19SBen Gras 	ptr = (char *)&sc[1];
4332fe8fb19SBen Gras 	if (szpssrc)
4342fe8fb19SBen Gras 		init_encoding(&sc->sc_src_encoding, is->is_src_encoding,
4352fe8fb19SBen Gras 			      ptr, ptr+szpssrc);
4362fe8fb19SBen Gras 	else
4372fe8fb19SBen Gras 		init_encoding(&sc->sc_src_encoding, is->is_src_encoding,
4382fe8fb19SBen Gras 			      NULL, NULL);
4392fe8fb19SBen Gras 	ptr += szpssrc*2;
4402fe8fb19SBen Gras 	if (szpsdst)
4412fe8fb19SBen Gras 		init_encoding(&sc->sc_dst_encoding, is->is_dst_encoding,
4422fe8fb19SBen Gras 			      ptr, ptr+szpsdst);
4432fe8fb19SBen Gras 	else
4442fe8fb19SBen Gras 		init_encoding(&sc->sc_dst_encoding, is->is_dst_encoding,
4452fe8fb19SBen Gras 			      NULL, NULL);
4462fe8fb19SBen Gras 
4472fe8fb19SBen Gras 	cv->cv_closure = (void *)sc;
4482fe8fb19SBen Gras 
4492fe8fb19SBen Gras 	return 0;
4502fe8fb19SBen Gras }
4512fe8fb19SBen Gras 
4522fe8fb19SBen Gras static void
_citrus_iconv_std_iconv_uninit_context(struct _citrus_iconv * cv)4532fe8fb19SBen Gras _citrus_iconv_std_iconv_uninit_context(struct _citrus_iconv *cv)
4542fe8fb19SBen Gras {
4552fe8fb19SBen Gras 	free(cv->cv_closure);
4562fe8fb19SBen Gras }
4572fe8fb19SBen Gras 
4582fe8fb19SBen Gras 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)4592fe8fb19SBen Gras _citrus_iconv_std_iconv_convert(struct _citrus_iconv * __restrict cv,
4602fe8fb19SBen Gras 				const char * __restrict * __restrict in,
4612fe8fb19SBen Gras 				size_t * __restrict inbytes,
4622fe8fb19SBen Gras 				char * __restrict * __restrict out,
4632fe8fb19SBen Gras 				size_t * __restrict outbytes, u_int32_t flags,
4642fe8fb19SBen Gras 				size_t * __restrict invalids)
4652fe8fb19SBen Gras {
4662fe8fb19SBen Gras 	const struct _citrus_iconv_std_shared *is = cv->cv_shared->ci_closure;
4672fe8fb19SBen Gras 	struct _citrus_iconv_std_context *sc = cv->cv_closure;
4682fe8fb19SBen Gras 	_index_t idx;
4692fe8fb19SBen Gras 	_csid_t csid;
4702fe8fb19SBen Gras 	int ret, state;
4712fe8fb19SBen Gras 	size_t szrin, szrout;
4722fe8fb19SBen Gras 	size_t inval;
4732fe8fb19SBen Gras 	const char *tmpin;
4742fe8fb19SBen Gras 
4752fe8fb19SBen Gras 	inval = 0;
4762fe8fb19SBen Gras 	if (in==NULL || *in==NULL) {
4772fe8fb19SBen Gras 		/* special cases */
4782fe8fb19SBen Gras 		if (out!=NULL && *out!=NULL) {
4792fe8fb19SBen Gras 			/* init output state and store the shift sequence */
4802fe8fb19SBen Gras 			save_encoding_state(&sc->sc_src_encoding);
4812fe8fb19SBen Gras 			save_encoding_state(&sc->sc_dst_encoding);
4822fe8fb19SBen Gras 			szrout = 0;
4832fe8fb19SBen Gras 
4842fe8fb19SBen Gras 			ret = put_state_resetx(&sc->sc_dst_encoding,
4852fe8fb19SBen Gras 					       *out, *outbytes,
4862fe8fb19SBen Gras 					       &szrout);
4872fe8fb19SBen Gras 			if (ret)
4882fe8fb19SBen Gras 				goto err;
4892fe8fb19SBen Gras 
4902fe8fb19SBen Gras 			if (szrout == (size_t)-2) {
4912fe8fb19SBen Gras 				/* too small to store the character */
4922fe8fb19SBen Gras 				ret = EINVAL;
4932fe8fb19SBen Gras 				goto err;
4942fe8fb19SBen Gras 			}
4952fe8fb19SBen Gras 			*out += szrout;
4962fe8fb19SBen Gras 			*outbytes -= szrout;
4972fe8fb19SBen Gras 		} else
4982fe8fb19SBen Gras 			/* otherwise, discard the shift sequence */
4992fe8fb19SBen Gras 			init_encoding_state(&sc->sc_dst_encoding);
5002fe8fb19SBen Gras 		init_encoding_state(&sc->sc_src_encoding);
5012fe8fb19SBen Gras 		*invalids = 0;
5022fe8fb19SBen Gras 		return 0;
5032fe8fb19SBen Gras 	}
5042fe8fb19SBen Gras 
5052fe8fb19SBen Gras 	/* normal case */
5062fe8fb19SBen Gras 	for (;;) {
5072fe8fb19SBen Gras 		if (*inbytes==0) {
5082fe8fb19SBen Gras 			ret = get_state_desc_gen(&sc->sc_src_encoding, &state);
5092fe8fb19SBen Gras 			if (state == _STDENC_SDGEN_INITIAL ||
5102fe8fb19SBen Gras 			    state == _STDENC_SDGEN_STABLE)
5112fe8fb19SBen Gras 				break;
5122fe8fb19SBen Gras 		}
5132fe8fb19SBen Gras 
5142fe8fb19SBen Gras 		/* save the encoding states for the error recovery */
5152fe8fb19SBen Gras 		save_encoding_state(&sc->sc_src_encoding);
5162fe8fb19SBen Gras 		save_encoding_state(&sc->sc_dst_encoding);
5172fe8fb19SBen Gras 
5182fe8fb19SBen Gras 		/* mb -> csid/index */
5192fe8fb19SBen Gras 		tmpin = *in;
5202fe8fb19SBen Gras 		szrin = szrout = 0;
5212fe8fb19SBen Gras 		ret = mbtocsx(&sc->sc_src_encoding, &csid, &idx,
5222fe8fb19SBen Gras 			      &tmpin, *inbytes, &szrin);
5232fe8fb19SBen Gras 		if (ret)
5242fe8fb19SBen Gras 			goto err;
5252fe8fb19SBen Gras 
5262fe8fb19SBen Gras 		if (szrin == (size_t)-2) {
5272fe8fb19SBen Gras 			/* incompleted character */
5282fe8fb19SBen Gras 			ret = get_state_desc_gen(&sc->sc_src_encoding, &state);
5292fe8fb19SBen Gras 			if (ret) {
5302fe8fb19SBen Gras 				ret = EINVAL;
5312fe8fb19SBen Gras 				goto err;
5322fe8fb19SBen Gras 			}
5332fe8fb19SBen Gras 			switch (state) {
5342fe8fb19SBen Gras 			case _STDENC_SDGEN_INITIAL:
5352fe8fb19SBen Gras 			case _STDENC_SDGEN_STABLE:
5362fe8fb19SBen Gras 				/* fetch shift sequences only. */
5372fe8fb19SBen Gras 				goto next;
5382fe8fb19SBen Gras 			}
5392fe8fb19SBen Gras 			ret = EINVAL;
5402fe8fb19SBen Gras 			goto err;
5412fe8fb19SBen Gras 		}
5422fe8fb19SBen Gras 		/* convert the character */
5432fe8fb19SBen Gras 		ret = do_conv(is, sc, &csid, &idx);
5442fe8fb19SBen Gras 		if (ret) {
5452fe8fb19SBen Gras 			if (ret == E_NO_CORRESPONDING_CHAR) {
5462fe8fb19SBen Gras 				inval++;
5472fe8fb19SBen Gras 				szrout = 0;
5482fe8fb19SBen Gras 				if ((flags&_CITRUS_ICONV_F_HIDE_INVALID)==0 &&
5492fe8fb19SBen Gras 				    is->is_use_invalid) {
5502fe8fb19SBen Gras 					ret = wctombx(&sc->sc_dst_encoding,
5512fe8fb19SBen Gras 						      *out, *outbytes,
5522fe8fb19SBen Gras 						      is->is_invalid,
5532fe8fb19SBen Gras 						      &szrout);
5542fe8fb19SBen Gras 					if (ret)
5552fe8fb19SBen Gras 						goto err;
5562fe8fb19SBen Gras 				}
5572fe8fb19SBen Gras 				goto next;
5582fe8fb19SBen Gras 			} else {
5592fe8fb19SBen Gras 				goto err;
5602fe8fb19SBen Gras 			}
5612fe8fb19SBen Gras 		}
5622fe8fb19SBen Gras 		/* csid/index -> mb */
5632fe8fb19SBen Gras 		ret = cstombx(&sc->sc_dst_encoding,
5642fe8fb19SBen Gras 			      *out, *outbytes, csid, idx, &szrout);
5652fe8fb19SBen Gras 		if (ret)
5662fe8fb19SBen Gras 			goto err;
5672fe8fb19SBen Gras next:
5682fe8fb19SBen Gras 		_DIAGASSERT(*inbytes>=szrin && *outbytes>=szrout);
5692fe8fb19SBen Gras 		*inbytes -= tmpin-*in; /* szrin is insufficient on \0. */
5702fe8fb19SBen Gras 		*in = tmpin;
5712fe8fb19SBen Gras 		*outbytes -= szrout;
5722fe8fb19SBen Gras 		*out += szrout;
5732fe8fb19SBen Gras 	}
5742fe8fb19SBen Gras 	*invalids = inval;
5752fe8fb19SBen Gras 
5762fe8fb19SBen Gras 	return 0;
5772fe8fb19SBen Gras 
5782fe8fb19SBen Gras err:
5792fe8fb19SBen Gras 	restore_encoding_state(&sc->sc_src_encoding);
5802fe8fb19SBen Gras 	restore_encoding_state(&sc->sc_dst_encoding);
5812fe8fb19SBen Gras err_norestore:
5822fe8fb19SBen Gras 	*invalids = inval;
5832fe8fb19SBen Gras 
5842fe8fb19SBen Gras 	return ret;
5852fe8fb19SBen Gras }
586