2 * Copyright (c) 1997-2002, Index Data
3 * See the file LICENSE for details.
5 * $Id: siconv.c,v 1.1 2002-08-27 14:02:13 adam Exp $
20 #include <yaz/yaz-util.h>
22 struct yaz_iconv_struct {
24 unsigned long (*read_handle)(yaz_iconv_t cd, char **inbuf,
26 size_t (*write_handle)(yaz_iconv_t cd, unsigned long x,
27 char **outbuf, size_t *outbytesleft);
34 static unsigned long yaz_read_ISO8859_1 (yaz_iconv_t cd,
35 char **inbuf, size_t *inbytesleft)
37 unsigned char *inp = *inbuf;
46 static unsigned long yaz_read_UTF8 (yaz_iconv_t cd,
47 char **inbuf, size_t *inbytesleft)
49 unsigned char *inp = *inbuf;
58 else if (inp[0] <= 0xdf && *inbytesleft >= 2)
60 x = ((inp[0] & 0x1f) << 6) + (inp[1] & 0x3f);
65 else if (inp[0] <= 0xef && *inbytesleft >= 3)
67 x = ((inp[0] & 0x0f) << 12) +
68 ((inp[1] & 0x3f) << 6) + (inp[1] & 0x3f);
73 else if (inp[0] <= 0xef && *inbytesleft >= 4)
75 x = ((inp[0] & 0x07) << 18) +
76 ((inp[1] & 0x3f) << 12) + ((inp[2] & 0x3f) << 6) +
84 cd->my_errno = YAZ_ICONV_EINVAL;
90 static unsigned long yaz_read_UCS4 (yaz_iconv_t cd,
91 char **inbuf, size_t *inbytesleft)
93 unsigned char *inp = *inbuf;
98 cd->my_errno = YAZ_ICONV_EINVAL; /* incomplete input */
101 memcpy (&x, inp, sizeof(x));
108 static size_t yaz_write_UTF8 (yaz_iconv_t cd, unsigned long x,
109 char **outbuf, size_t *outbytesleft)
111 unsigned char *outp = *outbuf;
112 if (x <= 0x7f && *outbytesleft >= 1)
117 else if (x <= 0x7ff && *outbytesleft >= 2)
119 *outp++ = (x >> 6) | 0xc0;
120 *outp++ = (x & 0x3f) | 0x80;
121 (*outbytesleft) -= 2;
123 else if (x <= 0xffff && *outbytesleft >= 3)
125 *outp++ = (x >> 12) | 0xe0;
126 *outp++ = ((x >> 6) & 0x3f) | 0x80;
127 *outp++ = (x & 0x3f) | 0x80;
128 (*outbytesleft) -= 3;
130 else if (x <= 0x1fffff && *outbytesleft >= 4)
132 *outp++ = (x >> 18) | 0xf0;
133 *outp++ = ((x >> 12) & 0x3f) | 0x80;
134 *outp++ = ((x >> 6) & 0x3f) | 0x80;
135 *outp++ = (x & 0x3f) | 0x80;
136 (*outbytesleft) -= 4;
138 else if (x > 0x1fffff)
140 cd->my_errno = YAZ_ICONV_EILSEQ; /* invalid sequence */
145 cd->my_errno = YAZ_ICONV_E2BIG; /* not room for output */
152 static size_t yaz_write_ISO8859_1 (yaz_iconv_t cd, unsigned long x,
153 char **outbuf, size_t *outbytesleft)
155 unsigned char *outp = *outbuf;
156 if (x > 255 || x < 1)
158 cd->my_errno = YAZ_ICONV_EILSEQ;
161 else if (*outbytesleft >= 1)
168 cd->my_errno = YAZ_ICONV_E2BIG;
176 static size_t yaz_write_UCS4 (yaz_iconv_t cd, unsigned long x,
177 char **outbuf, size_t *outbytesleft)
179 unsigned char *outp = *outbuf;
180 if (x < 1 || x > 0x1fffff)
182 cd->my_errno = YAZ_ICONV_EILSEQ;
185 else if (*outbytesleft >= 4)
187 memcpy (outp, &x, sizeof(x));
189 (*outbytesleft) -= 4;
193 cd->my_errno = YAZ_ICONV_E2BIG;
200 yaz_iconv_t yaz_iconv_open (const char *tocode, const char *fromcode)
202 yaz_iconv_t cd = xmalloc (sizeof(*cd));
204 cd->write_handle = 0;
206 cd->my_errno = YAZ_ICONV_UNKNOWN;
208 if (!strcmp(fromcode, "UTF-8"))
209 cd->read_handle = yaz_read_UTF8;
210 else if (!strcmp(fromcode, "ISO-8859-1"))
211 cd->read_handle = yaz_read_ISO8859_1;
212 else if (!strcmp(fromcode, "UCS-4"))
213 cd->read_handle = yaz_read_UCS4;
216 if (!strcmp(tocode, "UTF-8"))
217 cd->write_handle = yaz_write_UTF8;
218 else if (!strcmp (tocode, "ISO-8859-1"))
219 cd->write_handle = yaz_write_ISO8859_1;
220 else if (!strcmp (tocode, "UCS-4"))
221 cd->write_handle = yaz_write_UCS4;
225 if (!cd->read_handle || !cd->write_handle)
227 cd->iconv_cd = iconv_open (tocode, fromcode);
228 if (cd->iconv_cd == (iconv_t) (-1))
235 if (!cd->to_UCS4 || !cd->from_UCS4)
244 size_t yaz_iconv (yaz_iconv_t cd, char **inbuf, size_t *inbytesleft,
245 char **outbuf, size_t *outbytesleft)
253 iconv(cd->iconv_cd, inbuf, inbytesleft, outbuf, outbytesleft);
254 if (r == (size_t)(-1))
259 cd->my_errno = YAZ_ICONV_E2BIG;
262 cd->my_errno = YAZ_ICONV_EINVAL;
265 cd->my_errno = YAZ_ICONV_EILSEQ;
268 cd->my_errno = YAZ_ICONV_UNKNOWN;
274 if (inbuf == 0 || *inbuf == 0)
281 if (*inbytesleft == 0)
287 x = (cd->read_handle)(cd, inbuf, inbytesleft);
293 r = (cd->write_handle)(cd, x, outbuf, outbytesleft);
300 int yaz_iconv_error (yaz_iconv_t cd)
305 int yaz_iconv_close (yaz_iconv_t cd)
309 iconv_close (cd->iconv_cd);