2 * Copyright (C) 1995-2005, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: siconv.c,v 1.17 2006-02-10 12:45:39 adam Exp $
9 * \brief Implements simple ICONV
11 * This implements an interface similar to that of iconv and
12 * is used by YAZ to interface with iconv (if present).
13 * For systems where iconv is not present, this layer
14 * provides a few important conversion: UTF-8, MARC-8, Latin-1.
32 #include <yaz/yaz-util.h>
34 unsigned long yaz_marc8_1_conv (unsigned char *inp, size_t inbytesleft,
35 size_t *no_read, int *combining);
36 unsigned long yaz_marc8_2_conv (unsigned char *inp, size_t inbytesleft,
37 size_t *no_read, int *combining);
38 unsigned long yaz_marc8_3_conv (unsigned char *inp, size_t inbytesleft,
39 size_t *no_read, int *combining);
40 unsigned long yaz_marc8_4_conv (unsigned char *inp, size_t inbytesleft,
41 size_t *no_read, int *combining);
42 unsigned long yaz_marc8_5_conv (unsigned char *inp, size_t inbytesleft,
43 size_t *no_read, int *combining);
44 unsigned long yaz_marc8_6_conv (unsigned char *inp, size_t inbytesleft,
45 size_t *no_read, int *combining);
46 unsigned long yaz_marc8_7_conv (unsigned char *inp, size_t inbytesleft,
47 size_t *no_read, int *combining);
48 unsigned long yaz_marc8_8_conv (unsigned char *inp, size_t inbytesleft,
49 size_t *no_read, int *combining);
50 unsigned long yaz_marc8_9_conv (unsigned char *inp, size_t inbytesleft,
51 size_t *no_read, int *combining);
53 struct yaz_iconv_struct {
56 size_t (*init_handle)(yaz_iconv_t cd, unsigned char *inbuf,
57 size_t inbytesleft, size_t *no_read);
58 unsigned long (*read_handle)(yaz_iconv_t cd, unsigned char *inbuf,
59 size_t inbytesleft, size_t *no_read);
60 size_t (*write_handle)(yaz_iconv_t cd, unsigned long x,
61 char **outbuf, size_t *outbytesleft,
67 unsigned long comb_x[8];
68 size_t comb_no_read[8];
70 unsigned long unget_x;
74 unsigned long compose_char;
77 static unsigned long yaz_read_ISO8859_1 (yaz_iconv_t cd, unsigned char *inp,
78 size_t inbytesleft, size_t *no_read)
80 unsigned long x = inp[0];
85 static size_t yaz_init_UTF8 (yaz_iconv_t cd, unsigned char *inp,
86 size_t inbytesleft, size_t *no_read)
95 cd->my_errno = YAZ_ICONV_EINVAL;
98 if (inp[1] != 0xbb || inp[2] != 0xbf)
100 cd->my_errno = YAZ_ICONV_EILSEQ;
107 static unsigned long yaz_read_UTF8 (yaz_iconv_t cd, unsigned char *inp,
108 size_t inbytesleft, size_t *no_read)
117 else if (inp[0] <= 0xbf || inp[0] >= 0xfe)
120 cd->my_errno = YAZ_ICONV_EILSEQ;
122 else if (inp[0] <= 0xdf && inbytesleft >= 2)
124 x = ((inp[0] & 0x1f) << 6) | (inp[1] & 0x3f);
130 cd->my_errno = YAZ_ICONV_EILSEQ;
133 else if (inp[0] <= 0xef && inbytesleft >= 3)
135 x = ((inp[0] & 0x0f) << 12) | ((inp[1] & 0x3f) << 6) |
142 cd->my_errno = YAZ_ICONV_EILSEQ;
145 else if (inp[0] <= 0xf7 && inbytesleft >= 4)
147 x = ((inp[0] & 0x07) << 18) | ((inp[1] & 0x3f) << 12) |
148 ((inp[2] & 0x3f) << 6) | (inp[3] & 0x3f);
154 cd->my_errno = YAZ_ICONV_EILSEQ;
157 else if (inp[0] <= 0xfb && inbytesleft >= 5)
159 x = ((inp[0] & 0x03) << 24) | ((inp[1] & 0x3f) << 18) |
160 ((inp[2] & 0x3f) << 12) | ((inp[3] & 0x3f) << 6) |
167 cd->my_errno = YAZ_ICONV_EILSEQ;
170 else if (inp[0] <= 0xfd && inbytesleft >= 6)
172 x = ((inp[0] & 0x01) << 30) | ((inp[1] & 0x3f) << 24) |
173 ((inp[2] & 0x3f) << 18) | ((inp[3] & 0x3f) << 12) |
174 ((inp[4] & 0x3f) << 6) | (inp[5] & 0x3f);
180 cd->my_errno = YAZ_ICONV_EILSEQ;
186 cd->my_errno = YAZ_ICONV_EINVAL;
191 static unsigned long yaz_read_UCS4 (yaz_iconv_t cd, unsigned char *inp,
192 size_t inbytesleft, size_t *no_read)
198 cd->my_errno = YAZ_ICONV_EINVAL; /* incomplete input */
203 x = (inp[0]<<24) | (inp[1]<<16) | (inp[2]<<8) | inp[3];
209 static unsigned long yaz_read_UCS4LE (yaz_iconv_t cd, unsigned char *inp,
210 size_t inbytesleft, size_t *no_read)
216 cd->my_errno = YAZ_ICONV_EINVAL; /* incomplete input */
221 x = (inp[3]<<24) | (inp[2]<<16) | (inp[1]<<8) | inp[0];
228 static unsigned long yaz_read_wchar_t (yaz_iconv_t cd, unsigned char *inp,
229 size_t inbytesleft, size_t *no_read)
233 if (inbytesleft < sizeof(wchar_t))
235 cd->my_errno = YAZ_ICONV_EINVAL; /* incomplete input */
241 memcpy (&wch, inp, sizeof(wch));
243 *no_read = sizeof(wch);
250 static unsigned long yaz_read_marc8_comb (yaz_iconv_t cd, unsigned char *inp,
251 size_t inbytesleft, size_t *no_read,
254 static unsigned long yaz_read_marc8 (yaz_iconv_t cd, unsigned char *inp,
255 size_t inbytesleft, size_t *no_read)
258 if (cd->comb_offset < cd->comb_size)
260 *no_read = cd->comb_no_read[cd->comb_offset];
261 x = cd->comb_x[cd->comb_offset];
263 /* special case for double-diacritic combining characters,
264 INVERTED BREVE and DOUBLE TILDE.
265 We'll increment the no_read counter by 1, since we want to skip over
266 the processing of the closing ligature character
268 /* this code is no longer necessary.. our handlers code in
269 yaz_marc8_?_conv (generated by charconv.tcl) now returns
270 0 and no_read=1 when a sequence does not match the input.
271 The SECOND HALFs in codetables.xml produces a non-existant
272 entry in the conversion trie.. Hence when met, the input byte is
273 skipped as it should (in yaz_iconv)
276 if (x == 0x0361 || x == 0x0360)
284 for (cd->comb_size = 0; cd->comb_size < 8; cd->comb_size++)
287 x = yaz_read_marc8_comb(cd, inp, inbytesleft, no_read, &comb);
290 cd->comb_x[cd->comb_size] = x;
291 cd->comb_no_read[cd->comb_size] = *no_read;
293 inbytesleft = inbytesleft - *no_read;
298 static unsigned long yaz_read_marc8_comb (yaz_iconv_t cd, unsigned char *inp,
299 size_t inbytesleft, size_t *no_read,
303 while(inbytesleft >= 1 && inp[0] == 27)
305 size_t inbytesleft0 = inbytesleft;
308 while(inbytesleft > 0 && strchr("(,$!", *inp))
313 if (inbytesleft <= 0)
316 cd->my_errno = YAZ_ICONV_EINVAL;
319 cd->marc8_esc_mode = *inp++;
321 (*no_read) += inbytesleft0 - inbytesleft;
323 if (inbytesleft <= 0)
328 size_t no_read_sub = 0;
331 switch(cd->marc8_esc_mode)
333 case 'B': /* Basic ASCII */
334 case 'E': /* ANSEL */
335 case 's': /* ASCII */
336 x = yaz_marc8_1_conv(inp, inbytesleft, &no_read_sub, comb);
338 case 'g': /* Greek */
339 x = yaz_marc8_2_conv(inp, inbytesleft, &no_read_sub, comb);
341 case 'b': /* Subscripts */
342 x = yaz_marc8_3_conv(inp, inbytesleft, &no_read_sub, comb);
344 case 'p': /* Superscripts */
345 x = yaz_marc8_4_conv(inp, inbytesleft, &no_read_sub, comb);
347 case '2': /* Basic Hebrew */
348 x = yaz_marc8_5_conv(inp, inbytesleft, &no_read_sub, comb);
350 case 'N': /* Basic Cyrillic */
351 case 'Q': /* Extended Cyrillic */
352 x = yaz_marc8_6_conv(inp, inbytesleft, &no_read_sub, comb);
354 case '3': /* Basic Arabic */
355 case '4': /* Extended Arabic */
356 x = yaz_marc8_7_conv(inp, inbytesleft, &no_read_sub, comb);
358 case 'S': /* Greek */
359 x = yaz_marc8_8_conv(inp, inbytesleft, &no_read_sub, comb);
361 case '1': /* Chinese, Japanese, Korean (EACC) */
362 x = yaz_marc8_9_conv(inp, inbytesleft, &no_read_sub, comb);
366 cd->my_errno = YAZ_ICONV_EILSEQ;
369 *no_read += no_read_sub;
374 static size_t yaz_write_UTF8 (yaz_iconv_t cd, unsigned long x,
375 char **outbuf, size_t *outbytesleft,
378 unsigned char *outp = (unsigned char *) *outbuf;
379 if (x <= 0x7f && *outbytesleft >= 1)
381 *outp++ = (unsigned char) x;
384 else if (x <= 0x7ff && *outbytesleft >= 2)
386 *outp++ = (unsigned char) ((x >> 6) | 0xc0);
387 *outp++ = (unsigned char) ((x & 0x3f) | 0x80);
388 (*outbytesleft) -= 2;
390 else if (x <= 0xffff && *outbytesleft >= 3)
392 *outp++ = (unsigned char) ((x >> 12) | 0xe0);
393 *outp++ = (unsigned char) (((x >> 6) & 0x3f) | 0x80);
394 *outp++ = (unsigned char) ((x & 0x3f) | 0x80);
395 (*outbytesleft) -= 3;
397 else if (x <= 0x1fffff && *outbytesleft >= 4)
399 *outp++ = (unsigned char) ((x >> 18) | 0xf0);
400 *outp++ = (unsigned char) (((x >> 12) & 0x3f) | 0x80);
401 *outp++ = (unsigned char) (((x >> 6) & 0x3f) | 0x80);
402 *outp++ = (unsigned char) ((x & 0x3f) | 0x80);
403 (*outbytesleft) -= 4;
405 else if (x <= 0x3ffffff && *outbytesleft >= 5)
407 *outp++ = (unsigned char) ((x >> 24) | 0xf8);
408 *outp++ = (unsigned char) (((x >> 18) & 0x3f) | 0x80);
409 *outp++ = (unsigned char) (((x >> 12) & 0x3f) | 0x80);
410 *outp++ = (unsigned char) (((x >> 6) & 0x3f) | 0x80);
411 *outp++ = (unsigned char) ((x & 0x3f) | 0x80);
412 (*outbytesleft) -= 5;
414 else if (*outbytesleft >= 6)
416 *outp++ = (unsigned char) ((x >> 30) | 0xfc);
417 *outp++ = (unsigned char) (((x >> 24) & 0x3f) | 0x80);
418 *outp++ = (unsigned char) (((x >> 18) & 0x3f) | 0x80);
419 *outp++ = (unsigned char) (((x >> 12) & 0x3f) | 0x80);
420 *outp++ = (unsigned char) (((x >> 6) & 0x3f) | 0x80);
421 *outp++ = (unsigned char) ((x & 0x3f) | 0x80);
422 (*outbytesleft) -= 6;
426 cd->my_errno = YAZ_ICONV_E2BIG; /* not room for output */
429 *outbuf = (char *) outp;
434 static size_t yaz_write_ISO8859_1 (yaz_iconv_t cd, unsigned long x,
435 char **outbuf, size_t *outbytesleft,
438 /* list of two char unicode sequence that, when combined, are
439 equivalent to single unicode chars that can be represented in
441 Regular iconv on Linux at least does not seem to convert these,
442 but since MARC-8 to UTF-8 generates these composed sequence
443 we get a better chance of a successful MARC-8 -> ISO-8859-1
446 unsigned long x1, x2;
449 { 'A', 0x0300, 0xc0}, /* LATIN CAPITAL LETTER A WITH GRAVE */
450 { 'A', 0x0301, 0xc1}, /* LATIN CAPITAL LETTER A WITH ACUTE */
451 { 'A', 0x0302, 0xc2}, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
452 { 'A', 0x0303, 0xc3}, /* LATIN CAPITAL LETTER A WITH TILDE */
453 { 'A', 0x0308, 0xc4}, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
454 { 'A', 0x030a, 0xc5}, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
455 /* no need for 0xc6 LATIN CAPITAL LETTER AE */
456 { 'C', 0x0327, 0xc7}, /* LATIN CAPITAL LETTER C WITH CEDILLA */
457 { 'E', 0x0300, 0xc8}, /* LATIN CAPITAL LETTER E WITH GRAVE */
458 { 'E', 0x0301, 0xc9}, /* LATIN CAPITAL LETTER E WITH ACUTE */
459 { 'E', 0x0302, 0xca}, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
460 { 'E', 0x0308, 0xcb}, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
461 { 'I', 0x0300, 0xcc}, /* LATIN CAPITAL LETTER I WITH GRAVE */
462 { 'I', 0x0301, 0xcd}, /* LATIN CAPITAL LETTER I WITH ACUTE */
463 { 'I', 0x0302, 0xce}, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
464 { 'I', 0x0308, 0xcf}, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
465 { 'N', 0x0303, 0xd1}, /* LATIN CAPITAL LETTER N WITH TILDE */
466 { 'O', 0x0300, 0xd2}, /* LATIN CAPITAL LETTER O WITH GRAVE */
467 { 'O', 0x0301, 0xd3}, /* LATIN CAPITAL LETTER O WITH ACUTE */
468 { 'O', 0x0302, 0xd4}, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
469 { 'O', 0x0303, 0xd5}, /* LATIN CAPITAL LETTER O WITH TILDE */
470 { 'O', 0x0308, 0xd6}, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
471 /* omitted: 0xd7 MULTIPLICATION SIGN */
472 /* omitted: 0xd8 LATIN CAPITAL LETTER O WITH STROKE */
473 { 'U', 0x0300, 0xd9}, /* LATIN CAPITAL LETTER U WITH GRAVE */
474 { 'U', 0x0301, 0xda}, /* LATIN CAPITAL LETTER U WITH ACUTE */
475 { 'U', 0x0302, 0xdb}, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
476 { 'U', 0x0308, 0xdc}, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
477 { 'Y', 0x0301, 0xdd}, /* LATIN CAPITAL LETTER Y WITH ACUTE */
478 /* omitted: 0xde LATIN CAPITAL LETTER THORN */
479 /* omitted: 0xdf LATIN SMALL LETTER SHARP S */
480 { 'a', 0x0300, 0xe0}, /* LATIN SMALL LETTER A WITH GRAVE */
481 { 'a', 0x0301, 0xe1}, /* LATIN SMALL LETTER A WITH ACUTE */
482 { 'a', 0x0302, 0xe2}, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
483 { 'a', 0x0303, 0xe3}, /* LATIN SMALL LETTER A WITH TILDE */
484 { 'a', 0x0308, 0xe4}, /* LATIN SMALL LETTER A WITH DIAERESIS */
485 { 'a', 0x030a, 0xe5}, /* LATIN SMALL LETTER A WITH RING ABOVE */
486 /* omitted: 0xe6 LATIN SMALL LETTER AE */
487 { 'c', 0x0327, 0xe7}, /* LATIN SMALL LETTER C WITH CEDILLA */
488 { 'e', 0x0300, 0xe8}, /* LATIN SMALL LETTER E WITH GRAVE */
489 { 'e', 0x0301, 0xe9}, /* LATIN SMALL LETTER E WITH ACUTE */
490 { 'e', 0x0302, 0xea}, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
491 { 'e', 0x0308, 0xeb}, /* LATIN SMALL LETTER E WITH DIAERESIS */
492 { 'i', 0x0300, 0xec}, /* LATIN SMALL LETTER I WITH GRAVE */
493 { 'i', 0x0301, 0xed}, /* LATIN SMALL LETTER I WITH ACUTE */
494 { 'i', 0x0302, 0xee}, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
495 { 'i', 0x0308, 0xef}, /* LATIN SMALL LETTER I WITH DIAERESIS */
496 /* omitted: 0xf0 LATIN SMALL LETTER ETH */
497 { 'n', 0x0303, 0xf1}, /* LATIN SMALL LETTER N WITH TILDE */
498 { 'o', 0x0300, 0xf2}, /* LATIN SMALL LETTER O WITH GRAVE */
499 { 'o', 0x0301, 0xf3}, /* LATIN SMALL LETTER O WITH ACUTE */
500 { 'o', 0x0302, 0xf4}, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
501 { 'o', 0x0303, 0xf5}, /* LATIN SMALL LETTER O WITH TILDE */
502 { 'o', 0x0308, 0xf6}, /* LATIN SMALL LETTER O WITH DIAERESIS */
503 /* omitted: 0xf7 DIVISION SIGN */
504 /* omitted: 0xf8 LATIN SMALL LETTER O WITH STROKE */
505 { 'u', 0x0300, 0xf9}, /* LATIN SMALL LETTER U WITH GRAVE */
506 { 'u', 0x0301, 0xfa}, /* LATIN SMALL LETTER U WITH ACUTE */
507 { 'u', 0x0302, 0xfb}, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
508 { 'u', 0x0308, 0xfc}, /* LATIN SMALL LETTER U WITH DIAERESIS */
509 { 'y', 0x0301, 0xfd}, /* LATIN SMALL LETTER Y WITH ACUTE */
510 /* omitted: 0xfe LATIN SMALL LETTER THORN */
511 { 'y', 0x0308, 0xff}, /* LATIN SMALL LETTER Y WITH DIAERESIS */
515 unsigned char *outp = (unsigned char *) *outbuf;
517 if (!last && x > 32 && x < 127 && cd->compose_char == 0)
519 cd->compose_char = x;
522 else if (cd->compose_char)
525 for (i = 0; comb[i].x1; i++)
526 if (cd->compose_char == comb[i].x1 && x == comb[i].x2)
533 if (*outbytesleft >= 1)
535 *outp++ = (unsigned char) cd->compose_char;
537 *outbuf = (char *) outp;
538 if (!last && x > 32 && x < 127)
540 cd->compose_char = x;
546 cd->my_errno = YAZ_ICONV_E2BIG;
550 /* compose_char and old x combined to one new char: x */
551 cd->compose_char = 0;
553 if (x > 255 || x < 1)
555 cd->my_errno = YAZ_ICONV_EILSEQ;
558 else if (*outbytesleft >= 1)
560 *outp++ = (unsigned char) x;
565 cd->my_errno = YAZ_ICONV_E2BIG;
568 *outbuf = (char *) outp;
573 static size_t yaz_write_UCS4 (yaz_iconv_t cd, unsigned long x,
574 char **outbuf, size_t *outbytesleft,
577 unsigned char *outp = (unsigned char *) *outbuf;
578 if (*outbytesleft >= 4)
580 *outp++ = (unsigned char) (x>>24);
581 *outp++ = (unsigned char) (x>>16);
582 *outp++ = (unsigned char) (x>>8);
583 *outp++ = (unsigned char) x;
584 (*outbytesleft) -= 4;
588 cd->my_errno = YAZ_ICONV_E2BIG;
591 *outbuf = (char *) outp;
595 static size_t yaz_write_UCS4LE (yaz_iconv_t cd, unsigned long x,
596 char **outbuf, size_t *outbytesleft,
599 unsigned char *outp = (unsigned char *) *outbuf;
600 if (*outbytesleft >= 4)
602 *outp++ = (unsigned char) x;
603 *outp++ = (unsigned char) (x>>8);
604 *outp++ = (unsigned char) (x>>16);
605 *outp++ = (unsigned char) (x>>24);
606 (*outbytesleft) -= 4;
610 cd->my_errno = YAZ_ICONV_E2BIG;
613 *outbuf = (char *) outp;
618 static size_t yaz_write_wchar_t (yaz_iconv_t cd, unsigned long x,
619 char **outbuf, size_t *outbytesleft,
622 unsigned char *outp = (unsigned char *) *outbuf;
624 if (*outbytesleft >= sizeof(wchar_t))
627 memcpy(outp, &wch, sizeof(wch));
629 (*outbytesleft) -= sizeof(wch);
633 cd->my_errno = YAZ_ICONV_E2BIG;
636 *outbuf = (char *) outp;
641 int yaz_iconv_isbuiltin(yaz_iconv_t cd)
643 return cd->read_handle && cd->write_handle;
646 yaz_iconv_t yaz_iconv_open (const char *tocode, const char *fromcode)
648 yaz_iconv_t cd = (yaz_iconv_t) xmalloc (sizeof(*cd));
650 cd->write_handle = 0;
653 cd->my_errno = YAZ_ICONV_UNKNOWN;
654 cd->marc8_esc_mode = 'B';
655 cd->comb_offset = cd->comb_size = 0;
656 cd->compose_char = 0;
658 /* a useful hack: if fromcode has leading @,
659 the library not use YAZ's own conversions .. */
660 if (fromcode[0] == '@')
664 if (!yaz_matchstr(fromcode, "UTF8"))
666 cd->read_handle = yaz_read_UTF8;
667 cd->init_handle = yaz_init_UTF8;
669 else if (!yaz_matchstr(fromcode, "ISO88591"))
670 cd->read_handle = yaz_read_ISO8859_1;
671 else if (!yaz_matchstr(fromcode, "UCS4"))
672 cd->read_handle = yaz_read_UCS4;
673 else if (!yaz_matchstr(fromcode, "UCS4LE"))
674 cd->read_handle = yaz_read_UCS4LE;
675 else if (!yaz_matchstr(fromcode, "MARC8"))
676 cd->read_handle = yaz_read_marc8;
678 else if (!yaz_matchstr(fromcode, "WCHAR_T"))
679 cd->read_handle = yaz_read_wchar_t;
682 if (!yaz_matchstr(tocode, "UTF8"))
683 cd->write_handle = yaz_write_UTF8;
684 else if (!yaz_matchstr(tocode, "ISO88591"))
685 cd->write_handle = yaz_write_ISO8859_1;
686 else if (!yaz_matchstr (tocode, "UCS4"))
687 cd->write_handle = yaz_write_UCS4;
688 else if (!yaz_matchstr(tocode, "UCS4LE"))
689 cd->write_handle = yaz_write_UCS4LE;
691 else if (!yaz_matchstr(tocode, "WCHAR_T"))
692 cd->write_handle = yaz_write_wchar_t;
697 if (!cd->read_handle || !cd->write_handle)
699 cd->iconv_cd = iconv_open (tocode, fromcode);
700 if (cd->iconv_cd == (iconv_t) (-1))
707 if (!cd->read_handle || !cd->write_handle)
717 size_t yaz_iconv(yaz_iconv_t cd, char **inbuf, size_t *inbytesleft,
718 char **outbuf, size_t *outbytesleft)
726 iconv(cd->iconv_cd, inbuf, inbytesleft, outbuf, outbytesleft);
727 if (r == (size_t)(-1))
732 cd->my_errno = YAZ_ICONV_E2BIG;
735 cd->my_errno = YAZ_ICONV_EINVAL;
738 cd->my_errno = YAZ_ICONV_EILSEQ;
741 cd->my_errno = YAZ_ICONV_UNKNOWN;
747 if (inbuf == 0 || *inbuf == 0)
750 cd->my_errno = YAZ_ICONV_UNKNOWN;
760 size_t r = (cd->init_handle)(cd, (unsigned char *) *inbuf,
761 *inbytesleft, &no_read);
764 if (cd->my_errno == YAZ_ICONV_EINVAL)
769 *inbytesleft -= no_read;
781 if (*inbytesleft == 0)
788 x = (cd->read_handle)(cd, (unsigned char *) *inbuf, *inbytesleft,
799 no_read = cd->no_read_x;
803 r = (cd->write_handle)(cd, x, outbuf, outbytesleft,
804 (*inbytesleft - no_read) == 0 ? 1 : 0);
807 /* unable to write it. save it because read_handle cannot
810 cd->no_read_x = no_read;
815 *inbytesleft -= no_read;
821 int yaz_iconv_error (yaz_iconv_t cd)
826 int yaz_iconv_close (yaz_iconv_t cd)
830 iconv_close (cd->iconv_cd);
840 * indent-tabs-mode: nil
842 * vim: shiftwidth=4 tabstop=8 expandtab