1 /* $NetBSD: citrus_iconv_std.c,v 1.16 2012/02/12 13:51:29 wiz Exp $ */
4 * Copyright (c)2003 Citrus Project,
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 #if defined(LIBC_SCCS) && !defined(lint)
31 __RCSID("$NetBSD: citrus_iconv_std.c,v 1.16 2012/02/12 13:51:29 wiz Exp $");
32 #endif /* LIBC_SCCS and not lint */
40 #include <machine/endian.h>
41 #include <sys/queue.h>
43 #include "citrus_namespace.h"
44 #include "citrus_types.h"
45 #include "citrus_module.h"
46 #include "citrus_region.h"
47 #include "citrus_mmap.h"
48 #include "citrus_hash.h"
49 #include "citrus_iconv.h"
50 #include "citrus_stdenc.h"
51 #include "citrus_mapper.h"
52 #include "citrus_csmapper.h"
53 #include "citrus_memstream.h"
54 #include "citrus_iconv_std.h"
55 #include "citrus_esdb.h"
57 /* ---------------------------------------------------------------------- */
59 _CITRUS_ICONV_DECLS(iconv_std
);
60 _CITRUS_ICONV_DEF_OPS(iconv_std
);
63 /* ---------------------------------------------------------------------- */
66 _citrus_iconv_std_iconv_getops(struct _citrus_iconv_ops
*ops
, size_t lenops
,
67 u_int32_t expected_version
)
69 if (expected_version
<_CITRUS_ICONV_ABI_VERSION
|| lenops
<sizeof(*ops
))
72 memcpy(ops
, &_citrus_iconv_std_iconv_ops
,
73 sizeof(_citrus_iconv_std_iconv_ops
));
78 /* ---------------------------------------------------------------------- */
81 * convenience routines for stdenc.
84 save_encoding_state(struct _citrus_iconv_std_encoding
*se
)
87 memcpy(se
->se_pssaved
, se
->se_ps
,
88 _stdenc_get_state_size(se
->se_handle
));
92 restore_encoding_state(struct _citrus_iconv_std_encoding
*se
)
95 memcpy(se
->se_ps
, se
->se_pssaved
,
96 _stdenc_get_state_size(se
->se_handle
));
100 init_encoding_state(struct _citrus_iconv_std_encoding
*se
)
103 _stdenc_init_state(se
->se_handle
, se
->se_ps
);
107 mbtocsx(struct _citrus_iconv_std_encoding
*se
,
108 _csid_t
*csid
, _index_t
*idx
, const char **s
, size_t n
,
111 return _stdenc_mbtocs(se
->se_handle
, csid
, idx
, s
, n
, se
->se_ps
,
116 cstombx(struct _citrus_iconv_std_encoding
*se
,
117 char *s
, size_t n
, _csid_t csid
, _index_t idx
, size_t *nresult
)
119 return _stdenc_cstomb(se
->se_handle
, s
, n
, csid
, idx
, se
->se_ps
,
124 wctombx(struct _citrus_iconv_std_encoding
*se
,
125 char *s
, size_t n
, _wc_t wc
, size_t *nresult
)
127 return _stdenc_wctomb(se
->se_handle
, s
, n
, wc
, se
->se_ps
, nresult
);
131 put_state_resetx(struct _citrus_iconv_std_encoding
*se
,
132 char *s
, size_t n
, size_t *nresult
)
134 return _stdenc_put_state_reset(se
->se_handle
, s
, n
, se
->se_ps
, nresult
);
138 get_state_desc_gen(struct _citrus_iconv_std_encoding
*se
, int *rstate
)
141 struct _stdenc_state_desc ssd
;
143 ret
= _stdenc_get_state_desc(se
->se_handle
, se
->se_ps
,
144 _STDENC_SDID_GENERIC
, &ssd
);
146 *rstate
= ssd
.u
.generic
.state
;
152 * init encoding context
155 init_encoding(struct _citrus_iconv_std_encoding
*se
, struct _stdenc
*cs
,
156 void *ps1
, void *ps2
)
162 se
->se_pssaved
= ps2
;
165 ret
= _stdenc_init_state(cs
, se
->se_ps
);
166 if (!ret
&& se
->se_pssaved
)
167 ret
= _stdenc_init_state(cs
, se
->se_pssaved
);
173 open_csmapper(struct _csmapper
**rcm
, const char *src
, const char *dst
,
174 unsigned long *rnorm
)
177 struct _csmapper
*cm
;
179 ret
= _csmapper_open(&cm
, src
, dst
, 0, rnorm
);
182 if (_csmapper_get_src_max(cm
) != 1 || _csmapper_get_dst_max(cm
) != 1 ||
183 _csmapper_get_state_size(cm
) != 0) {
194 close_dsts(struct _citrus_iconv_std_dst_list
*dl
)
196 struct _citrus_iconv_std_dst
*sd
;
198 while ((sd
=TAILQ_FIRST(dl
)) != NULL
) {
199 TAILQ_REMOVE(dl
, sd
, sd_entry
);
200 _csmapper_close(sd
->sd_mapper
);
206 open_dsts(struct _citrus_iconv_std_dst_list
*dl
,
207 const struct _esdb_charset
*ec
, const struct _esdb
*dbdst
)
210 struct _citrus_iconv_std_dst
*sd
, *sdtmp
;
213 sd
= malloc(sizeof(*sd
));
217 for (i
=0; i
<dbdst
->db_num_charsets
; i
++) {
218 ret
= open_csmapper(&sd
->sd_mapper
, ec
->ec_csname
,
219 dbdst
->db_charsets
[i
].ec_csname
, &norm
);
221 sd
->sd_csid
= dbdst
->db_charsets
[i
].ec_csid
;
223 /* insert this mapper by sorted order. */
224 TAILQ_FOREACH(sdtmp
, dl
, sd_entry
) {
225 if (sdtmp
->sd_norm
> norm
) {
226 TAILQ_INSERT_BEFORE(sdtmp
, sd
,
233 TAILQ_INSERT_TAIL(dl
, sd
, sd_entry
);
234 sd
= malloc(sizeof(*sd
));
240 } else if (ret
!= ENOENT
) {
251 close_srcs(struct _citrus_iconv_std_src_list
*sl
)
253 struct _citrus_iconv_std_src
*ss
;
255 while ((ss
=TAILQ_FIRST(sl
)) != NULL
) {
256 TAILQ_REMOVE(sl
, ss
, ss_entry
);
257 close_dsts(&ss
->ss_dsts
);
263 open_srcs(struct _citrus_iconv_std_src_list
*sl
,
264 const struct _esdb
*dbsrc
, const struct _esdb
*dbdst
)
266 int i
, ret
, count
= 0;
267 struct _citrus_iconv_std_src
*ss
;
269 ss
= malloc(sizeof(*ss
));
273 TAILQ_INIT(&ss
->ss_dsts
);
275 for (i
=0; i
<dbsrc
->db_num_charsets
; i
++) {
276 ret
= open_dsts(&ss
->ss_dsts
, &dbsrc
->db_charsets
[i
], dbdst
);
279 if (!TAILQ_EMPTY(&ss
->ss_dsts
)) {
280 ss
->ss_csid
= dbsrc
->db_charsets
[i
].ec_csid
;
281 TAILQ_INSERT_TAIL(sl
, ss
, ss_entry
);
282 ss
= malloc(sizeof(*ss
));
288 TAILQ_INIT(&ss
->ss_dsts
);
293 return count
? 0 : ENOENT
;
301 /* do convert a character */
302 #define E_NO_CORRESPONDING_CHAR ENOENT /* XXX */
305 do_conv(const struct _citrus_iconv_std_shared
*is
,
306 struct _citrus_iconv_std_context
*sc
, _csid_t
*csid
, _index_t
*idx
)
310 struct _citrus_iconv_std_src
*ss
;
311 struct _citrus_iconv_std_dst
*sd
;
313 TAILQ_FOREACH(ss
, &is
->is_srcs
, ss_entry
) {
314 if (ss
->ss_csid
== *csid
) {
315 TAILQ_FOREACH(sd
, &ss
->ss_dsts
, sd_entry
) {
316 ret
= _csmapper_convert(sd
->sd_mapper
,
317 &tmpidx
, *idx
, NULL
);
319 case _MAPPER_CONVERT_SUCCESS
:
323 case _MAPPER_CONVERT_NONIDENTICAL
:
325 case _MAPPER_CONVERT_SRC_MORE
:
327 case _MAPPER_CONVERT_DST_MORE
:
329 case _MAPPER_CONVERT_FATAL
:
331 case _MAPPER_CONVERT_ILSEQ
:
339 return E_NO_CORRESPONDING_CHAR
;
341 /* ---------------------------------------------------------------------- */
345 _citrus_iconv_std_iconv_init_shared(struct _citrus_iconv_shared
*ci
,
346 const char * __restrict curdir
,
347 const char * __restrict src
,
348 const char * __restrict dst
,
349 const void * __restrict var
, size_t lenvar
)
352 struct _citrus_iconv_std_shared
*is
;
353 struct _citrus_esdb esdbsrc
, esdbdst
;
355 is
= malloc(sizeof(*is
));
360 ret
= _citrus_esdb_open(&esdbsrc
, src
);
363 ret
= _citrus_esdb_open(&esdbdst
, dst
);
366 ret
= _stdenc_open(&is
->is_src_encoding
, esdbsrc
.db_encname
,
367 esdbsrc
.db_variable
, esdbsrc
.db_len_variable
);
370 ret
= _stdenc_open(&is
->is_dst_encoding
, esdbdst
.db_encname
,
371 esdbdst
.db_variable
, esdbdst
.db_len_variable
);
374 is
->is_use_invalid
= esdbdst
.db_use_invalid
;
375 is
->is_invalid
= esdbdst
.db_invalid
;
377 TAILQ_INIT(&is
->is_srcs
);
378 ret
= open_srcs(&is
->is_srcs
, &esdbsrc
, &esdbdst
);
382 _esdb_close(&esdbsrc
);
383 _esdb_close(&esdbdst
);
389 _stdenc_close(is
->is_dst_encoding
);
391 _stdenc_close(is
->is_src_encoding
);
393 _esdb_close(&esdbdst
);
395 _esdb_close(&esdbsrc
);
403 _citrus_iconv_std_iconv_uninit_shared(struct _citrus_iconv_shared
*ci
)
405 struct _citrus_iconv_std_shared
*is
= ci
->ci_closure
;
410 _stdenc_close(is
->is_src_encoding
);
411 _stdenc_close(is
->is_dst_encoding
);
412 close_srcs(&is
->is_srcs
);
417 _citrus_iconv_std_iconv_init_context(struct _citrus_iconv
*cv
)
419 const struct _citrus_iconv_std_shared
*is
= cv
->cv_shared
->ci_closure
;
420 struct _citrus_iconv_std_context
*sc
;
421 size_t szpssrc
, szpsdst
, sz
;
424 szpssrc
= _stdenc_get_state_size(is
->is_src_encoding
);
425 szpsdst
= _stdenc_get_state_size(is
->is_dst_encoding
);
427 sz
= (szpssrc
+ szpsdst
)*2 + sizeof(struct _citrus_iconv_std_context
);
432 ptr
= (char *)&sc
[1];
434 init_encoding(&sc
->sc_src_encoding
, is
->is_src_encoding
,
437 init_encoding(&sc
->sc_src_encoding
, is
->is_src_encoding
,
441 init_encoding(&sc
->sc_dst_encoding
, is
->is_dst_encoding
,
444 init_encoding(&sc
->sc_dst_encoding
, is
->is_dst_encoding
,
447 cv
->cv_closure
= (void *)sc
;
453 _citrus_iconv_std_iconv_uninit_context(struct _citrus_iconv
*cv
)
455 free(cv
->cv_closure
);
459 _citrus_iconv_std_iconv_convert(struct _citrus_iconv
* __restrict cv
,
460 const char * __restrict
* __restrict in
,
461 size_t * __restrict inbytes
,
462 char * __restrict
* __restrict out
,
463 size_t * __restrict outbytes
, u_int32_t flags
,
464 size_t * __restrict invalids
)
466 const struct _citrus_iconv_std_shared
*is
= cv
->cv_shared
->ci_closure
;
467 struct _citrus_iconv_std_context
*sc
= cv
->cv_closure
;
471 size_t szrin
, szrout
;
476 if (in
==NULL
|| *in
==NULL
) {
478 if (out
!=NULL
&& *out
!=NULL
) {
479 /* init output state and store the shift sequence */
480 save_encoding_state(&sc
->sc_src_encoding
);
481 save_encoding_state(&sc
->sc_dst_encoding
);
484 ret
= put_state_resetx(&sc
->sc_dst_encoding
,
490 if (szrout
== (size_t)-2) {
491 /* too small to store the character */
498 /* otherwise, discard the shift sequence */
499 init_encoding_state(&sc
->sc_dst_encoding
);
500 init_encoding_state(&sc
->sc_src_encoding
);
508 ret
= get_state_desc_gen(&sc
->sc_src_encoding
, &state
);
509 if (state
== _STDENC_SDGEN_INITIAL
||
510 state
== _STDENC_SDGEN_STABLE
)
514 /* save the encoding states for the error recovery */
515 save_encoding_state(&sc
->sc_src_encoding
);
516 save_encoding_state(&sc
->sc_dst_encoding
);
518 /* mb -> csid/index */
521 ret
= mbtocsx(&sc
->sc_src_encoding
, &csid
, &idx
,
522 &tmpin
, *inbytes
, &szrin
);
526 if (szrin
== (size_t)-2) {
527 /* incompleted character */
528 ret
= get_state_desc_gen(&sc
->sc_src_encoding
, &state
);
534 case _STDENC_SDGEN_INITIAL
:
535 case _STDENC_SDGEN_STABLE
:
536 /* fetch shift sequences only. */
542 /* convert the character */
543 ret
= do_conv(is
, sc
, &csid
, &idx
);
545 if (ret
== E_NO_CORRESPONDING_CHAR
) {
548 if ((flags
&_CITRUS_ICONV_F_HIDE_INVALID
)==0 &&
549 is
->is_use_invalid
) {
550 ret
= wctombx(&sc
->sc_dst_encoding
,
562 /* csid/index -> mb */
563 ret
= cstombx(&sc
->sc_dst_encoding
,
564 *out
, *outbytes
, csid
, idx
, &szrout
);
568 _DIAGASSERT(*inbytes
>=szrin
&& *outbytes
>=szrout
);
569 *inbytes
-= tmpin
-*in
; /* szrin is insufficient on \0. */
579 restore_encoding_state(&sc
->sc_src_encoding
);
580 restore_encoding_state(&sc
->sc_dst_encoding
);