1 /* $NetBSD: src/lib/libc/citrus/modules/citrus_iconv_std.c,v 1.10 2005/02/11 06:21:21 simonb Exp $ */
2 /* $DragonFly: src/lib/libc/citrus/modules/citrus_iconv_std.c,v 1.1 2005/03/11 23:33:53 joerg Exp $ */
5 * Copyright (c)2003 Citrus Project,
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/types.h>
31 #include <sys/endian.h>
32 #include <sys/queue.h>
40 #include "citrus_namespace.h"
41 #include "citrus_types.h"
42 #include "citrus_module.h"
43 #include "citrus_region.h"
44 #include "citrus_mmap.h"
45 #include "citrus_hash.h"
46 #include "citrus_iconv.h"
47 #include "citrus_stdenc.h"
48 #include "citrus_mapper.h"
49 #include "citrus_csmapper.h"
50 #include "citrus_memstream.h"
51 #include "citrus_iconv_std.h"
52 #include "citrus_esdb.h"
54 /* ---------------------------------------------------------------------- */
56 _CITRUS_ICONV_DECLS(iconv_std);
57 _CITRUS_ICONV_DEF_OPS(iconv_std);
60 /* ---------------------------------------------------------------------- */
63 _citrus_iconv_std_iconv_getops(struct _citrus_iconv_ops *ops, size_t lenops,
64 u_int32_t expected_version)
66 if (expected_version<_CITRUS_ICONV_ABI_VERSION || lenops<sizeof(*ops))
69 memcpy(ops, &_citrus_iconv_std_iconv_ops,
70 sizeof(_citrus_iconv_std_iconv_ops));
75 /* ---------------------------------------------------------------------- */
78 * convenience routines for stdenc.
81 save_encoding_state(struct _citrus_iconv_std_encoding *se)
84 memcpy(se->se_pssaved, se->se_ps,
85 _stdenc_get_state_size(se->se_handle));
89 restore_encoding_state(struct _citrus_iconv_std_encoding *se)
92 memcpy(se->se_ps, se->se_pssaved,
93 _stdenc_get_state_size(se->se_handle));
97 init_encoding_state(struct _citrus_iconv_std_encoding *se)
100 _stdenc_init_state(se->se_handle, se->se_ps);
104 mbtocsx(struct _citrus_iconv_std_encoding *se,
105 _csid_t *csid, _index_t *idx, const char **s, size_t n,
108 return _stdenc_mbtocs(se->se_handle, csid, idx, s, n, se->se_ps,
113 cstombx(struct _citrus_iconv_std_encoding *se,
114 char *s, size_t n, _csid_t csid, _index_t idx, size_t *nresult)
116 return _stdenc_cstomb(se->se_handle, s, n, csid, idx, se->se_ps,
121 wctombx(struct _citrus_iconv_std_encoding *se,
122 char *s, size_t n, _wc_t wc, size_t *nresult)
124 return _stdenc_wctomb(se->se_handle, s, n, wc, se->se_ps, nresult);
128 put_state_resetx(struct _citrus_iconv_std_encoding *se,
129 char *s, size_t n, size_t *nresult)
131 return _stdenc_put_state_reset(se->se_handle, s, n, se->se_ps, nresult);
135 * init encoding context
138 init_encoding(struct _citrus_iconv_std_encoding *se, struct _stdenc *cs,
139 void *ps1, void *ps2)
145 se->se_pssaved = ps2;
148 ret = _stdenc_init_state(cs, se->se_ps);
149 if (!ret && se->se_pssaved)
150 ret = _stdenc_init_state(cs, se->se_pssaved);
156 open_csmapper(struct _csmapper **rcm, const char *src, const char *dst,
157 unsigned long *rnorm)
160 struct _csmapper *cm;
162 ret = _csmapper_open(&cm, src, dst, 0, rnorm);
165 if (_csmapper_get_src_max(cm) != 1 || _csmapper_get_dst_max(cm) != 1 ||
166 _csmapper_get_state_size(cm) != 0) {
177 close_dsts(struct _citrus_iconv_std_dst_list *dl)
179 struct _citrus_iconv_std_dst *sd;
181 while ((sd=TAILQ_FIRST(dl)) != NULL) {
182 TAILQ_REMOVE(dl, sd, sd_entry);
183 _csmapper_close(sd->sd_mapper);
189 open_dsts(struct _citrus_iconv_std_dst_list *dl,
190 const struct _esdb_charset *ec, const struct _esdb *dbdst)
193 struct _citrus_iconv_std_dst *sd, *sdtmp;
196 sd = malloc(sizeof(*sd));
200 for (i=0; i<dbdst->db_num_charsets; i++) {
201 ret = open_csmapper(&sd->sd_mapper, ec->ec_csname,
202 dbdst->db_charsets[i].ec_csname, &norm);
204 sd->sd_csid = dbdst->db_charsets[i].ec_csid;
206 /* insert this mapper by sorted order. */
207 TAILQ_FOREACH(sdtmp, dl, sd_entry) {
208 if (sdtmp->sd_norm > norm) {
209 TAILQ_INSERT_BEFORE(sdtmp, sd,
216 TAILQ_INSERT_TAIL(dl, sd, sd_entry);
217 sd = malloc(sizeof(*sd));
223 } else if (ret != ENOENT) {
234 close_srcs(struct _citrus_iconv_std_src_list *sl)
236 struct _citrus_iconv_std_src *ss;
238 while ((ss=TAILQ_FIRST(sl)) != NULL) {
239 TAILQ_REMOVE(sl, ss, ss_entry);
240 close_dsts(&ss->ss_dsts);
246 open_srcs(struct _citrus_iconv_std_src_list *sl,
247 const struct _esdb *dbsrc, const struct _esdb *dbdst)
249 int i, ret, count = 0;
250 struct _citrus_iconv_std_src *ss;
252 ss = malloc(sizeof(*ss));
256 TAILQ_INIT(&ss->ss_dsts);
258 for (i=0; i<dbsrc->db_num_charsets; i++) {
259 ret = open_dsts(&ss->ss_dsts, &dbsrc->db_charsets[i], dbdst);
262 if (!TAILQ_EMPTY(&ss->ss_dsts)) {
263 ss->ss_csid = dbsrc->db_charsets[i].ec_csid;
264 TAILQ_INSERT_TAIL(sl, ss, ss_entry);
265 ss = malloc(sizeof(*ss));
271 TAILQ_INIT(&ss->ss_dsts);
276 return count ? 0 : ENOENT;
284 /* do convert a character */
285 #define E_NO_CORRESPONDING_CHAR ENOENT /* XXX */
288 do_conv(const struct _citrus_iconv_std_shared *is,
289 struct _citrus_iconv_std_context *sc, _csid_t *csid, _index_t *idx)
293 struct _citrus_iconv_std_src *ss;
294 struct _citrus_iconv_std_dst *sd;
296 TAILQ_FOREACH(ss, &is->is_srcs, ss_entry) {
297 if (ss->ss_csid == *csid) {
298 TAILQ_FOREACH(sd, &ss->ss_dsts, sd_entry) {
299 ret = _csmapper_convert(sd->sd_mapper,
300 &tmpidx, *idx, NULL);
302 case _MAPPER_CONVERT_SUCCESS:
306 case _MAPPER_CONVERT_NONIDENTICAL:
308 case _MAPPER_CONVERT_SRC_MORE:
310 case _MAPPER_CONVERT_DST_MORE:
312 case _MAPPER_CONVERT_FATAL:
314 case _MAPPER_CONVERT_ILSEQ:
322 return E_NO_CORRESPONDING_CHAR;
324 /* ---------------------------------------------------------------------- */
328 _citrus_iconv_std_iconv_init_shared(struct _citrus_iconv_shared *ci,
329 const char * __restrict curdir,
330 const char * __restrict src,
331 const char * __restrict dst,
332 const void * __restrict var, size_t lenvar)
335 struct _citrus_iconv_std_shared *is;
336 struct _citrus_esdb esdbsrc, esdbdst;
338 is = malloc(sizeof(*is));
343 ret = _citrus_esdb_open(&esdbsrc, src);
346 ret = _citrus_esdb_open(&esdbdst, dst);
349 ret = _stdenc_open(&is->is_src_encoding, esdbsrc.db_encname,
350 esdbsrc.db_variable, esdbsrc.db_len_variable);
353 ret = _stdenc_open(&is->is_dst_encoding, esdbdst.db_encname,
354 esdbdst.db_variable, esdbdst.db_len_variable);
357 is->is_use_invalid = esdbdst.db_use_invalid;
358 is->is_invalid = esdbdst.db_invalid;
360 TAILQ_INIT(&is->is_srcs);
361 ret = open_srcs(&is->is_srcs, &esdbsrc, &esdbdst);
365 _esdb_close(&esdbsrc);
366 _esdb_close(&esdbdst);
372 _stdenc_close(is->is_dst_encoding);
374 _stdenc_close(is->is_src_encoding);
376 _esdb_close(&esdbdst);
378 _esdb_close(&esdbsrc);
386 _citrus_iconv_std_iconv_uninit_shared(struct _citrus_iconv_shared *ci)
388 struct _citrus_iconv_std_shared *is = ci->ci_closure;
393 _stdenc_close(is->is_src_encoding);
394 _stdenc_close(is->is_dst_encoding);
395 close_srcs(&is->is_srcs);
400 _citrus_iconv_std_iconv_init_context(struct _citrus_iconv *cv)
402 const struct _citrus_iconv_std_shared *is = cv->cv_shared->ci_closure;
403 struct _citrus_iconv_std_context *sc;
405 size_t szpssrc, szpsdst, sz;
408 szpssrc = _stdenc_get_state_size(is->is_src_encoding);
409 szpsdst = _stdenc_get_state_size(is->is_dst_encoding);
411 sz = (szpssrc + szpsdst)*2 + sizeof(struct _citrus_iconv_std_context);
416 ptr = (char *)&sc[1];
418 init_encoding(&sc->sc_src_encoding, is->is_src_encoding,
421 init_encoding(&sc->sc_src_encoding, is->is_src_encoding,
425 init_encoding(&sc->sc_dst_encoding, is->is_dst_encoding,
428 init_encoding(&sc->sc_dst_encoding, is->is_dst_encoding,
431 cv->cv_closure = (void *)sc;
437 _citrus_iconv_std_iconv_uninit_context(struct _citrus_iconv *cv)
439 free(cv->cv_closure);
443 _citrus_iconv_std_iconv_convert(struct _citrus_iconv * __restrict cv,
444 const char * __restrict * __restrict in,
445 size_t * __restrict inbytes,
446 char * __restrict * __restrict out,
447 size_t * __restrict outbytes, u_int32_t flags,
448 size_t * __restrict invalids)
450 const struct _citrus_iconv_std_shared *is = cv->cv_shared->ci_closure;
451 struct _citrus_iconv_std_context *sc = cv->cv_closure;
455 size_t szrin, szrout;
460 if (in==NULL || *in==NULL) {
462 if (out!=NULL && *out!=NULL) {
463 /* init output state and store the shift sequence */
464 save_encoding_state(&sc->sc_src_encoding);
465 save_encoding_state(&sc->sc_dst_encoding);
468 ret = put_state_resetx(&sc->sc_dst_encoding,
474 if (szrout == (size_t)-2) {
475 /* too small to store the character */
482 /* otherwise, discard the shift sequence */
483 init_encoding_state(&sc->sc_dst_encoding);
484 init_encoding_state(&sc->sc_src_encoding);
494 /* save the encoding states for the error recovery */
495 save_encoding_state(&sc->sc_src_encoding);
496 save_encoding_state(&sc->sc_dst_encoding);
498 /* mb -> csid/index */
501 ret = mbtocsx(&sc->sc_src_encoding, &csid, &idx,
502 &tmpin, *inbytes, &szrin);
506 if (szrin == (size_t)-2) {
507 /* incompleted character */
511 /* convert the character */
512 ret = do_conv(is, sc, &csid, &idx);
514 if (ret == E_NO_CORRESPONDING_CHAR) {
517 if ((flags&_CITRUS_ICONV_F_HIDE_INVALID)==0 &&
518 is->is_use_invalid) {
519 ret = wctombx(&sc->sc_dst_encoding,
531 /* csid/index -> mb */
532 ret = cstombx(&sc->sc_dst_encoding,
533 *out, *outbytes, csid, idx, &szrout);
537 _DIAGASSERT(*inbytes>=szrin && *outbytes>=szrout);
538 *inbytes -= tmpin-*in; /* szrin is insufficient on \0. */
548 restore_encoding_state(&sc->sc_src_encoding);
549 restore_encoding_state(&sc->sc_dst_encoding);