Home | History | Annotate | Line # | Download | only in modules
      1  1.16       wiz /*	$NetBSD: citrus_iconv_std.c,v 1.16 2012/02/12 13:51:29 wiz Exp $	*/
      2   1.1  tshiozak 
      3   1.1  tshiozak /*-
      4   1.1  tshiozak  * Copyright (c)2003 Citrus Project,
      5   1.1  tshiozak  * All rights reserved.
      6   1.1  tshiozak  *
      7   1.1  tshiozak  * Redistribution and use in source and binary forms, with or without
      8   1.1  tshiozak  * modification, are permitted provided that the following conditions
      9   1.1  tshiozak  * are met:
     10   1.1  tshiozak  * 1. Redistributions of source code must retain the above copyright
     11   1.1  tshiozak  *    notice, this list of conditions and the following disclaimer.
     12   1.1  tshiozak  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1  tshiozak  *    notice, this list of conditions and the following disclaimer in the
     14   1.1  tshiozak  *    documentation and/or other materials provided with the distribution.
     15   1.1  tshiozak  *
     16   1.1  tshiozak  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17   1.1  tshiozak  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18   1.1  tshiozak  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19   1.1  tshiozak  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20   1.1  tshiozak  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21   1.1  tshiozak  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22   1.1  tshiozak  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23   1.1  tshiozak  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24   1.1  tshiozak  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25   1.1  tshiozak  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26   1.1  tshiozak  * SUCH DAMAGE.
     27   1.1  tshiozak  */
     28   1.1  tshiozak 
     29   1.1  tshiozak #include <sys/cdefs.h>
     30   1.1  tshiozak #if defined(LIBC_SCCS) && !defined(lint)
     31  1.16       wiz __RCSID("$NetBSD: citrus_iconv_std.c,v 1.16 2012/02/12 13:51:29 wiz Exp $");
     32   1.1  tshiozak #endif /* LIBC_SCCS and not lint */
     33   1.1  tshiozak 
     34   1.1  tshiozak #include <assert.h>
     35   1.1  tshiozak #include <errno.h>
     36   1.1  tshiozak #include <limits.h>
     37   1.1  tshiozak #include <stdio.h>
     38   1.1  tshiozak #include <stdlib.h>
     39   1.1  tshiozak #include <string.h>
     40  1.12    dogcow #include <machine/endian.h>
     41   1.1  tshiozak #include <sys/queue.h>
     42   1.1  tshiozak 
     43   1.1  tshiozak #include "citrus_namespace.h"
     44   1.1  tshiozak #include "citrus_types.h"
     45   1.1  tshiozak #include "citrus_module.h"
     46   1.1  tshiozak #include "citrus_region.h"
     47   1.1  tshiozak #include "citrus_mmap.h"
     48   1.4  tshiozak #include "citrus_hash.h"
     49   1.1  tshiozak #include "citrus_iconv.h"
     50   1.1  tshiozak #include "citrus_stdenc.h"
     51   1.1  tshiozak #include "citrus_mapper.h"
     52   1.1  tshiozak #include "citrus_csmapper.h"
     53   1.1  tshiozak #include "citrus_memstream.h"
     54   1.1  tshiozak #include "citrus_iconv_std.h"
     55   1.1  tshiozak #include "citrus_esdb.h"
     56   1.1  tshiozak 
     57   1.1  tshiozak /* ---------------------------------------------------------------------- */
     58   1.1  tshiozak 
     59   1.1  tshiozak _CITRUS_ICONV_DECLS(iconv_std);
     60   1.1  tshiozak _CITRUS_ICONV_DEF_OPS(iconv_std);
     61   1.1  tshiozak 
     62   1.1  tshiozak 
     63   1.1  tshiozak /* ---------------------------------------------------------------------- */
     64   1.1  tshiozak 
     65   1.1  tshiozak int
     66   1.1  tshiozak _citrus_iconv_std_iconv_getops(struct _citrus_iconv_ops *ops, size_t lenops,
     67   1.1  tshiozak 			       u_int32_t expected_version)
     68   1.1  tshiozak {
     69   1.1  tshiozak 	if (expected_version<_CITRUS_ICONV_ABI_VERSION || lenops<sizeof(*ops))
     70   1.1  tshiozak 		return (EINVAL);
     71   1.1  tshiozak 
     72   1.1  tshiozak 	memcpy(ops, &_citrus_iconv_std_iconv_ops,
     73   1.1  tshiozak 	       sizeof(_citrus_iconv_std_iconv_ops));
     74   1.1  tshiozak 
     75   1.1  tshiozak 	return (0);
     76   1.1  tshiozak }
     77   1.1  tshiozak 
     78   1.1  tshiozak /* ---------------------------------------------------------------------- */
     79   1.1  tshiozak 
     80   1.1  tshiozak /*
     81   1.1  tshiozak  * convenience routines for stdenc.
     82   1.1  tshiozak  */
     83   1.1  tshiozak static __inline void
     84   1.1  tshiozak save_encoding_state(struct _citrus_iconv_std_encoding *se)
     85   1.1  tshiozak {
     86   1.1  tshiozak 	if (se->se_ps)
     87   1.1  tshiozak 		memcpy(se->se_pssaved, se->se_ps,
     88   1.1  tshiozak 		       _stdenc_get_state_size(se->se_handle));
     89   1.1  tshiozak }
     90   1.1  tshiozak 
     91   1.1  tshiozak static __inline void
     92   1.1  tshiozak restore_encoding_state(struct _citrus_iconv_std_encoding *se)
     93   1.1  tshiozak {
     94   1.1  tshiozak 	if (se->se_ps)
     95   1.1  tshiozak 		memcpy(se->se_ps, se->se_pssaved,
     96   1.1  tshiozak 		       _stdenc_get_state_size(se->se_handle));
     97   1.1  tshiozak }
     98   1.1  tshiozak 
     99   1.1  tshiozak static __inline void
    100   1.1  tshiozak init_encoding_state(struct _citrus_iconv_std_encoding *se)
    101   1.1  tshiozak {
    102   1.1  tshiozak 	if (se->se_ps)
    103   1.1  tshiozak 		_stdenc_init_state(se->se_handle, se->se_ps);
    104   1.1  tshiozak }
    105   1.1  tshiozak 
    106   1.1  tshiozak static __inline int
    107   1.1  tshiozak mbtocsx(struct _citrus_iconv_std_encoding *se,
    108   1.1  tshiozak 	_csid_t *csid, _index_t *idx, const char **s, size_t n,
    109   1.1  tshiozak 	size_t *nresult)
    110   1.1  tshiozak {
    111   1.1  tshiozak 	return _stdenc_mbtocs(se->se_handle, csid, idx, s, n, se->se_ps,
    112   1.1  tshiozak 			      nresult);
    113   1.1  tshiozak }
    114   1.1  tshiozak 
    115   1.1  tshiozak static __inline int
    116   1.1  tshiozak cstombx(struct _citrus_iconv_std_encoding *se,
    117   1.1  tshiozak 	char *s, size_t n, _csid_t csid, _index_t idx, size_t *nresult)
    118   1.1  tshiozak {
    119   1.1  tshiozak 	return _stdenc_cstomb(se->se_handle, s, n, csid, idx, se->se_ps,
    120   1.1  tshiozak 			      nresult);
    121   1.1  tshiozak }
    122   1.1  tshiozak 
    123   1.1  tshiozak static __inline int
    124   1.1  tshiozak wctombx(struct _citrus_iconv_std_encoding *se,
    125   1.1  tshiozak 	char *s, size_t n, _wc_t wc, size_t *nresult)
    126   1.1  tshiozak {
    127   1.1  tshiozak 	return _stdenc_wctomb(se->se_handle, s, n, wc, se->se_ps, nresult);
    128   1.1  tshiozak }
    129   1.1  tshiozak 
    130   1.2  tshiozak static __inline int
    131   1.2  tshiozak put_state_resetx(struct _citrus_iconv_std_encoding *se,
    132   1.2  tshiozak 		 char *s, size_t n, size_t *nresult)
    133   1.2  tshiozak {
    134   1.2  tshiozak 	return _stdenc_put_state_reset(se->se_handle, s, n, se->se_ps, nresult);
    135   1.2  tshiozak }
    136   1.2  tshiozak 
    137  1.11  tshiozak static __inline int
    138  1.11  tshiozak get_state_desc_gen(struct _citrus_iconv_std_encoding *se, int *rstate)
    139  1.11  tshiozak {
    140  1.11  tshiozak 	int ret;
    141  1.11  tshiozak 	struct _stdenc_state_desc ssd;
    142  1.11  tshiozak 
    143  1.11  tshiozak 	ret = _stdenc_get_state_desc(se->se_handle, se->se_ps,
    144  1.11  tshiozak 				     _STDENC_SDID_GENERIC, &ssd);
    145  1.11  tshiozak 	if (!ret)
    146  1.11  tshiozak 		*rstate = ssd.u.generic.state;
    147  1.11  tshiozak 
    148  1.11  tshiozak 	return ret;
    149  1.11  tshiozak }
    150  1.11  tshiozak 
    151   1.1  tshiozak /*
    152   1.4  tshiozak  * init encoding context
    153   1.1  tshiozak  */
    154   1.4  tshiozak static int
    155   1.4  tshiozak init_encoding(struct _citrus_iconv_std_encoding *se, struct _stdenc *cs,
    156   1.4  tshiozak 	      void *ps1, void *ps2)
    157   1.1  tshiozak {
    158  1.13  christos 	int ret = -1;
    159   1.1  tshiozak 
    160   1.4  tshiozak 	se->se_handle = cs;
    161   1.4  tshiozak 	se->se_ps = ps1;
    162   1.4  tshiozak 	se->se_pssaved = ps2;
    163   1.1  tshiozak 
    164   1.4  tshiozak 	if (se->se_ps)
    165   1.4  tshiozak 		ret = _stdenc_init_state(cs, se->se_ps);
    166   1.4  tshiozak 	if (!ret && se->se_pssaved)
    167   1.4  tshiozak 		ret = _stdenc_init_state(cs, se->se_pssaved);
    168   1.1  tshiozak 
    169   1.1  tshiozak 	return ret;
    170   1.1  tshiozak }
    171   1.1  tshiozak 
    172   1.1  tshiozak static int
    173   1.1  tshiozak open_csmapper(struct _csmapper **rcm, const char *src, const char *dst,
    174   1.1  tshiozak 	      unsigned long *rnorm)
    175   1.1  tshiozak {
    176   1.1  tshiozak 	int ret;
    177   1.1  tshiozak 	struct _csmapper *cm;
    178   1.1  tshiozak 
    179   1.1  tshiozak 	ret = _csmapper_open(&cm, src, dst, 0, rnorm);
    180   1.1  tshiozak 	if (ret)
    181   1.1  tshiozak 		return ret;
    182   1.1  tshiozak 	if (_csmapper_get_src_max(cm) != 1 || _csmapper_get_dst_max(cm) != 1 ||
    183   1.1  tshiozak 	    _csmapper_get_state_size(cm) != 0) {
    184   1.1  tshiozak 		_csmapper_close(cm);
    185   1.1  tshiozak 		return EINVAL;
    186   1.1  tshiozak 	}
    187   1.1  tshiozak 
    188   1.1  tshiozak 	*rcm = cm;
    189   1.1  tshiozak 
    190   1.1  tshiozak 	return 0;
    191   1.1  tshiozak }
    192   1.1  tshiozak 
    193   1.1  tshiozak static void
    194   1.1  tshiozak close_dsts(struct _citrus_iconv_std_dst_list *dl)
    195   1.1  tshiozak {
    196   1.1  tshiozak 	struct _citrus_iconv_std_dst *sd;
    197   1.1  tshiozak 
    198   1.1  tshiozak 	while ((sd=TAILQ_FIRST(dl)) != NULL) {
    199   1.1  tshiozak 		TAILQ_REMOVE(dl, sd, sd_entry);
    200   1.1  tshiozak 		_csmapper_close(sd->sd_mapper);
    201   1.1  tshiozak 		free(sd);
    202   1.1  tshiozak 	}
    203   1.1  tshiozak }
    204   1.1  tshiozak 
    205   1.1  tshiozak static int
    206   1.1  tshiozak open_dsts(struct _citrus_iconv_std_dst_list *dl,
    207   1.8      yamt 	  const struct _esdb_charset *ec, const struct _esdb *dbdst)
    208   1.1  tshiozak {
    209   1.1  tshiozak 	int i, ret;
    210   1.1  tshiozak 	struct _citrus_iconv_std_dst *sd, *sdtmp;
    211   1.1  tshiozak 	unsigned long norm;
    212   1.1  tshiozak 
    213   1.1  tshiozak 	sd = malloc(sizeof(*sd));
    214   1.1  tshiozak 	if (sd == NULL)
    215   1.1  tshiozak 		return errno;
    216   1.1  tshiozak 
    217   1.1  tshiozak 	for (i=0; i<dbdst->db_num_charsets; i++) {
    218   1.3  tshiozak 		ret = open_csmapper(&sd->sd_mapper, ec->ec_csname,
    219   1.1  tshiozak 				    dbdst->db_charsets[i].ec_csname, &norm);
    220   1.1  tshiozak 		if (ret == 0) {
    221   1.1  tshiozak 			sd->sd_csid = dbdst->db_charsets[i].ec_csid;
    222   1.1  tshiozak 			sd->sd_norm = norm;
    223   1.1  tshiozak 			/* insert this mapper by sorted order. */
    224   1.1  tshiozak 			TAILQ_FOREACH(sdtmp, dl, sd_entry) {
    225   1.1  tshiozak 				if (sdtmp->sd_norm > norm) {
    226   1.1  tshiozak 					TAILQ_INSERT_BEFORE(sdtmp, sd,
    227   1.1  tshiozak 							    sd_entry);
    228   1.1  tshiozak 					sd = NULL;
    229   1.1  tshiozak 					break;
    230   1.1  tshiozak 				}
    231   1.1  tshiozak 			}
    232   1.1  tshiozak 			if (sd)
    233   1.1  tshiozak 				TAILQ_INSERT_TAIL(dl, sd, sd_entry);
    234   1.1  tshiozak 			sd = malloc(sizeof(*sd));
    235   1.1  tshiozak 			if (sd == NULL) {
    236   1.1  tshiozak 				ret = errno;
    237   1.1  tshiozak 				close_dsts(dl);
    238   1.1  tshiozak 				return ret;
    239   1.1  tshiozak 			}
    240   1.1  tshiozak 		} else if (ret != ENOENT) {
    241   1.1  tshiozak 			close_dsts(dl);
    242   1.1  tshiozak 			free(sd);
    243   1.1  tshiozak 			return ret;
    244   1.1  tshiozak 		}
    245   1.1  tshiozak 	}
    246   1.1  tshiozak 	free(sd);
    247   1.1  tshiozak 	return 0;
    248   1.1  tshiozak }
    249   1.1  tshiozak 
    250   1.1  tshiozak static void
    251   1.1  tshiozak close_srcs(struct _citrus_iconv_std_src_list *sl)
    252   1.1  tshiozak {
    253   1.1  tshiozak 	struct _citrus_iconv_std_src *ss;
    254   1.1  tshiozak 
    255   1.1  tshiozak 	while ((ss=TAILQ_FIRST(sl)) != NULL) {
    256   1.1  tshiozak 		TAILQ_REMOVE(sl, ss, ss_entry);
    257   1.1  tshiozak 		close_dsts(&ss->ss_dsts);
    258   1.1  tshiozak 		free(ss);
    259   1.1  tshiozak 	}
    260   1.1  tshiozak }
    261   1.1  tshiozak 
    262   1.1  tshiozak static int
    263   1.1  tshiozak open_srcs(struct _citrus_iconv_std_src_list *sl,
    264   1.8      yamt 	  const struct _esdb *dbsrc, const struct _esdb *dbdst)
    265   1.1  tshiozak {
    266   1.1  tshiozak 	int i, ret, count = 0;
    267   1.1  tshiozak 	struct _citrus_iconv_std_src *ss;
    268   1.1  tshiozak 
    269   1.1  tshiozak 	ss = malloc(sizeof(*ss));
    270   1.1  tshiozak 	if (ss == NULL)
    271   1.1  tshiozak 		return errno;
    272   1.1  tshiozak 
    273   1.1  tshiozak 	TAILQ_INIT(&ss->ss_dsts);
    274   1.1  tshiozak 
    275   1.1  tshiozak 	for (i=0; i<dbsrc->db_num_charsets; i++) {
    276   1.1  tshiozak 		ret = open_dsts(&ss->ss_dsts, &dbsrc->db_charsets[i], dbdst);
    277   1.1  tshiozak 		if (ret)
    278   1.1  tshiozak 			goto err;
    279   1.1  tshiozak 		if (!TAILQ_EMPTY(&ss->ss_dsts)) {
    280   1.1  tshiozak 			ss->ss_csid = dbsrc->db_charsets[i].ec_csid;
    281   1.1  tshiozak 			TAILQ_INSERT_TAIL(sl, ss, ss_entry);
    282   1.1  tshiozak 			ss = malloc(sizeof(*ss));
    283   1.1  tshiozak 			if (ss == NULL) {
    284   1.1  tshiozak 				ret = errno;
    285   1.1  tshiozak 				goto err;
    286   1.1  tshiozak 			}
    287   1.1  tshiozak 			count++;
    288   1.1  tshiozak 			TAILQ_INIT(&ss->ss_dsts);
    289   1.1  tshiozak 		}
    290   1.1  tshiozak 	}
    291   1.1  tshiozak 	free(ss);
    292   1.1  tshiozak 
    293   1.1  tshiozak 	return count ? 0 : ENOENT;
    294   1.1  tshiozak 
    295   1.1  tshiozak err:
    296   1.1  tshiozak 	free(ss);
    297   1.1  tshiozak 	close_srcs(sl);
    298   1.1  tshiozak 	return ret;
    299   1.1  tshiozak }
    300   1.1  tshiozak 
    301   1.1  tshiozak /* do convert a character */
    302   1.1  tshiozak #define E_NO_CORRESPONDING_CHAR ENOENT /* XXX */
    303   1.1  tshiozak static int
    304   1.4  tshiozak /*ARGSUSED*/
    305   1.9      yamt do_conv(const struct _citrus_iconv_std_shared *is,
    306   1.4  tshiozak 	struct _citrus_iconv_std_context *sc, _csid_t *csid, _index_t *idx)
    307   1.1  tshiozak {
    308   1.1  tshiozak 	_index_t tmpidx;
    309   1.1  tshiozak 	int ret;
    310   1.1  tshiozak 	struct _citrus_iconv_std_src *ss;
    311   1.1  tshiozak 	struct _citrus_iconv_std_dst *sd;
    312   1.1  tshiozak 
    313   1.1  tshiozak 	TAILQ_FOREACH(ss, &is->is_srcs, ss_entry) {
    314   1.1  tshiozak 		if (ss->ss_csid == *csid) {
    315   1.1  tshiozak 			TAILQ_FOREACH(sd, &ss->ss_dsts, sd_entry) {
    316   1.1  tshiozak 				ret = _csmapper_convert(sd->sd_mapper,
    317   1.1  tshiozak 							&tmpidx, *idx, NULL);
    318   1.1  tshiozak 				switch (ret) {
    319   1.5  tshiozak 				case _MAPPER_CONVERT_SUCCESS:
    320   1.1  tshiozak 					*csid = sd->sd_csid;
    321   1.1  tshiozak 					*idx = tmpidx;
    322   1.1  tshiozak 					return 0;
    323   1.5  tshiozak 				case _MAPPER_CONVERT_NONIDENTICAL:
    324   1.1  tshiozak 					break;
    325   1.5  tshiozak 				case _MAPPER_CONVERT_SRC_MORE:
    326   1.1  tshiozak 					/*FALLTHROUGH*/
    327   1.5  tshiozak 				case _MAPPER_CONVERT_DST_MORE:
    328   1.1  tshiozak 					/*FALLTHROUGH*/
    329   1.5  tshiozak 				case _MAPPER_CONVERT_FATAL:
    330   1.1  tshiozak 					return EINVAL;
    331   1.5  tshiozak 				case _MAPPER_CONVERT_ILSEQ:
    332   1.1  tshiozak 					return EILSEQ;
    333   1.1  tshiozak 				}
    334   1.1  tshiozak 			}
    335   1.1  tshiozak 			break;
    336   1.1  tshiozak 		}
    337   1.1  tshiozak 	}
    338   1.1  tshiozak 
    339   1.1  tshiozak 	return E_NO_CORRESPONDING_CHAR;
    340   1.1  tshiozak }
    341   1.1  tshiozak /* ---------------------------------------------------------------------- */
    342   1.1  tshiozak 
    343   1.1  tshiozak static int
    344   1.1  tshiozak /*ARGSUSED*/
    345   1.4  tshiozak _citrus_iconv_std_iconv_init_shared(struct _citrus_iconv_shared *ci,
    346   1.4  tshiozak 				    const char * __restrict curdir,
    347   1.4  tshiozak 				    const char * __restrict src,
    348   1.4  tshiozak 				    const char * __restrict dst,
    349   1.4  tshiozak 				    const void * __restrict var, size_t lenvar)
    350   1.1  tshiozak {
    351   1.1  tshiozak 	int ret;
    352   1.4  tshiozak 	struct _citrus_iconv_std_shared *is;
    353   1.1  tshiozak 	struct _citrus_esdb esdbsrc, esdbdst;
    354   1.1  tshiozak 
    355   1.1  tshiozak 	is = malloc(sizeof(*is));
    356   1.1  tshiozak 	if (is==NULL) {
    357   1.1  tshiozak 		ret = errno;
    358   1.1  tshiozak 		goto err0;
    359   1.1  tshiozak 	}
    360   1.1  tshiozak 	ret = _citrus_esdb_open(&esdbsrc, src);
    361   1.1  tshiozak 	if (ret)
    362   1.1  tshiozak 		goto err1;
    363   1.1  tshiozak 	ret = _citrus_esdb_open(&esdbdst, dst);
    364   1.1  tshiozak 	if (ret)
    365   1.1  tshiozak 		goto err2;
    366   1.4  tshiozak 	ret = _stdenc_open(&is->is_src_encoding, esdbsrc.db_encname,
    367   1.4  tshiozak 			   esdbsrc.db_variable, esdbsrc.db_len_variable);
    368   1.1  tshiozak 	if (ret)
    369   1.1  tshiozak 		goto err3;
    370   1.4  tshiozak 	ret = _stdenc_open(&is->is_dst_encoding, esdbdst.db_encname,
    371   1.4  tshiozak 			   esdbdst.db_variable, esdbdst.db_len_variable);
    372   1.1  tshiozak 	if (ret)
    373   1.1  tshiozak 		goto err4;
    374   1.1  tshiozak 	is->is_use_invalid = esdbdst.db_use_invalid;
    375   1.1  tshiozak 	is->is_invalid = esdbdst.db_invalid;
    376   1.1  tshiozak 
    377   1.1  tshiozak 	TAILQ_INIT(&is->is_srcs);
    378   1.1  tshiozak 	ret = open_srcs(&is->is_srcs, &esdbsrc, &esdbdst);
    379   1.1  tshiozak 	if (ret)
    380   1.1  tshiozak 		goto err5;
    381   1.1  tshiozak 
    382   1.1  tshiozak 	_esdb_close(&esdbsrc);
    383   1.1  tshiozak 	_esdb_close(&esdbdst);
    384   1.1  tshiozak 	ci->ci_closure = is;
    385   1.1  tshiozak 
    386   1.1  tshiozak 	return 0;
    387   1.1  tshiozak 
    388   1.1  tshiozak err5:
    389   1.4  tshiozak 	_stdenc_close(is->is_dst_encoding);
    390   1.1  tshiozak err4:
    391   1.4  tshiozak 	_stdenc_close(is->is_src_encoding);
    392   1.1  tshiozak err3:
    393   1.1  tshiozak 	_esdb_close(&esdbdst);
    394   1.1  tshiozak err2:
    395   1.1  tshiozak 	_esdb_close(&esdbsrc);
    396   1.1  tshiozak err1:
    397   1.1  tshiozak 	free(is);
    398   1.1  tshiozak err0:
    399   1.1  tshiozak 	return ret;
    400   1.1  tshiozak }
    401   1.1  tshiozak 
    402   1.1  tshiozak static void
    403   1.4  tshiozak _citrus_iconv_std_iconv_uninit_shared(struct _citrus_iconv_shared *ci)
    404   1.1  tshiozak {
    405   1.4  tshiozak 	struct _citrus_iconv_std_shared *is = ci->ci_closure;
    406   1.1  tshiozak 
    407   1.4  tshiozak 	if (is == NULL)
    408   1.1  tshiozak 		return;
    409   1.1  tshiozak 
    410   1.4  tshiozak 	_stdenc_close(is->is_src_encoding);
    411   1.4  tshiozak 	_stdenc_close(is->is_dst_encoding);
    412   1.1  tshiozak 	close_srcs(&is->is_srcs);
    413   1.1  tshiozak 	free(is);
    414   1.1  tshiozak }
    415   1.1  tshiozak 
    416   1.1  tshiozak static int
    417   1.4  tshiozak _citrus_iconv_std_iconv_init_context(struct _citrus_iconv *cv)
    418   1.4  tshiozak {
    419   1.9      yamt 	const struct _citrus_iconv_std_shared *is = cv->cv_shared->ci_closure;
    420   1.4  tshiozak 	struct _citrus_iconv_std_context *sc;
    421   1.4  tshiozak 	size_t szpssrc, szpsdst, sz;
    422   1.4  tshiozak 	char *ptr;
    423   1.4  tshiozak 
    424   1.4  tshiozak 	szpssrc = _stdenc_get_state_size(is->is_src_encoding);
    425   1.4  tshiozak 	szpsdst = _stdenc_get_state_size(is->is_dst_encoding);
    426   1.4  tshiozak 
    427   1.4  tshiozak 	sz = (szpssrc + szpsdst)*2 + sizeof(struct _citrus_iconv_std_context);
    428   1.4  tshiozak 	sc = malloc(sz);
    429   1.4  tshiozak 	if (sc == NULL)
    430   1.4  tshiozak 		return errno;
    431   1.4  tshiozak 
    432   1.4  tshiozak 	ptr = (char *)&sc[1];
    433   1.4  tshiozak 	if (szpssrc)
    434   1.4  tshiozak 		init_encoding(&sc->sc_src_encoding, is->is_src_encoding,
    435   1.4  tshiozak 			      ptr, ptr+szpssrc);
    436   1.4  tshiozak 	else
    437   1.4  tshiozak 		init_encoding(&sc->sc_src_encoding, is->is_src_encoding,
    438   1.4  tshiozak 			      NULL, NULL);
    439   1.4  tshiozak 	ptr += szpssrc*2;
    440   1.4  tshiozak 	if (szpsdst)
    441   1.4  tshiozak 		init_encoding(&sc->sc_dst_encoding, is->is_dst_encoding,
    442   1.4  tshiozak 			      ptr, ptr+szpsdst);
    443   1.4  tshiozak 	else
    444   1.4  tshiozak 		init_encoding(&sc->sc_dst_encoding, is->is_dst_encoding,
    445   1.4  tshiozak 			      NULL, NULL);
    446   1.4  tshiozak 
    447   1.4  tshiozak 	cv->cv_closure = (void *)sc;
    448   1.4  tshiozak 
    449   1.4  tshiozak 	return 0;
    450   1.4  tshiozak }
    451   1.4  tshiozak 
    452   1.4  tshiozak static void
    453   1.4  tshiozak _citrus_iconv_std_iconv_uninit_context(struct _citrus_iconv *cv)
    454   1.4  tshiozak {
    455   1.4  tshiozak 	free(cv->cv_closure);
    456   1.4  tshiozak }
    457   1.4  tshiozak 
    458   1.4  tshiozak static int
    459   1.4  tshiozak _citrus_iconv_std_iconv_convert(struct _citrus_iconv * __restrict cv,
    460   1.1  tshiozak 				const char * __restrict * __restrict in,
    461   1.1  tshiozak 				size_t * __restrict inbytes,
    462   1.1  tshiozak 				char * __restrict * __restrict out,
    463   1.1  tshiozak 				size_t * __restrict outbytes, u_int32_t flags,
    464   1.1  tshiozak 				size_t * __restrict invalids)
    465   1.1  tshiozak {
    466   1.9      yamt 	const struct _citrus_iconv_std_shared *is = cv->cv_shared->ci_closure;
    467   1.4  tshiozak 	struct _citrus_iconv_std_context *sc = cv->cv_closure;
    468   1.1  tshiozak 	_index_t idx;
    469   1.1  tshiozak 	_csid_t csid;
    470  1.11  tshiozak 	int ret, state;
    471   1.1  tshiozak 	size_t szrin, szrout;
    472   1.1  tshiozak 	size_t inval;
    473   1.1  tshiozak 	const char *tmpin;
    474   1.1  tshiozak 
    475   1.1  tshiozak 	inval = 0;
    476   1.1  tshiozak 	if (in==NULL || *in==NULL) {
    477   1.1  tshiozak 		/* special cases */
    478   1.1  tshiozak 		if (out!=NULL && *out!=NULL) {
    479   1.6  tshiozak 			/* init output state and store the shift sequence */
    480   1.4  tshiozak 			save_encoding_state(&sc->sc_src_encoding);
    481   1.4  tshiozak 			save_encoding_state(&sc->sc_dst_encoding);
    482   1.1  tshiozak 			szrout = 0;
    483   1.2  tshiozak 
    484   1.4  tshiozak 			ret = put_state_resetx(&sc->sc_dst_encoding,
    485   1.2  tshiozak 					       *out, *outbytes,
    486   1.2  tshiozak 					       &szrout);
    487   1.1  tshiozak 			if (ret)
    488   1.1  tshiozak 				goto err;
    489   1.1  tshiozak 
    490   1.1  tshiozak 			if (szrout == (size_t)-2) {
    491   1.1  tshiozak 				/* too small to store the character */
    492   1.1  tshiozak 				ret = EINVAL;
    493   1.1  tshiozak 				goto err;
    494   1.1  tshiozak 			}
    495   1.1  tshiozak 			*out += szrout;
    496   1.1  tshiozak 			*outbytes -= szrout;
    497   1.6  tshiozak 		} else
    498   1.6  tshiozak 			/* otherwise, discard the shift sequence */
    499   1.6  tshiozak 			init_encoding_state(&sc->sc_dst_encoding);
    500   1.6  tshiozak 		init_encoding_state(&sc->sc_src_encoding);
    501   1.1  tshiozak 		*invalids = 0;
    502   1.1  tshiozak 		return 0;
    503   1.1  tshiozak 	}
    504   1.1  tshiozak 
    505   1.1  tshiozak 	/* normal case */
    506   1.1  tshiozak 	for (;;) {
    507  1.14   tnozaki 		if (*inbytes==0) {
    508  1.14   tnozaki 			ret = get_state_desc_gen(&sc->sc_src_encoding, &state);
    509  1.15   tnozaki 			if (state == _STDENC_SDGEN_INITIAL ||
    510  1.15   tnozaki 			    state == _STDENC_SDGEN_STABLE)
    511  1.14   tnozaki 				break;
    512  1.14   tnozaki 		}
    513   1.7      yamt 
    514   1.1  tshiozak 		/* save the encoding states for the error recovery */
    515   1.4  tshiozak 		save_encoding_state(&sc->sc_src_encoding);
    516   1.4  tshiozak 		save_encoding_state(&sc->sc_dst_encoding);
    517   1.1  tshiozak 
    518   1.1  tshiozak 		/* mb -> csid/index */
    519   1.1  tshiozak 		tmpin = *in;
    520   1.1  tshiozak 		szrin = szrout = 0;
    521   1.4  tshiozak 		ret = mbtocsx(&sc->sc_src_encoding, &csid, &idx,
    522   1.4  tshiozak 			      &tmpin, *inbytes, &szrin);
    523   1.1  tshiozak 		if (ret)
    524   1.1  tshiozak 			goto err;
    525   1.1  tshiozak 
    526   1.1  tshiozak 		if (szrin == (size_t)-2) {
    527   1.1  tshiozak 			/* incompleted character */
    528  1.11  tshiozak 			ret = get_state_desc_gen(&sc->sc_src_encoding, &state);
    529  1.11  tshiozak 			if (ret) {
    530  1.11  tshiozak 				ret = EINVAL;
    531  1.11  tshiozak 				goto err;
    532  1.11  tshiozak 			}
    533  1.11  tshiozak 			switch (state) {
    534  1.11  tshiozak 			case _STDENC_SDGEN_INITIAL:
    535  1.11  tshiozak 			case _STDENC_SDGEN_STABLE:
    536  1.11  tshiozak 				/* fetch shift sequences only. */
    537  1.11  tshiozak 				goto next;
    538  1.11  tshiozak 			}
    539   1.1  tshiozak 			ret = EINVAL;
    540   1.1  tshiozak 			goto err;
    541   1.1  tshiozak 		}
    542   1.1  tshiozak 		/* convert the character */
    543   1.4  tshiozak 		ret = do_conv(is, sc, &csid, &idx);
    544   1.1  tshiozak 		if (ret) {
    545   1.1  tshiozak 			if (ret == E_NO_CORRESPONDING_CHAR) {
    546  1.10    simonb 				inval++;
    547   1.2  tshiozak 				szrout = 0;
    548   1.1  tshiozak 				if ((flags&_CITRUS_ICONV_F_HIDE_INVALID)==0 &&
    549   1.1  tshiozak 				    is->is_use_invalid) {
    550   1.4  tshiozak 					ret = wctombx(&sc->sc_dst_encoding,
    551   1.1  tshiozak 						      *out, *outbytes,
    552   1.1  tshiozak 						      is->is_invalid,
    553   1.1  tshiozak 						      &szrout);
    554   1.1  tshiozak 					if (ret)
    555   1.1  tshiozak 						goto err;
    556   1.1  tshiozak 				}
    557   1.1  tshiozak 				goto next;
    558   1.1  tshiozak 			} else {
    559   1.1  tshiozak 				goto err;
    560   1.1  tshiozak 			}
    561   1.1  tshiozak 		}
    562   1.1  tshiozak 		/* csid/index -> mb */
    563   1.4  tshiozak 		ret = cstombx(&sc->sc_dst_encoding,
    564   1.1  tshiozak 			      *out, *outbytes, csid, idx, &szrout);
    565   1.1  tshiozak 		if (ret)
    566   1.1  tshiozak 			goto err;
    567   1.1  tshiozak next:
    568   1.1  tshiozak 		_DIAGASSERT(*inbytes>=szrin && *outbytes>=szrout);
    569   1.1  tshiozak 		*inbytes -= tmpin-*in; /* szrin is insufficient on \0. */
    570   1.1  tshiozak 		*in = tmpin;
    571   1.1  tshiozak 		*outbytes -= szrout;
    572   1.1  tshiozak 		*out += szrout;
    573   1.1  tshiozak 	}
    574   1.1  tshiozak 	*invalids = inval;
    575   1.1  tshiozak 
    576   1.1  tshiozak 	return 0;
    577   1.1  tshiozak 
    578   1.1  tshiozak err:
    579   1.4  tshiozak 	restore_encoding_state(&sc->sc_src_encoding);
    580   1.4  tshiozak 	restore_encoding_state(&sc->sc_dst_encoding);
    581   1.1  tshiozak err_norestore:
    582   1.1  tshiozak 	*invalids = inval;
    583   1.1  tshiozak 
    584   1.1  tshiozak 	return ret;
    585   1.1  tshiozak }
    586