1 /* $NetBSD: citrus_iconv_std.c,v 1.15 2006/11/13 19:08:19 tnozaki Exp $ */
2 /* $DragonFly: src/lib/libc/citrus/modules/citrus_iconv_std.c,v 1.2 2008/04/10 10:21:01 hasso 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 get_state_desc_gen(struct _citrus_iconv_std_encoding
*se
, int *rstate
)
138 struct _stdenc_state_desc ssd
;
140 ret
= _stdenc_get_state_desc(se
->se_handle
, se
->se_ps
,
141 _STDENC_SDID_GENERIC
, &ssd
);
143 *rstate
= ssd
.u
.generic
.state
;
149 * init encoding context
152 init_encoding(struct _citrus_iconv_std_encoding
*se
, struct _stdenc
*cs
,
153 void *ps1
, void *ps2
)
159 se
->se_pssaved
= ps2
;
162 ret
= _stdenc_init_state(cs
, se
->se_ps
);
163 if (!ret
&& se
->se_pssaved
)
164 ret
= _stdenc_init_state(cs
, se
->se_pssaved
);
170 open_csmapper(struct _csmapper
**rcm
, const char *src
, const char *dst
,
171 unsigned long *rnorm
)
174 struct _csmapper
*cm
;
176 ret
= _csmapper_open(&cm
, src
, dst
, 0, rnorm
);
179 if (_csmapper_get_src_max(cm
) != 1 || _csmapper_get_dst_max(cm
) != 1 ||
180 _csmapper_get_state_size(cm
) != 0) {
191 close_dsts(struct _citrus_iconv_std_dst_list
*dl
)
193 struct _citrus_iconv_std_dst
*sd
;
195 while ((sd
=TAILQ_FIRST(dl
)) != NULL
) {
196 TAILQ_REMOVE(dl
, sd
, sd_entry
);
197 _csmapper_close(sd
->sd_mapper
);
203 open_dsts(struct _citrus_iconv_std_dst_list
*dl
,
204 const struct _esdb_charset
*ec
, const struct _esdb
*dbdst
)
207 struct _citrus_iconv_std_dst
*sd
, *sdtmp
;
210 sd
= malloc(sizeof(*sd
));
214 for (i
=0; i
<dbdst
->db_num_charsets
; i
++) {
215 ret
= open_csmapper(&sd
->sd_mapper
, ec
->ec_csname
,
216 dbdst
->db_charsets
[i
].ec_csname
, &norm
);
218 sd
->sd_csid
= dbdst
->db_charsets
[i
].ec_csid
;
220 /* insert this mapper by sorted order. */
221 TAILQ_FOREACH(sdtmp
, dl
, sd_entry
) {
222 if (sdtmp
->sd_norm
> norm
) {
223 TAILQ_INSERT_BEFORE(sdtmp
, sd
,
230 TAILQ_INSERT_TAIL(dl
, sd
, sd_entry
);
231 sd
= malloc(sizeof(*sd
));
237 } else if (ret
!= ENOENT
) {
248 close_srcs(struct _citrus_iconv_std_src_list
*sl
)
250 struct _citrus_iconv_std_src
*ss
;
252 while ((ss
=TAILQ_FIRST(sl
)) != NULL
) {
253 TAILQ_REMOVE(sl
, ss
, ss_entry
);
254 close_dsts(&ss
->ss_dsts
);
260 open_srcs(struct _citrus_iconv_std_src_list
*sl
,
261 const struct _esdb
*dbsrc
, const struct _esdb
*dbdst
)
263 int i
, ret
, count
= 0;
264 struct _citrus_iconv_std_src
*ss
;
266 ss
= malloc(sizeof(*ss
));
270 TAILQ_INIT(&ss
->ss_dsts
);
272 for (i
=0; i
<dbsrc
->db_num_charsets
; i
++) {
273 ret
= open_dsts(&ss
->ss_dsts
, &dbsrc
->db_charsets
[i
], dbdst
);
276 if (!TAILQ_EMPTY(&ss
->ss_dsts
)) {
277 ss
->ss_csid
= dbsrc
->db_charsets
[i
].ec_csid
;
278 TAILQ_INSERT_TAIL(sl
, ss
, ss_entry
);
279 ss
= malloc(sizeof(*ss
));
285 TAILQ_INIT(&ss
->ss_dsts
);
290 return count
? 0 : ENOENT
;
298 /* do convert a character */
299 #define E_NO_CORRESPONDING_CHAR ENOENT /* XXX */
302 do_conv(const struct _citrus_iconv_std_shared
*is
,
303 struct _citrus_iconv_std_context
*sc
, _csid_t
*csid
, _index_t
*idx
)
307 struct _citrus_iconv_std_src
*ss
;
308 struct _citrus_iconv_std_dst
*sd
;
310 TAILQ_FOREACH(ss
, &is
->is_srcs
, ss_entry
) {
311 if (ss
->ss_csid
== *csid
) {
312 TAILQ_FOREACH(sd
, &ss
->ss_dsts
, sd_entry
) {
313 ret
= _csmapper_convert(sd
->sd_mapper
,
314 &tmpidx
, *idx
, NULL
);
316 case _MAPPER_CONVERT_SUCCESS
:
320 case _MAPPER_CONVERT_NONIDENTICAL
:
322 case _MAPPER_CONVERT_SRC_MORE
:
324 case _MAPPER_CONVERT_DST_MORE
:
326 case _MAPPER_CONVERT_FATAL
:
328 case _MAPPER_CONVERT_ILSEQ
:
336 return E_NO_CORRESPONDING_CHAR
;
338 /* ---------------------------------------------------------------------- */
342 _citrus_iconv_std_iconv_init_shared(struct _citrus_iconv_shared
*ci
,
343 const char * __restrict curdir
,
344 const char * __restrict src
,
345 const char * __restrict dst
,
346 const void * __restrict var
, size_t lenvar
)
349 struct _citrus_iconv_std_shared
*is
;
350 struct _citrus_esdb esdbsrc
, esdbdst
;
352 is
= malloc(sizeof(*is
));
357 ret
= _citrus_esdb_open(&esdbsrc
, src
);
360 ret
= _citrus_esdb_open(&esdbdst
, dst
);
363 ret
= _stdenc_open(&is
->is_src_encoding
, esdbsrc
.db_encname
,
364 esdbsrc
.db_variable
, esdbsrc
.db_len_variable
);
367 ret
= _stdenc_open(&is
->is_dst_encoding
, esdbdst
.db_encname
,
368 esdbdst
.db_variable
, esdbdst
.db_len_variable
);
371 is
->is_use_invalid
= esdbdst
.db_use_invalid
;
372 is
->is_invalid
= esdbdst
.db_invalid
;
374 TAILQ_INIT(&is
->is_srcs
);
375 ret
= open_srcs(&is
->is_srcs
, &esdbsrc
, &esdbdst
);
379 _esdb_close(&esdbsrc
);
380 _esdb_close(&esdbdst
);
386 _stdenc_close(is
->is_dst_encoding
);
388 _stdenc_close(is
->is_src_encoding
);
390 _esdb_close(&esdbdst
);
392 _esdb_close(&esdbsrc
);
400 _citrus_iconv_std_iconv_uninit_shared(struct _citrus_iconv_shared
*ci
)
402 struct _citrus_iconv_std_shared
*is
= ci
->ci_closure
;
407 _stdenc_close(is
->is_src_encoding
);
408 _stdenc_close(is
->is_dst_encoding
);
409 close_srcs(&is
->is_srcs
);
414 _citrus_iconv_std_iconv_init_context(struct _citrus_iconv
*cv
)
416 const struct _citrus_iconv_std_shared
*is
= cv
->cv_shared
->ci_closure
;
417 struct _citrus_iconv_std_context
*sc
;
419 size_t szpssrc
, szpsdst
, sz
;
422 szpssrc
= _stdenc_get_state_size(is
->is_src_encoding
);
423 szpsdst
= _stdenc_get_state_size(is
->is_dst_encoding
);
425 sz
= (szpssrc
+ szpsdst
)*2 + sizeof(struct _citrus_iconv_std_context
);
430 ptr
= (char *)&sc
[1];
432 init_encoding(&sc
->sc_src_encoding
, is
->is_src_encoding
,
435 init_encoding(&sc
->sc_src_encoding
, is
->is_src_encoding
,
439 init_encoding(&sc
->sc_dst_encoding
, is
->is_dst_encoding
,
442 init_encoding(&sc
->sc_dst_encoding
, is
->is_dst_encoding
,
445 cv
->cv_closure
= (void *)sc
;
451 _citrus_iconv_std_iconv_uninit_context(struct _citrus_iconv
*cv
)
453 free(cv
->cv_closure
);
457 _citrus_iconv_std_iconv_convert(struct _citrus_iconv
* __restrict cv
,
458 const char * __restrict
* __restrict in
,
459 size_t * __restrict inbytes
,
460 char * __restrict
* __restrict out
,
461 size_t * __restrict outbytes
, u_int32_t flags
,
462 size_t * __restrict invalids
)
464 const struct _citrus_iconv_std_shared
*is
= cv
->cv_shared
->ci_closure
;
465 struct _citrus_iconv_std_context
*sc
= cv
->cv_closure
;
469 size_t szrin
, szrout
;
474 if (in
==NULL
|| *in
==NULL
) {
476 if (out
!=NULL
&& *out
!=NULL
) {
477 /* init output state and store the shift sequence */
478 save_encoding_state(&sc
->sc_src_encoding
);
479 save_encoding_state(&sc
->sc_dst_encoding
);
482 ret
= put_state_resetx(&sc
->sc_dst_encoding
,
488 if (szrout
== (size_t)-2) {
489 /* too small to store the character */
496 /* otherwise, discard the shift sequence */
497 init_encoding_state(&sc
->sc_dst_encoding
);
498 init_encoding_state(&sc
->sc_src_encoding
);
506 ret
= get_state_desc_gen(&sc
->sc_src_encoding
, &state
);
507 if (state
== _STDENC_SDGEN_INITIAL
||
508 state
== _STDENC_SDGEN_STABLE
)
512 /* save the encoding states for the error recovery */
513 save_encoding_state(&sc
->sc_src_encoding
);
514 save_encoding_state(&sc
->sc_dst_encoding
);
516 /* mb -> csid/index */
519 ret
= mbtocsx(&sc
->sc_src_encoding
, &csid
, &idx
,
520 &tmpin
, *inbytes
, &szrin
);
524 if (szrin
== (size_t)-2) {
525 /* incompleted character */
526 ret
= get_state_desc_gen(&sc
->sc_src_encoding
, &state
);
532 case _STDENC_SDGEN_INITIAL
:
533 case _STDENC_SDGEN_STABLE
:
534 /* fetch shift sequences only. */
540 /* convert the character */
541 ret
= do_conv(is
, sc
, &csid
, &idx
);
543 if (ret
== E_NO_CORRESPONDING_CHAR
) {
546 if ((flags
&_CITRUS_ICONV_F_HIDE_INVALID
)==0 &&
547 is
->is_use_invalid
) {
548 ret
= wctombx(&sc
->sc_dst_encoding
,
560 /* csid/index -> mb */
561 ret
= cstombx(&sc
->sc_dst_encoding
,
562 *out
, *outbytes
, csid
, idx
, &szrout
);
566 _DIAGASSERT(*inbytes
>=szrin
&& *outbytes
>=szrout
);
567 *inbytes
-= tmpin
-*in
; /* szrin is insufficient on \0. */
577 restore_encoding_state(&sc
->sc_src_encoding
);
578 restore_encoding_state(&sc
->sc_dst_encoding
);