Update.
[platform/upstream/glibc.git] / iconv / gconv_simple.c
1 /* Simple transformations functions.
2    Copyright (C) 1997, 1998 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <errno.h>
22 #include <gconv.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <wchar.h>
27 #include <sys/param.h>
28
29 #ifndef EILSEQ
30 # define EILSEQ EINVAL
31 #endif
32
33
34 /* These are definitions used by some of the functions for handling
35    UTF-8 encoding below.  */
36 static const wchar_t encoding_mask[] =
37 {
38   ~0x7ff, ~0xffff, ~0x1fffff, ~0x3ffffff
39 };
40
41 static const unsigned char encoding_byte[] =
42 {
43   0xc0, 0xe0, 0xf0, 0xf8, 0xfc
44 };
45
46
47
48 int
49 __gconv_transform_dummy (struct gconv_step *step, struct gconv_step_data *data,
50                          const char *inbuf, size_t *inlen, size_t *written,
51                          int do_flush)
52 {
53   size_t do_write;
54
55   /* We have no stateful encoding.  So we don't have to do anything
56      special.  */
57   if (do_flush)
58     do_write = 0;
59   else
60     {
61       do_write = MIN (*inlen, data->outbufsize - data->outbufavail);
62
63       memcpy (data->outbuf, inbuf, do_write);
64
65       *inlen -= do_write;
66       data->outbufavail += do_write;
67     }
68
69   /* ### TODO Actually, this number must be devided according to the
70      size of the input charset.  I.e., if the input is in UCS4 the
71      number of copied bytes must be divided by 4.  */
72   if (written != NULL)
73     *written = do_write;
74
75   return GCONV_OK;
76 }
77
78
79 /* Convert from ISO 646-IRV to ISO 10646/UCS4.  */
80 int
81 __gconv_transform_ascii_ucs4 (struct gconv_step *step,
82                               struct gconv_step_data *data, const char *inbuf,
83                               size_t *inlen, size_t *written, int do_flush)
84 {
85   struct gconv_step *next_step = step + 1;
86   struct gconv_step_data *next_data = data + 1;
87   gconv_fct fct = next_step->fct;
88   size_t do_write;
89   int result;
90
91   /* If the function is called with no input this means we have to reset
92      to the initial state.  The possibly partly converted input is
93      dropped.  */
94   if (do_flush)
95     {
96       /* Clear the state.  */
97       memset (data->statep, '\0', sizeof (mbstate_t));
98       do_write = 0;
99
100       /* Call the steps down the chain if there are any.  */
101       if (data->is_last)
102         result = GCONV_OK;
103       else
104         {
105           struct gconv_step *next_step = step + 1;
106           struct gconv_step_data *next_data = data + 1;
107
108           result = (*fct) (next_step, next_data, NULL, 0, written, 1);
109
110           /* Clear output buffer.  */
111           data->outbufavail = 0;
112         }
113     }
114   else
115     {
116       int save_errno = errno;
117       do_write = 0;
118
119       result = GCONV_OK;
120       do
121         {
122           const unsigned char *newinbuf = inbuf;
123           size_t actually = 0;
124           size_t cnt = 0;
125
126           while (data->outbufavail + sizeof (wchar_t) <= data->outbufsize
127                  && cnt < *inlen)
128             {
129               if (*newinbuf > '\x7f')
130                 {
131                   /* This is no correct ANSI_X3.4-1968 character.  */
132                   result = GCONV_ILLEGAL_INPUT;
133                   break;
134                 }
135
136               /* It's an one byte sequence.  */
137               *(wchar_t *) &data->outbuf[data->outbufavail]
138                 = (wchar_t) *newinbuf;
139               data->outbufavail += sizeof (wchar_t);
140               ++actually;
141
142               ++newinbuf;
143               ++cnt;
144             }
145
146           /* Remember how much we converted.  */
147           do_write += cnt * sizeof (wchar_t);
148           *inlen -= cnt;
149
150           /* Check whether an illegal character appeared.  */
151           if (result != GCONV_OK)
152             break;
153
154           if (data->is_last)
155             {
156               /* This is the last step.  */
157               result = (*inlen == 0 ? GCONV_EMPTY_INPUT : GCONV_FULL_OUTPUT);
158               break;
159             }
160
161           /* Status so far.  */
162           result = GCONV_EMPTY_INPUT;
163
164           if (data->outbufavail > 0)
165             {
166               /* Call the functions below in the chain.  */
167               size_t newavail = data->outbufavail;
168
169               result = (*fct) (next_step, next_data, data->outbuf, &newavail,
170                                written, 0);
171
172               /* Correct the output buffer.  */
173               if (newavail != data->outbufavail && newavail > 0)
174                 {
175                   memmove (data->outbuf,
176                            &data->outbuf[data->outbufavail - newavail],
177                            newavail);
178                   data->outbufavail = newavail;
179                 }
180             }
181         }
182       while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
183
184       __set_errno (save_errno);
185     }
186
187   if (written != NULL && data->is_last)
188     *written = do_write / sizeof (wchar_t);
189
190   return result;
191 }
192
193
194 /* Convert from ISO 10646/UCS to ISO 646-IRV.  */
195 int
196 __gconv_transform_ucs4_ascii (struct gconv_step *step,
197                               struct gconv_step_data *data, const char *inbuf,
198                               size_t *inlen, size_t *written, int do_flush)
199 {
200   struct gconv_step *next_step = step + 1;
201   struct gconv_step_data *next_data = data + 1;
202   gconv_fct fct = next_step->fct;
203   size_t do_write;
204   int result;
205
206   /* If the function is called with no input this means we have to reset
207      to the initial state.  The possibly partly converted input is
208      dropped.  */
209   if (do_flush)
210     {
211       /* Clear the state.  */
212       memset (data->statep, '\0', sizeof (mbstate_t));
213       do_write = 0;
214
215       /* Call the steps down the chain if there are any.  */
216       if (data->is_last)
217         result = GCONV_OK;
218       else
219         {
220           struct gconv_step *next_step = step + 1;
221           struct gconv_step_data *next_data = data + 1;
222
223           result = (*fct) (next_step, next_data, NULL, 0, written, 1);
224
225           /* Clear output buffer.  */
226           data->outbufavail = 0;
227         }
228     }
229   else
230     {
231       int save_errno = errno;
232       do_write = 0;
233
234       result = GCONV_OK;
235       do
236         {
237           const wchar_t *newinbuf = (const wchar_t *) inbuf;
238           size_t actually = 0;
239           size_t cnt = 0;
240
241           while (data->outbufavail < data->outbufsize
242                  && cnt + sizeof (wchar_t) + 3 < *inlen)
243             {
244               if (*newinbuf < L'\0' || *newinbuf > L'\x7f')
245                 {
246                   /* This is no correct ANSI_X3.4-1968 character.  */
247                   result = GCONV_ILLEGAL_INPUT;
248                   break;
249                 }
250
251               /* It's an one byte sequence.  */
252               data->outbuf[data->outbufavail++] = (char) *newinbuf;
253               ++actually;
254
255               ++newinbuf;
256               cnt += sizeof (wchar_t);
257             }
258
259           /* Remember how much we converted.  */
260           do_write += cnt / sizeof (wchar_t);
261           *inlen -= cnt;
262
263           /* Check whether an illegal character appeared.  */
264           if (result != GCONV_OK)
265             break;
266
267           if (data->is_last)
268             {
269               /* This is the last step.  */
270               result = (*inlen < sizeof (wchar_t)
271                         ? GCONV_EMPTY_INPUT : GCONV_FULL_OUTPUT);
272               break;
273             }
274
275           /* Status so far.  */
276           result = GCONV_EMPTY_INPUT;
277
278           if (data->outbufavail > 0)
279             {
280               /* Call the functions below in the chain.  */
281               size_t newavail = data->outbufavail;
282
283               result = (*fct) (next_step, next_data, data->outbuf, &newavail,
284                                written, 0);
285
286               /* Correct the output buffer.  */
287               if (newavail != data->outbufavail && newavail > 0)
288                 {
289                   memmove (data->outbuf,
290                            &data->outbuf[data->outbufavail - newavail],
291                            newavail);
292                   data->outbufavail = newavail;
293                 }
294             }
295         }
296       while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
297
298       __set_errno (save_errno);
299     }
300
301   if (written != NULL && data->is_last)
302     *written = do_write;
303
304   return result;
305 }
306
307
308 int
309 __gconv_transform_ucs4_utf8 (struct gconv_step *step,
310                              struct gconv_step_data *data, const char *inbuf,
311                              size_t *inlen, size_t *written, int do_flush)
312 {
313   struct gconv_step *next_step = step + 1;
314   struct gconv_step_data *next_data = data + 1;
315   gconv_fct fct = next_step->fct;
316   size_t do_write;
317   int result;
318
319   /* If the function is called with no input this means we have to reset
320      to the initial state.  The possibly partly converted input is
321      dropped.  */
322   if (do_flush)
323     {
324       /* Clear the state.  */
325       memset (data->statep, '\0', sizeof (mbstate_t));
326       do_write = 0;
327
328       /* Call the steps down the chain if there are any.  */
329       if (data->is_last)
330         result = GCONV_OK;
331       else
332         {
333           struct gconv_step *next_step = step + 1;
334           struct gconv_step_data *next_data = data + 1;
335
336           result = (*fct) (next_step, next_data, NULL, 0, written, 1);
337
338           /* Clear output buffer.  */
339           data->outbufavail = 0;
340         }
341     }
342   else
343     {
344       int save_errno = errno;
345       do_write = 0;
346
347       result = GCONV_OK;
348       do
349         {
350           const wchar_t *newinbuf = (const wchar_t *) inbuf;
351           size_t cnt = 0;
352
353           while (data->outbufavail < data->outbufsize
354                  && cnt * sizeof (wchar_t) + 3 < *inlen)
355             {
356               wchar_t wc = newinbuf[cnt];
357
358               if (wc < 0 && wc > 0x7fffffff)
359                 {
360                   /* This is no correct ISO 10646 character.  */
361                   result = GCONV_ILLEGAL_INPUT;
362                   break;
363                 }
364
365               if (wc < 0x80)
366                 /* It's an one byte sequence.  */
367                 data->outbuf[data->outbufavail++] = (char) wc;
368               else
369                 {
370                   size_t step;
371                   size_t start;
372
373                   for (step = 2; step < 6; ++step)
374                     if ((wc & encoding_mask[step - 2]) == 0)
375                       break;
376
377                   if (data->outbufavail + step >= data->outbufsize)
378                     /* Too long.  */
379                     break;
380
381                   start = data->outbufavail;
382                   data->outbufavail += step;
383                   data->outbuf[start] = encoding_byte[step - 2];
384                   --step;
385                   do
386                     {
387                       data->outbuf[start + step] = 0x80 | (wc & 0x3f);
388                       wc >>= 6;
389                     }
390                   while (--step > 0);
391                   data->outbuf[start] |= wc;
392                 }
393
394               ++cnt;
395             }
396
397           /* Remember how much we converted.  */
398           do_write += cnt;
399           *inlen -= cnt * sizeof (wchar_t);
400
401           /* Check whether an illegal character appeared.  */
402           if (result != GCONV_OK)
403             break;
404
405           if (data->is_last)
406             {
407               /* This is the last step.  */
408               result = (*inlen < sizeof (wchar_t)
409                         ? GCONV_EMPTY_INPUT : GCONV_FULL_OUTPUT);
410               break;
411             }
412
413           /* Status so far.  */
414           result = GCONV_EMPTY_INPUT;
415
416           if (data->outbufavail > 0)
417             {
418               /* Call the functions below in the chain.  */
419               size_t newavail = data->outbufavail;
420
421               result = (*fct) (next_step, next_data, data->outbuf, &newavail,
422                                written, 0);
423
424               /* Correct the output buffer.  */
425               if (newavail != data->outbufavail && newavail > 0)
426                 {
427                   memmove (data->outbuf,
428                            &data->outbuf[data->outbufavail - newavail],
429                            newavail);
430                   data->outbufavail = newavail;
431                 }
432             }
433         }
434       while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
435
436       __set_errno (save_errno);
437     }
438
439   if (written != NULL && data->is_last)
440     *written = do_write;
441
442   return result;
443 }
444
445
446 int
447 __gconv_transform_utf8_ucs4 (struct gconv_step *step,
448                              struct gconv_step_data *data, const char *inbuf,
449                              size_t *inlen, size_t *written, int do_flush)
450 {
451   struct gconv_step *next_step = step + 1;
452   struct gconv_step_data *next_data = data + 1;
453   gconv_fct fct = next_step->fct;
454   size_t do_write;
455   int result;
456
457   /* If the function is called with no input this means we have to reset
458      to the initial state.  The possibly partly converted input is
459      dropped.  */
460   if (do_flush)
461     {
462       /* Clear the state.  */
463       memset (data->statep, '\0', sizeof (mbstate_t));
464       do_write = 0;
465
466       /* Call the steps down the chain if there are any.  */
467       if (data->is_last)
468         result = GCONV_OK;
469       else
470         {
471           struct gconv_step *next_step = step + 1;
472           struct gconv_step_data *next_data = data + 1;
473
474           result = (*fct) (next_step, next_data, NULL, 0, written, 1);
475         }
476     }
477   else
478     {
479       int save_errno = errno;
480       int extra = 0;
481       do_write = 0;
482
483       result = GCONV_OK;
484       do
485         {
486           wchar_t *outbuf = (wchar_t *) &data->outbuf[data->outbufavail];
487           size_t cnt = 0;
488           size_t actually = 0;
489
490           while (data->outbufavail + sizeof (wchar_t) <= data->outbufsize
491                  && cnt < *inlen)
492             {
493               size_t start = cnt;
494               wchar_t value;
495               unsigned char byte;
496               int count;
497
498               /* Next input byte.  */
499               byte = inbuf[cnt++];
500
501               if (byte < 0x80)
502                 {
503                   /* One byte sequence.  */
504                   count = 0;
505                   value = byte;
506                 }
507               else if ((byte & 0xe0) == 0xc0)
508                 {
509                   count = 1;
510                   value = byte & 0x1f;
511                 }
512               else if ((byte & 0xf0) == 0xe0)
513                 {
514                   /* We expect three bytes.  */
515                   count = 2;
516                   value = byte & 0x0f;
517                 }
518               else if ((byte & 0xf8) == 0xf0)
519                 {
520                   /* We expect four bytes.  */
521                   count = 3;
522                   value = byte & 0x07;
523                 }
524               else if ((byte & 0xfc) == 0xf8)
525                 {
526                   /* We expect five bytes.  */
527                   count = 4;
528                   value = byte & 0x03;
529                 }
530               else if ((byte & 0xfe) == 0xfc)
531                 {
532                   /* We expect six bytes.  */
533                   count = 5;
534                   value = byte & 0x01;
535                 }
536               else
537                 {
538                   /* This is an illegal encoding.  */
539                   result = GCONV_ILLEGAL_INPUT;
540                   break;
541                 }
542
543               if (cnt + count > *inlen)
544                 {
545                   /* We don't have enough input.  */
546                   --cnt;
547                   extra = count;
548                   break;
549                 }
550
551               /* Read the possible remaining bytes.  */
552               while (count > 0)
553                 {
554                   byte = inbuf[cnt++];
555                   --count;
556
557                   if ((byte & 0xc0) != 0x80)
558                     {
559                       /* This is an illegal encoding.  */
560                       result = GCONV_ILLEGAL_INPUT;
561                       break;
562                     }
563
564                   value <<= 6;
565                   value |= byte & 0x3f;
566                 }
567
568               if (result != GCONV_OK)
569                 {
570                   cnt = start;
571                   break;
572                 }
573
574               *outbuf++ = value;
575               ++actually;
576             }
577
578           /* Remember how much we converted.  */
579           do_write += actually;
580           *inlen -= cnt;
581
582           data->outbufavail += actually * sizeof (wchar_t);
583
584           /* Check whether an illegal character appeared.  */
585           if (result != GCONV_OK)
586             {
587               result = GCONV_ILLEGAL_INPUT;
588               break;
589             }
590
591           if (*inlen < extra)
592             {
593               /* We have an incomplete character at the end.  */
594               result = GCONV_INCOMPLETE_INPUT;
595               break;
596             }
597
598           if (data->is_last)
599             {
600               /* This is the last step.  */
601               result = (data->outbufavail + sizeof (wchar_t) > data->outbufsize
602                         ? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
603               break;
604             }
605
606           /* Status so far.  */
607           result = GCONV_EMPTY_INPUT;
608
609           if (data->outbufavail > 0)
610             {
611               /* Call the functions below in the chain.  */
612               size_t newavail = data->outbufavail;
613
614               result = (*fct) (next_step, next_data, data->outbuf, &newavail,
615                                written, 0);
616
617               /* Correct the output buffer.  */
618               if (newavail != data->outbufavail && newavail > 0)
619                 {
620                   memmove (data->outbuf,
621                            &data->outbuf[data->outbufavail - newavail],
622                            newavail);
623                   data->outbufavail = newavail;
624                 }
625             }
626         }
627       while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
628
629       __set_errno (save_errno);
630     }
631
632   if (written != NULL && data->is_last)
633     *written = do_write;
634
635   return result;
636 }
637
638
639 int
640 __gconv_transform_ucs2_ucs4 (struct gconv_step *step,
641                              struct gconv_step_data *data, const char *inbuf,
642                              size_t *inlen, size_t *written, int do_flush)
643 {
644   struct gconv_step *next_step = step + 1;
645   struct gconv_step_data *next_data = data + 1;
646   gconv_fct fct = next_step->fct;
647   size_t do_write;
648   int result;
649
650   /* If the function is called with no input this means we have to reset
651      to the initial state.  The possibly partly converted input is
652      dropped.  */
653   if (do_flush)
654     {
655       /* Clear the state.  */
656       memset (data->statep, '\0', sizeof (mbstate_t));
657       do_write = 0;
658
659       /* Call the steps down the chain if there are any.  */
660       if (data->is_last)
661         result = GCONV_OK;
662       else
663         {
664           struct gconv_step *next_step = step + 1;
665           struct gconv_step_data *next_data = data + 1;
666
667           result = (*fct) (next_step, next_data, NULL, 0, written, 1);
668         }
669     }
670   else
671     {
672       int save_errno = errno;
673       do_write = 0;
674
675       do
676         {
677           const uint16_t *newinbuf = (const uint16_t *) inbuf;
678           wchar_t *outbuf = (wchar_t *) &data->outbuf[data->outbufavail];
679           size_t actually = 0;
680
681           errno = 0;
682
683           while (data->outbufavail + 4 <= data->outbufsize
684                  && *inlen >= 2)
685             {
686               outbuf[actually++] = *newinbuf++;
687               data->outbufavail += 4;
688               *inlen -= 2;
689             }
690
691           if (*inlen != 1)
692             {
693               /* We have an incomplete input character.  */
694               mbstate_t *state = data->statep;
695               state->count = 1;
696               state->value = *(uint8_t *) newinbuf;
697               --*inlen;
698             }
699
700           /* Remember how much we converted.  */
701           do_write += actually * sizeof (wchar_t);
702
703           /* Check whether an illegal character appeared.  */
704           if (errno != 0)
705             {
706               result = GCONV_ILLEGAL_INPUT;
707               break;
708             }
709
710           if (*inlen == 0 && !__mbsinit (data->statep))
711             {
712               /* We have an incomplete character at the end.  */
713               result = GCONV_INCOMPLETE_INPUT;
714               break;
715             }
716
717           if (data->is_last)
718             {
719               /* This is the last step.  */
720               result = (data->outbufavail + sizeof (wchar_t) > data->outbufsize
721                         ? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
722               break;
723             }
724
725           /* Status so far.  */
726           result = GCONV_EMPTY_INPUT;
727
728           if (data->outbufavail > 0)
729             {
730               /* Call the functions below in the chain.  */
731               size_t newavail = data->outbufavail;
732
733               result = (*fct) (next_step, next_data, data->outbuf, &newavail,
734                                written, 0);
735
736               /* Correct the output buffer.  */
737               if (newavail != data->outbufavail && newavail > 0)
738                 {
739                   memmove (data->outbuf,
740                            &data->outbuf[data->outbufavail - newavail],
741                            newavail);
742                   data->outbufavail = newavail;
743                 }
744             }
745         }
746       while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
747
748       __set_errno (save_errno);
749     }
750
751   if (written != NULL && data->is_last)
752     *written = do_write;
753
754   return result;
755 }
756
757
758 int
759 __gconv_transform_ucs4_ucs2 (struct gconv_step *step,
760                              struct gconv_step_data *data, const char *inbuf,
761                              size_t *inlen, size_t *written, int do_flush)
762 {
763   struct gconv_step *next_step = step + 1;
764   struct gconv_step_data *next_data = data + 1;
765   gconv_fct fct = next_step->fct;
766   size_t do_write;
767   int result;
768
769   /* If the function is called with no input this means we have to reset
770      to the initial state.  The possibly partly converted input is
771      dropped.  */
772   if (do_flush)
773     {
774       /* Clear the state.  */
775       memset (data->statep, '\0', sizeof (mbstate_t));
776       do_write = 0;
777
778       /* Call the steps down the chain if there are any.  */
779       if (data->is_last)
780         result = GCONV_OK;
781       else
782         {
783           struct gconv_step *next_step = step + 1;
784           struct gconv_step_data *next_data = data + 1;
785
786           result = (*fct) (next_step, next_data, NULL, 0, written, 1);
787
788           /* Clear output buffer.  */
789           data->outbufavail = 0;
790         }
791     }
792   else
793     {
794       int save_errno = errno;
795       do_write = 0;
796
797       do
798         {
799           const wchar_t *newinbuf = (const wchar_t *) inbuf;
800           uint16_t *outbuf = (uint16_t *) &data->outbuf[data->outbufavail];
801           size_t actually = 0;
802
803           errno = 0;
804
805           while (data->outbufavail + 2 <= data->outbufsize
806                  && *inlen >= 4)
807             {
808               if (*newinbuf >= 0x10000)
809                 {
810                   __set_errno (EILSEQ);
811                     break;
812                 }
813               outbuf[actually++] = (wchar_t) *newinbuf;
814               *inlen -= 4;
815               data->outbufavail += 2;
816             }
817
818           if (*inlen < 4)
819             {
820               /* We have an incomplete input character.  */
821               mbstate_t *state = data->statep;
822               state->count = *inlen;
823               state->value = 0;
824               while (*inlen > 0)
825                 {
826                   state->value <<= 8;
827                   state->value += *(uint8_t *) newinbuf;
828                   --*inlen;
829                 }
830             }
831
832           /* Remember how much we converted.  */
833           do_write += (const char *) newinbuf - inbuf;
834
835           /* Check whether an illegal character appeared.  */
836           if (errno != 0)
837             {
838               result = GCONV_ILLEGAL_INPUT;
839               break;
840             }
841
842           if (*inlen == 0 && !__mbsinit (data->statep))
843             {
844               /* We have an incomplete character at the end.  */
845               result = GCONV_INCOMPLETE_INPUT;
846               break;
847             }
848
849           if (data->is_last)
850             {
851               /* This is the last step.  */
852               result = *inlen == 0 ? GCONV_EMPTY_INPUT : GCONV_FULL_OUTPUT;
853               break;
854             }
855
856           /* Status so far.  */
857           result = GCONV_EMPTY_INPUT;
858
859           if (data->outbufavail > 0)
860             {
861               /* Call the functions below in the chain.  */
862               size_t newavail = data->outbufavail;
863
864               result = (*fct) (next_step, next_data, data->outbuf, &newavail,
865                                written, 0);
866
867               /* Correct the output buffer.  */
868               if (newavail != data->outbufavail && newavail > 0)
869                 {
870                   memmove (data->outbuf,
871                            &data->outbuf[data->outbufavail - newavail],
872                            newavail);
873                   data->outbufavail = newavail;
874                 }
875             }
876         }
877       while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
878
879       __set_errno (save_errno);
880     }
881
882   if (written != NULL && data->is_last)
883     *written = do_write / sizeof (wchar_t);
884
885   return result;
886 }