1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2013 Index Data
3 * See the file LICENSE for details.
7 * \brief Implements simple ICONV
9 * This implements an interface similar to that of iconv and
10 * is used by YAZ to interface with iconv (if present).
11 * For systems where iconv is not present, this layer
12 * provides a few important conversions: UTF-8, MARC-8, Latin-1.
28 #include <yaz/xmalloc.h>
29 #include <yaz/errno.h>
32 struct yaz_iconv_struct {
36 size_t (*init_handle)(yaz_iconv_t cd, unsigned char *inbuf,
37 size_t inbytesleft, size_t *no_read);
38 unsigned long (*read_handle)(yaz_iconv_t cd, unsigned char *inbuf,
39 size_t inbytesleft, size_t *no_read);
42 unsigned long unget_x;
46 struct yaz_iconv_encoder_s encoder;
47 struct yaz_iconv_decoder_s decoder;
51 int yaz_iconv_isbuiltin(yaz_iconv_t cd)
53 return cd->decoder.read_handle && cd->encoder.write_handle;
57 static int prepare_encoders(yaz_iconv_t cd, const char *tocode)
59 if (yaz_marc8_encoder(tocode, &cd->encoder))
61 if (yaz_utf8_encoder(tocode, &cd->encoder))
63 if (yaz_ucs4_encoder(tocode, &cd->encoder))
65 if (yaz_iso_8859_1_encoder(tocode, &cd->encoder))
67 if (yaz_iso_5428_encoder(tocode, &cd->encoder))
69 if (yaz_advancegreek_encoder(tocode, &cd->encoder))
71 if (yaz_wchar_encoder(tocode, &cd->encoder))
76 static int prepare_decoders(yaz_iconv_t cd, const char *tocode)
78 if (yaz_marc8_decoder(tocode, &cd->decoder))
80 if (yaz_iso5426_decoder(tocode, &cd->decoder))
82 if (yaz_utf8_decoder(tocode, &cd->decoder))
84 if (yaz_ucs4_decoder(tocode, &cd->decoder))
86 if (yaz_iso_8859_1_decoder(tocode, &cd->decoder))
88 if (yaz_iso_5428_decoder(tocode, &cd->decoder))
90 if (yaz_advancegreek_decoder(tocode, &cd->decoder))
92 if (yaz_wchar_decoder(tocode, &cd->decoder))
94 if (yaz_danmarc_decoder(tocode, &cd->decoder))
99 yaz_iconv_t yaz_iconv_open(const char *tocode, const char *fromcode)
101 yaz_iconv_t cd = (yaz_iconv_t) xmalloc(sizeof(*cd));
103 cd->encoder.data = 0;
104 cd->encoder.write_handle = 0;
105 cd->encoder.flush_handle = 0;
106 cd->encoder.init_handle = 0;
107 cd->encoder.destroy_handle = 0;
109 cd->decoder.data = 0;
110 cd->decoder.read_handle = 0;
111 cd->decoder.init_handle = 0;
112 cd->decoder.destroy_handle = 0;
114 cd->my_errno = YAZ_ICONV_UNKNOWN;
116 /* a useful hack: if fromcode has leading @,
117 the library not use YAZ's own conversions .. */
118 if (fromcode[0] == '@')
122 prepare_encoders(cd, tocode);
123 prepare_decoders(cd, fromcode);
125 if (cd->decoder.read_handle && cd->encoder.write_handle)
128 cd->iconv_cd = (iconv_t) (-1);
135 cd->iconv_cd = iconv_open(tocode, fromcode);
136 if (cd->iconv_cd == (iconv_t) (-1))
150 size_t yaz_iconv(yaz_iconv_t cd, char **inbuf, size_t *inbytesleft,
151 char **outbuf, size_t *outbytesleft)
157 if (cd->iconv_cd != (iconv_t) (-1))
160 iconv(cd->iconv_cd, inbuf, inbytesleft, outbuf, outbytesleft);
161 if (r == (size_t)(-1))
166 cd->my_errno = YAZ_ICONV_E2BIG;
169 cd->my_errno = YAZ_ICONV_EINVAL;
172 cd->my_errno = YAZ_ICONV_EILSEQ;
175 cd->my_errno = YAZ_ICONV_UNKNOWN;
187 cd->my_errno = YAZ_ICONV_UNKNOWN;
189 if (cd->encoder.init_handle)
190 (*cd->encoder.init_handle)(&cd->encoder);
195 if (cd->decoder.init_handle)
198 size_t r = (cd->decoder.init_handle)(
200 inbuf ? (unsigned char *) *inbuf : 0,
201 inbytesleft ? *inbytesleft : 0,
205 if (cd->my_errno == YAZ_ICONV_EINVAL)
211 *inbytesleft -= no_read;
218 if (!inbuf || !*inbuf)
220 if (outbuf && *outbuf)
223 r = (*cd->encoder.write_handle)(cd, &cd->encoder,
224 cd->unget_x, outbuf, outbytesleft);
225 if (cd->encoder.flush_handle)
226 r = (*cd->encoder.flush_handle)(cd, &cd->encoder,
227 outbuf, outbytesleft);
242 no_read = cd->no_read_x;
246 if (*inbytesleft == 0)
251 x = (*cd->decoder.read_handle)(
253 (unsigned char *) *inbuf, *inbytesleft, &no_read);
262 r = (*cd->encoder.write_handle)(cd, &cd->encoder,
263 x, outbuf, outbytesleft);
266 /* unable to write it. save it because read_handle cannot
268 if (cd->my_errno == YAZ_ICONV_E2BIG)
271 cd->no_read_x = no_read;
277 *inbytesleft -= no_read;
283 int yaz_iconv_error(yaz_iconv_t cd)
288 int yaz_iconv_close(yaz_iconv_t cd)
291 if (cd->iconv_cd != (iconv_t) (-1))
292 iconv_close(cd->iconv_cd);
294 if (cd->encoder.destroy_handle)
295 (*cd->encoder.destroy_handle)(&cd->encoder);
296 if (cd->decoder.destroy_handle)
297 (*cd->decoder.destroy_handle)(&cd->decoder);
302 void yaz_iconv_set_errno(yaz_iconv_t cd, int no)
310 * c-file-style: "Stroustrup"
311 * indent-tabs-mode: nil
313 * vim: shiftwidth=4 tabstop=8 expandtab