Do an indirect conversion if iconv_open does not support a direct conversion.
[gnulib.git] / lib / striconveh.c
1 /* Character set conversion with error handling.
2    Copyright (C) 2001-2007 Free Software Foundation, Inc.
3    Written by Bruno Haible and Simon Josefsson.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18
19 #include <config.h>
20
21 /* Specification.  */
22 #include "striconveh.h"
23
24 #include <errno.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #if HAVE_ICONV
30 # include <iconv.h>
31 # include "unistr.h"
32 #endif
33
34 #include "c-strcase.h"
35 #include "c-strcaseeq.h"
36
37 #ifndef SIZE_MAX
38 # define SIZE_MAX ((size_t) -1)
39 #endif
40
41
42 #if HAVE_ICONV
43
44 /* The caller must provide CD, CD1, CD2, not just CD, because when a conversion
45    error occurs, we may have to determine the Unicode representation of the
46    inconvertible character.  */
47
48 /* iconv_carefully is like iconv, except that it stops as soon as it encounters
49    a conversion error, and it returns in *INCREMENTED a boolean telling whether
50    it has incremented the input pointers past the error location.  */
51 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
52 /* Irix iconv() inserts a NUL byte if it cannot convert.
53    NetBSD iconv() inserts a question mark if it cannot convert.
54    Only GNU libiconv and GNU libc are known to prefer to fail rather
55    than doing a lossy conversion.  */
56 static size_t
57 iconv_carefully (iconv_t cd,
58                  const char **inbuf, size_t *inbytesleft,
59                  char **outbuf, size_t *outbytesleft,
60                  bool *incremented)
61 {
62   const char *inptr = *inbuf;
63   const char *inptr_end = inptr + *inbytesleft;
64   char *outptr = *outbuf;
65   size_t outsize = *outbytesleft;
66   const char *inptr_before;
67   size_t res;
68
69   do
70     {
71       size_t insize;
72
73       inptr_before = inptr;
74       res = (size_t)(-1);
75
76       for (insize = 1; inptr + insize <= inptr_end; insize++)
77         {
78           res = iconv (cd,
79                        (ICONV_CONST char **) &inptr, &insize,
80                        &outptr, &outsize);
81           if (!(res == (size_t)(-1) && errno == EINVAL))
82             break;
83           /* We expect that no input bytes have been consumed so far.  */
84           if (inptr != inptr_before)
85             abort ();
86         }
87
88       if (res == 0)
89         {
90           *outbuf = outptr;
91           *outbytesleft = outsize;
92         }
93     }
94   while (res == 0 && inptr < inptr_end);
95
96   *inbuf = inptr;
97   *inbytesleft = inptr_end - inptr;
98   if (res != (size_t)(-1) && res > 0)
99     {
100       /* iconv() has already incremented INPTR.  We cannot go back to a
101          previous INPTR, otherwise the state inside CD would become invalid,
102          if FROM_CODESET is a stateful encoding.  So, tell the caller that
103          *INBUF has already been incremented.  */
104       *incremented = (inptr > inptr_before);
105       errno = EILSEQ;
106       return (size_t)(-1);
107     }
108   else
109     {
110       *incremented = false;
111       return res;
112     }
113 }
114 # else
115 #  define iconv_carefully(cd, inbuf, inbytesleft, outbuf, outbytesleft, incremented) \
116      (*(incremented) = false, \
117       iconv (cd, (ICONV_CONST char **) (inbuf), inbytesleft, outbuf, outbytesleft))
118 # endif
119
120 /* iconv_carefully_1 is like iconv_carefully, except that it stops after
121    converting one character.  */
122 static size_t
123 iconv_carefully_1 (iconv_t cd,
124                    const char **inbuf, size_t *inbytesleft,
125                    char **outbuf, size_t *outbytesleft,
126                    bool *incremented)
127 {
128   const char *inptr = *inbuf;
129   const char *inptr_end = inptr + *inbytesleft;
130   char *outptr = *outbuf;
131   size_t outsize = *outbytesleft;
132   const char *inptr_before = inptr;
133   size_t res = (size_t)(-1);
134   size_t insize;
135
136   for (insize = 1; inptr + insize <= inptr_end; insize++)
137     {
138       res = iconv (cd,
139                    (ICONV_CONST char **) &inptr, &insize,
140                    &outptr, &outsize);
141       if (!(res == (size_t)(-1) && errno == EINVAL))
142         break;
143       /* We expect that no input bytes have been consumed so far.  */
144       if (inptr != inptr_before)
145         abort ();
146     }
147
148   *inbuf = inptr;
149   *inbytesleft = inptr_end - inptr;
150 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
151   /* Irix iconv() inserts a NUL byte if it cannot convert.
152      NetBSD iconv() inserts a question mark if it cannot convert.
153      Only GNU libiconv and GNU libc are known to prefer to fail rather
154      than doing a lossy conversion.  */
155   if (res != (size_t)(-1) && res > 0)
156     {
157       /* iconv() has already incremented INPTR.  We cannot go back to a
158          previous INPTR, otherwise the state inside CD would become invalid,
159          if FROM_CODESET is a stateful encoding.  So, tell the caller that
160          *INBUF has already been incremented.  */
161       *incremented = (inptr > inptr_before);
162       errno = EILSEQ;
163       return (size_t)(-1);
164     }
165 # endif
166
167   if (res != (size_t)(-1))
168     {
169       *outbuf = outptr;
170       *outbytesleft = outsize;
171     }
172   *incremented = false;
173   return res;
174 }
175
176 /* utf8conv_carefully is like iconv, except that
177      - it converts from UTF-8 to UTF-8,
178      - it stops as soon as it encounters a conversion error, and it returns
179        in *INCREMENTED a boolean telling whether it has incremented the input
180        pointers past the error location,
181      - if one_character_only is true, it stops after converting one
182        character.  */
183 static size_t
184 utf8conv_carefully (bool one_character_only,
185                     const char **inbuf, size_t *inbytesleft,
186                     char **outbuf, size_t *outbytesleft,
187                     bool *incremented)
188 {
189   const char *inptr = *inbuf;
190   size_t insize = *inbytesleft;
191   char *outptr = *outbuf;
192   size_t outsize = *outbytesleft;
193   size_t res;
194
195   res = 0;
196   do
197     {
198       ucs4_t uc;
199       int n;
200       int m;
201
202       n = u8_mbtoucr (&uc, (const uint8_t *) inptr, insize);
203       if (n < 0)
204         {
205           errno = (n == -2 ? EINVAL : EILSEQ);
206           n = u8_mbtouc (&uc, (const uint8_t *) inptr, insize);
207           inptr += n;
208           insize -= n;
209           res = (size_t)(-1);
210           *incremented = true;
211           break;
212         }
213       if (outsize == 0)
214         {
215           errno = E2BIG;
216           res = (size_t)(-1);
217           *incremented = false;
218           break;
219         }
220       m = u8_uctomb ((uint8_t *) outptr, uc, outsize);
221       if (m == -2)
222         {
223           errno = E2BIG;
224           res = (size_t)(-1);
225           *incremented = false;
226           break;
227         }
228       inptr += n;
229       insize -= n;
230       if (m == -1)
231         {
232           errno = EILSEQ;
233           res = (size_t)(-1);
234           *incremented = true;
235           break;
236         }
237       outptr += m;
238       outsize -= m;
239     }
240   while (!one_character_only && insize > 0);
241
242   *inbuf = inptr;
243   *inbytesleft = insize;
244   *outbuf = outptr;
245   *outbytesleft = outsize;
246   return res;
247 }
248
249 static int
250 mem_cd_iconveh_internal (const char *src, size_t srclen,
251                          iconv_t cd, iconv_t cd1, iconv_t cd2,
252                          enum iconv_ilseq_handler handler,
253                          size_t extra_alloc,
254                          size_t *offsets,
255                          char **resultp, size_t *lengthp)
256 {
257   /* When a conversion error occurs, we cannot start using CD1 and CD2 at
258      this point: FROM_CODESET may be a stateful encoding like ISO-2022-KR.
259      Instead, we have to start afresh from the beginning of SRC.  */
260   /* Use a temporary buffer, so that for small strings, a single malloc()
261      call will be sufficient.  */
262 # define tmpbufsize 4096
263   /* The alignment is needed when converting e.g. to glibc's WCHAR_T or
264      libiconv's UCS-4-INTERNAL encoding.  */
265   union { unsigned int align; char buf[tmpbufsize]; } tmp;
266 # define tmpbuf tmp.buf
267
268   char *initial_result;
269   char *result;
270   size_t allocated;
271   size_t length;
272   size_t last_length = (size_t)(-1); /* only needed if offsets != NULL */
273
274   if (*resultp != NULL && *lengthp >= sizeof (tmpbuf))
275     {
276       initial_result = *resultp;
277       allocated = *lengthp;
278     }
279   else
280     {
281       initial_result = tmpbuf;
282       allocated = sizeof (tmpbuf);
283     }
284   result = initial_result;
285
286   /* Test whether a direct conversion is possible at all.  */
287   if (cd == (iconv_t)(-1))
288     goto indirectly;
289
290   if (offsets != NULL)
291     {
292       size_t i;
293
294       for (i = 0; i < srclen; i++)
295         offsets[i] = (size_t)(-1);
296
297       last_length = (size_t)(-1);
298     }
299   length = 0;
300
301   /* First, try a direct conversion, and see whether a conversion error
302      occurs at all.  */
303   {
304     const char *inptr = src;
305     size_t insize = srclen;
306
307     /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug.  */
308 # if defined _LIBICONV_VERSION \
309      || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
310     /* Set to the initial state.  */
311     iconv (cd, NULL, NULL, NULL, NULL);
312 # endif
313
314     while (insize > 0)
315       {
316         char *outptr = result + length;
317         size_t outsize = allocated - extra_alloc - length;
318         bool incremented;
319         size_t res;
320         bool grow;
321
322         if (offsets != NULL)
323           {
324             if (length != last_length) /* ensure that offset[] be increasing */
325               {
326                 offsets[inptr - src] = length;
327                 last_length = length;
328               }
329             res = iconv_carefully_1 (cd,
330                                      &inptr, &insize,
331                                      &outptr, &outsize,
332                                      &incremented);
333           }
334         else
335           /* Use iconv_carefully instead of iconv here, because:
336              - If TO_CODESET is UTF-8, we can do the error handling in this
337                loop, no need for a second loop,
338              - With iconv() implementations other than GNU libiconv and GNU
339                libc, if we use iconv() in a big swoop, checking for an E2BIG
340                return, we lose the number of irreversible conversions.  */
341           res = iconv_carefully (cd,
342                                  &inptr, &insize,
343                                  &outptr, &outsize,
344                                  &incremented);
345
346         length = outptr - result;
347         grow = (length + extra_alloc > allocated / 2);
348         if (res == (size_t)(-1))
349           {
350             if (errno == E2BIG)
351               grow = true;
352             else if (errno == EINVAL)
353               break;
354             else if (errno == EILSEQ && handler != iconveh_error)
355               {
356                 if (cd2 == (iconv_t)(-1))
357                   {
358                     /* TO_CODESET is UTF-8.  */
359                     /* Error handling can produce up to 1 byte of output.  */
360                     if (length + 1 + extra_alloc > allocated)
361                       {
362                         char *memory;
363
364                         allocated = 2 * allocated;
365                         if (length + 1 + extra_alloc > allocated)
366                           abort ();
367                         if (result == initial_result)
368                           memory = (char *) malloc (allocated);
369                         else
370                           memory = (char *) realloc (result, allocated);
371                         if (memory == NULL)
372                           {
373                             if (result != initial_result)
374                               free (result);
375                             errno = ENOMEM;
376                             return -1;
377                           }
378                         if (result == initial_result)
379                           memcpy (memory, initial_result, length);
380                         result = memory;
381                         grow = false;
382                       }
383                     /* The input is invalid in FROM_CODESET.  Eat up one byte
384                        and emit a question mark.  */
385                     if (!incremented)
386                       {
387                         if (insize == 0)
388                           abort ();
389                         inptr++;
390                         insize--;
391                       }
392                     result[length] = '?';
393                     length++;
394                   }
395                 else
396                   goto indirectly;
397               }
398             else
399               {
400                 if (result != initial_result)
401                   {
402                     int saved_errno = errno;
403                     free (result);
404                     errno = saved_errno;
405                   }
406                 return -1;
407               }
408           }
409         if (insize == 0)
410           break;
411         if (grow)
412           {
413             char *memory;
414
415             allocated = 2 * allocated;
416             if (result == initial_result)
417               memory = (char *) malloc (allocated);
418             else
419               memory = (char *) realloc (result, allocated);
420             if (memory == NULL)
421               {
422                 if (result != initial_result)
423                   free (result);
424                 errno = ENOMEM;
425                 return -1;
426               }
427             if (result == initial_result)
428               memcpy (memory, initial_result, length);
429             result = memory;
430           }
431       }
432   }
433
434   /* Now get the conversion state back to the initial state.
435      But avoid glibc-2.1 bug and Solaris 2.7 bug.  */
436 #if defined _LIBICONV_VERSION \
437     || !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
438   for (;;)
439     {
440       char *outptr = result + length;
441       size_t outsize = allocated - extra_alloc - length;
442       size_t res;
443
444       res = iconv (cd, NULL, NULL, &outptr, &outsize);
445       length = outptr - result;
446       if (res == (size_t)(-1))
447         {
448           if (errno == E2BIG)
449             {
450               char *memory;
451
452               allocated = 2 * allocated;
453               if (result == initial_result)
454                 memory = (char *) malloc (allocated);
455               else
456                 memory = (char *) realloc (result, allocated);
457               if (memory == NULL)
458                 {
459                   if (result != initial_result)
460                     free (result);
461                   errno = ENOMEM;
462                   return -1;
463                 }
464               if (result == initial_result)
465                 memcpy (memory, initial_result, length);
466               result = memory;
467             }
468           else
469             {
470               if (result != initial_result)
471                 {
472                   int saved_errno = errno;
473                   free (result);
474                   errno = saved_errno;
475                 }
476               return -1;
477             }
478         }
479       else
480         break;
481     }
482 #endif
483
484   /* The direct conversion succeeded.  */
485   goto done;
486
487  indirectly:
488   /* The direct conversion failed.
489      Use a conversion through UTF-8.  */
490   if (offsets != NULL)
491     {
492       size_t i;
493
494       for (i = 0; i < srclen; i++)
495         offsets[i] = (size_t)(-1);
496
497       last_length = (size_t)(-1);
498     }
499   length = 0;
500   {
501     const bool slowly = (offsets != NULL || handler == iconveh_error);
502 # define utf8bufsize 4096 /* may also be smaller or larger than tmpbufsize */
503     char utf8buf[utf8bufsize + 1];
504     size_t utf8len = 0;
505     const char *in1ptr = src;
506     size_t in1size = srclen;
507     bool do_final_flush1 = true;
508     bool do_final_flush2 = true;
509
510     /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug.  */
511 # if defined _LIBICONV_VERSION \
512      || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
513     /* Set to the initial state.  */
514     if (cd1 != (iconv_t)(-1))
515       iconv (cd1, NULL, NULL, NULL, NULL);
516     if (cd2 != (iconv_t)(-1))
517       iconv (cd2, NULL, NULL, NULL, NULL);
518 # endif
519
520     while (in1size > 0 || do_final_flush1 || utf8len > 0 || do_final_flush2)
521       {
522         char *out1ptr = utf8buf + utf8len;
523         size_t out1size = utf8bufsize - utf8len;
524         bool incremented1;
525         size_t res1;
526         int errno1;
527
528         /* Conversion step 1: from FROM_CODESET to UTF-8.  */
529         if (in1size > 0)
530           {
531             if (offsets != NULL
532                 && length != last_length) /* ensure that offset[] be increasing */
533               {
534                 offsets[in1ptr - src] = length;
535                 last_length = length;
536               }
537             if (cd1 != (iconv_t)(-1))
538               {
539                 if (slowly)
540                   res1 = iconv_carefully_1 (cd1,
541                                             &in1ptr, &in1size,
542                                             &out1ptr, &out1size,
543                                             &incremented1);
544                 else
545                   res1 = iconv_carefully (cd1,
546                                           &in1ptr, &in1size,
547                                           &out1ptr, &out1size,
548                                           &incremented1);
549               }
550             else
551               {
552                 /* FROM_CODESET is UTF-8.  */
553                 res1 = utf8conv_carefully (slowly,
554                                            &in1ptr, &in1size,
555                                            &out1ptr, &out1size,
556                                            &incremented1);
557               }
558           }
559         else if (do_final_flush1)
560           {
561             /* Now get the conversion state of CD1 back to the initial state.
562                But avoid glibc-2.1 bug and Solaris 2.7 bug.  */
563 # if defined _LIBICONV_VERSION \
564      || !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
565             if (cd1 != (iconv_t)(-1))
566               res1 = iconv (cd1, NULL, NULL, &out1ptr, &out1size);
567             else
568 # endif
569               res1 = 0;
570             do_final_flush1 = false;
571             incremented1 = true;
572           }
573         else
574           {
575             res1 = 0;
576             incremented1 = true;
577           }
578         if (res1 == (size_t)(-1)
579             && !(errno == E2BIG || errno == EINVAL || errno == EILSEQ))
580           {
581             if (result != initial_result)
582               {
583                 int saved_errno = errno;
584                 free (result);
585                 errno = saved_errno;
586               }
587             return -1;
588           }
589         if (res1 == (size_t)(-1)
590             && errno == EILSEQ && handler != iconveh_error)
591           {
592             /* The input is invalid in FROM_CODESET.  Eat up one byte and
593                emit a question mark.  Room for the question mark was allocated
594                at the end of utf8buf.  */
595             if (!incremented1)
596               {
597                 if (in1size == 0)
598                   abort ();
599                 in1ptr++;
600                 in1size--;
601               }
602             utf8buf[utf8len++] = '?';
603           }
604         errno1 = errno;
605         utf8len = out1ptr - utf8buf;
606
607         if (offsets != NULL
608             || in1size == 0
609             || utf8len > utf8bufsize / 2
610             || (res1 == (size_t)(-1) && errno1 == E2BIG))
611           {
612             /* Conversion step 2: from UTF-8 to TO_CODESET.  */
613             const char *in2ptr = utf8buf;
614             size_t in2size = utf8len;
615
616             while (in2size > 0
617                    || (in1size == 0 && !do_final_flush1 && do_final_flush2))
618               {
619                 char *out2ptr = result + length;
620                 size_t out2size = allocated - extra_alloc - length;
621                 bool incremented2;
622                 size_t res2;
623                 bool grow;
624
625                 if (in2size > 0)
626                   {
627                     if (cd2 != (iconv_t)(-1))
628                       res2 = iconv_carefully (cd2,
629                                               &in2ptr, &in2size,
630                                               &out2ptr, &out2size,
631                                               &incremented2);
632                     else
633                       /* TO_CODESET is UTF-8.  */
634                       res2 = utf8conv_carefully (false,
635                                                  &in2ptr, &in2size,
636                                                  &out2ptr, &out2size,
637                                                  &incremented2);
638                   }
639                 else /* in1size == 0 && !do_final_flush1
640                         && in2size == 0 && do_final_flush2 */
641                   {
642                     /* Now get the conversion state of CD1 back to the initial
643                        state.  But avoid glibc-2.1 bug and Solaris 2.7 bug.  */
644 # if defined _LIBICONV_VERSION \
645      || !((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) || defined __sun)
646                     if (cd2 != (iconv_t)(-1))
647                       res2 = iconv (cd2, NULL, NULL, &out2ptr, &out2size);
648                     else
649 # endif
650                       res2 = 0;
651                     do_final_flush2 = false;
652                     incremented2 = true;
653                   }
654
655                 length = out2ptr - result;
656                 grow = (length + extra_alloc > allocated / 2);
657                 if (res2 == (size_t)(-1))
658                   {
659                     if (errno == E2BIG)
660                       grow = true;
661                     else if (errno == EINVAL)
662                       break;
663                     else if (errno == EILSEQ && handler != iconveh_error)
664                       {
665                         /* Error handling can produce up to 10 bytes of ASCII
666                            output.  But TO_CODESET may be UCS-2, UTF-16 or
667                            UCS-4, so use CD2 here as well.  */
668                         char scratchbuf[10];
669                         size_t scratchlen;
670                         ucs4_t uc;
671                         const char *inptr;
672                         size_t insize;
673                         size_t res;
674
675                         if (incremented2)
676                           {
677                             if (u8_prev (&uc, (const uint8_t *) in2ptr,
678                                          (const uint8_t *) utf8buf)
679                                 == NULL)
680                               abort ();
681                           }
682                         else
683                           {
684                             int n;
685                             if (in2size == 0)
686                               abort ();
687                             n = u8_mbtouc_unsafe (&uc, (const uint8_t *) in2ptr,
688                                                   in2size);
689                             in2ptr += n;
690                             in2size -= n;
691                           }
692
693                         if (handler == iconveh_escape_sequence)
694                           {
695                             static char hex[16] = "0123456789ABCDEF";
696                             scratchlen = 0;
697                             scratchbuf[scratchlen++] = '\\';
698                             if (uc < 0x10000)
699                               scratchbuf[scratchlen++] = 'u';
700                             else
701                               {
702                                 scratchbuf[scratchlen++] = 'U';
703                                 scratchbuf[scratchlen++] = hex[(uc>>28) & 15];
704                                 scratchbuf[scratchlen++] = hex[(uc>>24) & 15];
705                                 scratchbuf[scratchlen++] = hex[(uc>>20) & 15];
706                                 scratchbuf[scratchlen++] = hex[(uc>>16) & 15];
707                               }
708                             scratchbuf[scratchlen++] = hex[(uc>>12) & 15];
709                             scratchbuf[scratchlen++] = hex[(uc>>8) & 15];
710                             scratchbuf[scratchlen++] = hex[(uc>>4) & 15];
711                             scratchbuf[scratchlen++] = hex[uc & 15];
712                           }
713                         else
714                           {
715                             scratchbuf[0] = '?';
716                             scratchlen = 1;
717                           }
718
719                         inptr = scratchbuf;
720                         insize = scratchlen;
721                         if (cd2 != (iconv_t)(-1))
722                           res = iconv (cd2,
723                                        (ICONV_CONST char **) &inptr, &insize,
724                                        &out2ptr, &out2size);
725                         else
726                           {
727                             /* TO_CODESET is UTF-8.  */
728                             if (out2size >= insize)
729                               {
730                                 memcpy (out2ptr, inptr, insize);
731                                 out2ptr += insize;
732                                 out2size -= insize;
733                                 inptr += insize;
734                                 insize = 0;
735                                 res = 0;
736                               }
737                             else
738                               {
739                                 errno = E2BIG;
740                                 res = (size_t)(-1);
741                               }
742                           }
743                         length = out2ptr - result;
744                         if (res == (size_t)(-1) && errno == E2BIG)
745                           {
746                             char *memory;
747
748                             allocated = 2 * allocated;
749                             if (length + 1 + extra_alloc > allocated)
750                               abort ();
751                             if (result == initial_result)
752                               memory = (char *) malloc (allocated);
753                             else
754                               memory = (char *) realloc (result, allocated);
755                             if (memory == NULL)
756                               {
757                                 if (result != initial_result)
758                                   free (result);
759                                 errno = ENOMEM;
760                                 return -1;
761                               }
762                             if (result == initial_result)
763                               memcpy (memory, initial_result, length);
764                             result = memory;
765                             grow = false;
766
767                             out2ptr = result + length;
768                             out2size = allocated - extra_alloc - length;
769                             if (cd2 != (iconv_t)(-1))
770                               res = iconv (cd2,
771                                            (ICONV_CONST char **) &inptr,
772                                            &insize,
773                                            &out2ptr, &out2size);
774                             else
775                               {
776                                 /* TO_CODESET is UTF-8.  */
777                                 if (!(out2size >= insize))
778                                   abort ();
779                                 memcpy (out2ptr, inptr, insize);
780                                 out2ptr += insize;
781                                 out2size -= insize;
782                                 inptr += insize;
783                                 insize = 0;
784                                 res = 0;
785                               }
786                             length = out2ptr - result;
787                           }
788 # if !defined _LIBICONV_VERSION && !defined __GLIBC__
789                         /* Irix iconv() inserts a NUL byte if it cannot convert.
790                            NetBSD iconv() inserts a question mark if it cannot
791                            convert.
792                            Only GNU libiconv and GNU libc are known to prefer
793                            to fail rather than doing a lossy conversion.  */
794                         if (res != (size_t)(-1) && res > 0)
795                           {
796                             errno = EILSEQ;
797                             res = (size_t)(-1);
798                           }
799 # endif
800                         if (res == (size_t)(-1))
801                           {
802                             /* Failure converting the ASCII replacement.  */
803                             if (result != initial_result)
804                               {
805                                 int saved_errno = errno;
806                                 free (result);
807                                 errno = saved_errno;
808                               }
809                             return -1;
810                           }
811                       }
812                     else
813                       {
814                         if (result != initial_result)
815                           {
816                             int saved_errno = errno;
817                             free (result);
818                             errno = saved_errno;
819                           }
820                         return -1;
821                       }
822                   }
823                 if (!(in2size > 0
824                       || (in1size == 0 && !do_final_flush1 && do_final_flush2)))
825                   break;
826                 if (grow)
827                   {
828                     char *memory;
829
830                     allocated = 2 * allocated;
831                     if (result == initial_result)
832                       memory = (char *) malloc (allocated);
833                     else
834                       memory = (char *) realloc (result, allocated);
835                     if (memory == NULL)
836                       {
837                         if (result != initial_result)
838                           free (result);
839                         errno = ENOMEM;
840                         return -1;
841                       }
842                     if (result == initial_result)
843                       memcpy (memory, initial_result, length);
844                     result = memory;
845                   }
846               }
847
848             /* Move the remaining bytes to the beginning of utf8buf.  */
849             if (in2size > 0)
850               memmove (utf8buf, in2ptr, in2size);
851             utf8len = in2size;
852           }
853
854         if (res1 == (size_t)(-1))
855           {
856             if (errno1 == EINVAL)
857               in1size = 0;
858             else if (errno1 == EILSEQ)
859               {
860                 if (result != initial_result)
861                   free (result);
862                 errno = errno1;
863                 return -1;
864               }
865           }
866       }
867 # undef utf8bufsize
868   }
869
870  done:
871   /* Now the final memory allocation.  */
872   if (result == tmpbuf)
873     {
874       char *memory;
875
876       memory = (char *) malloc (length + extra_alloc);
877       if (memory != NULL)
878         {
879           memcpy (memory, tmpbuf, length);
880           result = memory;
881         }
882       else
883         {
884           errno = ENOMEM;
885           return -1;
886         }
887     }
888   else if (result != *resultp && length + extra_alloc < allocated)
889     {
890       /* Shrink the allocated memory if possible.  */
891       char *memory;
892
893       memory = (char *) realloc (result, length + extra_alloc);
894       if (memory != NULL)
895         result = memory;
896     }
897   *resultp = result;
898   *lengthp = length;
899   return 0;
900 # undef tmpbuf
901 # undef tmpbufsize
902 }
903
904 int
905 mem_cd_iconveh (const char *src, size_t srclen,
906                 iconv_t cd, iconv_t cd1, iconv_t cd2,
907                 enum iconv_ilseq_handler handler,
908                 size_t *offsets,
909                 char **resultp, size_t *lengthp)
910 {
911   return mem_cd_iconveh_internal (src, srclen, cd, cd1, cd2, handler, 0,
912                                   offsets, resultp, lengthp);
913 }
914
915 char *
916 str_cd_iconveh (const char *src,
917                 iconv_t cd, iconv_t cd1, iconv_t cd2,
918                 enum iconv_ilseq_handler handler)
919 {
920   /* For most encodings, a trailing NUL byte in the input will be converted
921      to a trailing NUL byte in the output.  But not for UTF-7.  So that this
922      function is usable for UTF-7, we have to exclude the NUL byte from the
923      conversion and add it by hand afterwards.  */
924   char *result = NULL;
925   size_t length = 0;
926   int retval = mem_cd_iconveh_internal (src, strlen (src),
927                                         cd, cd1, cd2, handler, 1, NULL,
928                                         &result, &length);
929
930   if (retval < 0)
931     {
932       if (result != NULL)
933         {
934           int saved_errno = errno;
935           free (result);
936           errno = saved_errno;
937         }
938       return NULL;
939     }
940
941   /* Add the terminating NUL byte.  */
942   result[length] = '\0';
943
944   return result;
945 }
946
947 #endif
948
949 int
950 mem_iconveh (const char *src, size_t srclen,
951              const char *from_codeset, const char *to_codeset,
952              enum iconv_ilseq_handler handler,
953              size_t *offsets,
954              char **resultp, size_t *lengthp)
955 {
956   if (srclen == 0)
957     {
958       /* Nothing to convert.  */
959       *lengthp = 0;
960       return 0;
961     }
962   else if (offsets == NULL && c_strcasecmp (from_codeset, to_codeset) == 0)
963     {
964       char *result;
965
966       if (*resultp != NULL && *lengthp >= srclen)
967         result = *resultp;
968       else
969         {
970           result = (char *) malloc (srclen);
971           if (result == NULL)
972             {
973               errno = ENOMEM;
974               return -1;
975             }
976         }
977       memcpy (result, src, srclen);
978       *resultp = result;
979       *lengthp = srclen;
980       return 0;
981     }
982   else
983     {
984 #if HAVE_ICONV
985       iconv_t cd;
986       iconv_t cd1;
987       iconv_t cd2;
988       char *result;
989       size_t length;
990       int retval;
991
992       /* Avoid glibc-2.1 bug with EUC-KR.  */
993 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
994       if (c_strcasecmp (from_codeset, "EUC-KR") == 0
995           || c_strcasecmp (to_codeset, "EUC-KR") == 0)
996         {
997           errno = EINVAL;
998           return -1;
999         }
1000 # endif
1001
1002       cd = iconv_open (to_codeset, from_codeset);
1003
1004       if (STRCASEEQ (from_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1005         cd1 = (iconv_t)(-1);
1006       else
1007         {
1008           cd1 = iconv_open ("UTF-8", from_codeset);
1009           if (cd1 == (iconv_t)(-1))
1010             {
1011               int saved_errno = errno;
1012               if (cd != (iconv_t)(-1))
1013                 iconv_close (cd);
1014               errno = saved_errno;
1015               return -1;
1016             }
1017         }
1018
1019       if (STRCASEEQ (to_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1020         cd2 = (iconv_t)(-1);
1021       else
1022         {
1023           cd2 = iconv_open (to_codeset, "UTF-8");
1024           if (cd2 == (iconv_t)(-1))
1025             {
1026               int saved_errno = errno;
1027               if (cd1 != (iconv_t)(-1))
1028                 iconv_close (cd1);
1029               if (cd != (iconv_t)(-1))
1030                 iconv_close (cd);
1031               errno = saved_errno;
1032               return -1;
1033             }
1034         }
1035
1036       result = *resultp;
1037       length = *lengthp;
1038       retval = mem_cd_iconveh (src, srclen, cd, cd1, cd2, handler, offsets,
1039                                &result, &length);
1040
1041       if (retval < 0)
1042         {
1043           /* Close cd, cd1, cd2, but preserve the errno from str_cd_iconv.  */
1044           int saved_errno = errno;
1045           if (cd2 != (iconv_t)(-1))
1046             iconv_close (cd2);
1047           if (cd1 != (iconv_t)(-1))
1048             iconv_close (cd1);
1049           if (cd != (iconv_t)(-1))
1050             iconv_close (cd);
1051           errno = saved_errno;
1052         }
1053       else
1054         {
1055           if (cd2 != (iconv_t)(-1) && iconv_close (cd2) < 0)
1056             {
1057               /* Return -1, but free the allocated memory, and while doing
1058                  that, preserve the errno from iconv_close.  */
1059               int saved_errno = errno;
1060               if (cd1 != (iconv_t)(-1))
1061                 iconv_close (cd1);
1062               if (cd != (iconv_t)(-1))
1063                 iconv_close (cd);
1064               if (result != *resultp && result != NULL)
1065                 free (result);
1066               errno = saved_errno;
1067               return -1;
1068             }
1069           if (cd1 != (iconv_t)(-1) && iconv_close (cd1) < 0)
1070             {
1071               /* Return -1, but free the allocated memory, and while doing
1072                  that, preserve the errno from iconv_close.  */
1073               int saved_errno = errno;
1074               if (cd != (iconv_t)(-1))
1075                 iconv_close (cd);
1076               if (result != *resultp && result != NULL)
1077                 free (result);
1078               errno = saved_errno;
1079               return -1;
1080             }
1081           if (cd != (iconv_t)(-1) && iconv_close (cd) < 0)
1082             {
1083               /* Return -1, but free the allocated memory, and while doing
1084                  that, preserve the errno from iconv_close.  */
1085               int saved_errno = errno;
1086               if (result != *resultp && result != NULL)
1087                 free (result);
1088               errno = saved_errno;
1089               return -1;
1090             }
1091           *resultp = result;
1092           *lengthp = length;
1093         }
1094       return retval;
1095 #else
1096       /* This is a different error code than if iconv_open existed but didn't
1097          support from_codeset and to_codeset, so that the caller can emit
1098          an error message such as
1099            "iconv() is not supported. Installing GNU libiconv and
1100             then reinstalling this package would fix this."  */
1101       errno = ENOSYS;
1102       return -1;
1103 #endif
1104     }
1105 }
1106
1107 char *
1108 str_iconveh (const char *src,
1109              const char *from_codeset, const char *to_codeset,
1110              enum iconv_ilseq_handler handler)
1111 {
1112   if (*src == '\0' || c_strcasecmp (from_codeset, to_codeset) == 0)
1113     {
1114       char *result = strdup (src);
1115
1116       if (result == NULL)
1117         errno = ENOMEM;
1118       return result;
1119     }
1120   else
1121     {
1122 #if HAVE_ICONV
1123       iconv_t cd;
1124       iconv_t cd1;
1125       iconv_t cd2;
1126       char *result;
1127
1128       /* Avoid glibc-2.1 bug with EUC-KR.  */
1129 # if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
1130       if (c_strcasecmp (from_codeset, "EUC-KR") == 0
1131           || c_strcasecmp (to_codeset, "EUC-KR") == 0)
1132         {
1133           errno = EINVAL;
1134           return NULL;
1135         }
1136 # endif
1137
1138       cd = iconv_open (to_codeset, from_codeset);
1139
1140       if (STRCASEEQ (from_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1141         cd1 = (iconv_t)(-1);
1142       else
1143         {
1144           cd1 = iconv_open ("UTF-8", from_codeset);
1145           if (cd1 == (iconv_t)(-1))
1146             {
1147               int saved_errno = errno;
1148               if (cd != (iconv_t)(-1))
1149                 iconv_close (cd);
1150               errno = saved_errno;
1151               return NULL;
1152             }
1153         }
1154
1155       if (STRCASEEQ (to_codeset, "UTF-8", 'U','T','F','-','8',0,0,0,0))
1156         cd2 = (iconv_t)(-1);
1157       else
1158         {
1159           cd2 = iconv_open (to_codeset, "UTF-8");
1160           if (cd2 == (iconv_t)(-1))
1161             {
1162               int saved_errno = errno;
1163               if (cd1 != (iconv_t)(-1))
1164                 iconv_close (cd1);
1165               if (cd != (iconv_t)(-1))
1166                 iconv_close (cd);
1167               errno = saved_errno;
1168               return NULL;
1169             }
1170         }
1171
1172       result = str_cd_iconveh (src, cd, cd1, cd2, handler);
1173
1174       if (result == NULL)
1175         {
1176           /* Close cd, cd1, cd2, but preserve the errno from str_cd_iconv.  */
1177           int saved_errno = errno;
1178           if (cd2 != (iconv_t)(-1))
1179             iconv_close (cd2);
1180           if (cd1 != (iconv_t)(-1))
1181             iconv_close (cd1);
1182           if (cd != (iconv_t)(-1))
1183             iconv_close (cd);
1184           errno = saved_errno;
1185         }
1186       else
1187         {
1188           if (cd2 != (iconv_t)(-1) && iconv_close (cd2) < 0)
1189             {
1190               /* Return NULL, but free the allocated memory, and while doing
1191                  that, preserve the errno from iconv_close.  */
1192               int saved_errno = errno;
1193               if (cd1 != (iconv_t)(-1))
1194                 iconv_close (cd1);
1195               if (cd != (iconv_t)(-1))
1196                 iconv_close (cd);
1197               free (result);
1198               errno = saved_errno;
1199               return NULL;
1200             }
1201           if (cd1 != (iconv_t)(-1) && iconv_close (cd1) < 0)
1202             {
1203               /* Return NULL, but free the allocated memory, and while doing
1204                  that, preserve the errno from iconv_close.  */
1205               int saved_errno = errno;
1206               if (cd != (iconv_t)(-1))
1207                 iconv_close (cd);
1208               free (result);
1209               errno = saved_errno;
1210               return NULL;
1211             }
1212           if (cd != (iconv_t)(-1) && iconv_close (cd) < 0)
1213             {
1214               /* Return NULL, but free the allocated memory, and while doing
1215                  that, preserve the errno from iconv_close.  */
1216               int saved_errno = errno;
1217               free (result);
1218               errno = saved_errno;
1219               return NULL;
1220             }
1221         }
1222       return result;
1223 #else
1224       /* This is a different error code than if iconv_open existed but didn't
1225          support from_codeset and to_codeset, so that the caller can emit
1226          an error message such as
1227            "iconv() is not supported. Installing GNU libiconv and
1228             then reinstalling this package would fix this."  */
1229       errno = ENOSYS;
1230       return NULL;
1231 #endif
1232     }
1233 }