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