diff options
Diffstat (limited to 'iconv/gconv.c')
-rw-r--r-- | iconv/gconv.c | 53 |
1 files changed, 36 insertions, 17 deletions
diff --git a/iconv/gconv.c b/iconv/gconv.c index f8b7c8050d..aa58bdba7d 100644 --- a/iconv/gconv.c +++ b/iconv/gconv.c @@ -19,39 +19,58 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <assert.h> #include <gconv.h> +#include <sys/param.h> int internal_function -__gconv (gconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, - size_t *outbytesleft, size_t *converted) +__gconv (gconv_t cd, const char **inbuf, const char *inbufend, char **outbuf, + char *outbufend, size_t *converted) { size_t last_step = cd->nsteps - 1; - size_t oldinbytes = *inbytesleft; int result; if (cd == (gconv_t) -1L) return GCONV_ILLEGAL_DESCRIPTOR; - cd->data[last_step].outbuf = outbuf ? *outbuf : NULL; - cd->data[last_step].outbufavail = 0; - cd->data[last_step].outbufsize = *outbytesleft; + assert (converted != NULL); + *converted = 0; - if (converted != NULL) - *converted = 0; + if (inbuf == NULL || *inbuf == NULL) + /* We just flush. */ + result = (*cd->steps->fct) (cd->steps, cd->data, NULL, NULL, converted, 1); + else + { + const char *last_start; - result = (*cd->steps->fct) (cd->steps, cd->data, - inbuf ? *inbuf : NULL, inbytesleft, - converted, inbuf == NULL || *inbuf == NULL); + assert (outbuf != NULL && *outbuf != NULL); + cd->data[last_step].outbuf = *outbuf; + cd->data[last_step].outbufend = outbufend; - if (inbuf != NULL && *inbuf != NULL) - *inbuf += oldinbytes - *inbytesleft; - if (outbuf != NULL && *outbuf != NULL) - { - *outbuf += cd->data[last_step].outbufavail; - *outbytesleft -= cd->data[last_step].outbufavail; + do + { + /* See whether the input size is reasoable for the output + size. If not adjust it. */ + size_t inlen = ((inbufend - *inbuf) / cd->steps->max_needed_from + * cd->steps->max_needed_from); + + if (cd->nsteps > 1) + inlen = MIN (inlen, (((outbufend - cd->data[last_step].outbuf) + / cd->steps[last_step].max_needed_to) + * cd->steps[last_step].max_needed_to)); + + last_start = *inbuf; + result = (*cd->steps->fct) (cd->steps, cd->data, inbuf, + *inbuf + inlen, converted, 0); + } + while (result == GCONV_EMPTY_INPUT && last_start != *inbuf + && *inbuf + cd->steps->min_needed_from <= inbufend); } + if (outbuf != NULL && *outbuf != NULL) + *outbuf = cd->data[last_step].outbuf; + return result; } |