Blame gettext-runtime/gnulib-lib/iconv.c

Packit Bot 06c835
/* Character set conversion.
Packit Bot 06c835
   Copyright (C) 1999-2001, 2007, 2009-2015 Free Software Foundation, Inc.
Packit Bot 06c835
Packit Bot 06c835
   This program is free software; you can redistribute it and/or modify
Packit Bot 06c835
   it under the terms of the GNU General Public License as published by
Packit Bot 06c835
   the Free Software Foundation; either version 3, or (at your option)
Packit Bot 06c835
   any later version.
Packit Bot 06c835
Packit Bot 06c835
   This program is distributed in the hope that it will be useful,
Packit Bot 06c835
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Bot 06c835
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Bot 06c835
   GNU General Public License for more details.
Packit Bot 06c835
Packit Bot 06c835
   You should have received a copy of the GNU General Public License along
Packit Bot 06c835
   with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit Bot 06c835
Packit Bot 06c835
#include <config.h>
Packit Bot 06c835
Packit Bot 06c835
/* Specification.  */
Packit Bot 06c835
#include <iconv.h>
Packit Bot 06c835
Packit Bot 06c835
#include <stddef.h>
Packit Bot 06c835
Packit Bot 06c835
#if REPLACE_ICONV_UTF
Packit Bot 06c835
# include <errno.h>
Packit Bot 06c835
# include <stdint.h>
Packit Bot 06c835
# include <stdlib.h>
Packit Bot 06c835
# include "unistr.h"
Packit Bot 06c835
# ifndef uintptr_t
Packit Bot 06c835
#  define uintptr_t unsigned long
Packit Bot 06c835
# endif
Packit Bot 06c835
#endif
Packit Bot 06c835
Packit Bot 06c835
#if REPLACE_ICONV_UTF
Packit Bot 06c835
Packit Bot 06c835
/* UTF-{16,32}{BE,LE} converters taken from GNU libiconv 1.11.  */
Packit Bot 06c835
Packit Bot 06c835
/* Return code if invalid. (xxx_mbtowc) */
Packit Bot 06c835
# define RET_ILSEQ      -1
Packit Bot 06c835
/* Return code if no bytes were read. (xxx_mbtowc) */
Packit Bot 06c835
# define RET_TOOFEW     -2
Packit Bot 06c835
Packit Bot 06c835
/* Return code if invalid. (xxx_wctomb) */
Packit Bot 06c835
# define RET_ILUNI      -1
Packit Bot 06c835
/* Return code if output buffer is too small. (xxx_wctomb, xxx_reset) */
Packit Bot 06c835
# define RET_TOOSMALL   -2
Packit Bot 06c835
Packit Bot 06c835
/*
Packit Bot 06c835
 * UTF-16BE
Packit Bot 06c835
 */
Packit Bot 06c835
Packit Bot 06c835
/* Specification: RFC 2781 */
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
utf16be_mbtowc (ucs4_t *pwc, const unsigned char *s, size_t n)
Packit Bot 06c835
{
Packit Bot 06c835
  if (n >= 2)
Packit Bot 06c835
    {
Packit Bot 06c835
      ucs4_t wc = (s[0] << 8) + s[1];
Packit Bot 06c835
      if (wc >= 0xd800 && wc < 0xdc00)
Packit Bot 06c835
        {
Packit Bot 06c835
          if (n >= 4)
Packit Bot 06c835
            {
Packit Bot 06c835
              ucs4_t wc2 = (s[2] << 8) + s[3];
Packit Bot 06c835
              if (!(wc2 >= 0xdc00 && wc2 < 0xe000))
Packit Bot 06c835
                return RET_ILSEQ;
Packit Bot 06c835
              *pwc = 0x10000 + ((wc - 0xd800) << 10) + (wc2 - 0xdc00);
Packit Bot 06c835
              return 4;
Packit Bot 06c835
            }
Packit Bot 06c835
        }
Packit Bot 06c835
      else if (wc >= 0xdc00 && wc < 0xe000)
Packit Bot 06c835
        {
Packit Bot 06c835
          return RET_ILSEQ;
Packit Bot 06c835
        }
Packit Bot 06c835
      else
Packit Bot 06c835
        {
Packit Bot 06c835
          *pwc = wc;
Packit Bot 06c835
          return 2;
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
  return RET_TOOFEW;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
utf16be_wctomb (unsigned char *r, ucs4_t wc, size_t n)
Packit Bot 06c835
{
Packit Bot 06c835
  if (!(wc >= 0xd800 && wc < 0xe000))
Packit Bot 06c835
    {
Packit Bot 06c835
      if (wc < 0x10000)
Packit Bot 06c835
        {
Packit Bot 06c835
          if (n >= 2)
Packit Bot 06c835
            {
Packit Bot 06c835
              r[0] = (unsigned char) (wc >> 8);
Packit Bot 06c835
              r[1] = (unsigned char) wc;
Packit Bot 06c835
              return 2;
Packit Bot 06c835
            }
Packit Bot 06c835
          else
Packit Bot 06c835
            return RET_TOOSMALL;
Packit Bot 06c835
        }
Packit Bot 06c835
      else if (wc < 0x110000)
Packit Bot 06c835
        {
Packit Bot 06c835
          if (n >= 4)
Packit Bot 06c835
            {
Packit Bot 06c835
              ucs4_t wc1 = 0xd800 + ((wc - 0x10000) >> 10);
Packit Bot 06c835
              ucs4_t wc2 = 0xdc00 + ((wc - 0x10000) & 0x3ff);
Packit Bot 06c835
              r[0] = (unsigned char) (wc1 >> 8);
Packit Bot 06c835
              r[1] = (unsigned char) wc1;
Packit Bot 06c835
              r[2] = (unsigned char) (wc2 >> 8);
Packit Bot 06c835
              r[3] = (unsigned char) wc2;
Packit Bot 06c835
              return 4;
Packit Bot 06c835
            }
Packit Bot 06c835
          else
Packit Bot 06c835
            return RET_TOOSMALL;
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
  return RET_ILUNI;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/*
Packit Bot 06c835
 * UTF-16LE
Packit Bot 06c835
 */
Packit Bot 06c835
Packit Bot 06c835
/* Specification: RFC 2781 */
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
utf16le_mbtowc (ucs4_t *pwc, const unsigned char *s, size_t n)
Packit Bot 06c835
{
Packit Bot 06c835
  if (n >= 2)
Packit Bot 06c835
    {
Packit Bot 06c835
      ucs4_t wc = s[0] + (s[1] << 8);
Packit Bot 06c835
      if (wc >= 0xd800 && wc < 0xdc00)
Packit Bot 06c835
        {
Packit Bot 06c835
          if (n >= 4)
Packit Bot 06c835
            {
Packit Bot 06c835
              ucs4_t wc2 = s[2] + (s[3] << 8);
Packit Bot 06c835
              if (!(wc2 >= 0xdc00 && wc2 < 0xe000))
Packit Bot 06c835
                return RET_ILSEQ;
Packit Bot 06c835
              *pwc = 0x10000 + ((wc - 0xd800) << 10) + (wc2 - 0xdc00);
Packit Bot 06c835
              return 4;
Packit Bot 06c835
            }
Packit Bot 06c835
        }
Packit Bot 06c835
      else if (wc >= 0xdc00 && wc < 0xe000)
Packit Bot 06c835
        {
Packit Bot 06c835
          return RET_ILSEQ;
Packit Bot 06c835
        }
Packit Bot 06c835
      else
Packit Bot 06c835
        {
Packit Bot 06c835
          *pwc = wc;
Packit Bot 06c835
          return 2;
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
  return RET_TOOFEW;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
utf16le_wctomb (unsigned char *r, ucs4_t wc, size_t n)
Packit Bot 06c835
{
Packit Bot 06c835
  if (!(wc >= 0xd800 && wc < 0xe000))
Packit Bot 06c835
    {
Packit Bot 06c835
      if (wc < 0x10000)
Packit Bot 06c835
        {
Packit Bot 06c835
          if (n >= 2)
Packit Bot 06c835
            {
Packit Bot 06c835
              r[0] = (unsigned char) wc;
Packit Bot 06c835
              r[1] = (unsigned char) (wc >> 8);
Packit Bot 06c835
              return 2;
Packit Bot 06c835
            }
Packit Bot 06c835
          else
Packit Bot 06c835
            return RET_TOOSMALL;
Packit Bot 06c835
        }
Packit Bot 06c835
      else if (wc < 0x110000)
Packit Bot 06c835
        {
Packit Bot 06c835
          if (n >= 4)
Packit Bot 06c835
            {
Packit Bot 06c835
              ucs4_t wc1 = 0xd800 + ((wc - 0x10000) >> 10);
Packit Bot 06c835
              ucs4_t wc2 = 0xdc00 + ((wc - 0x10000) & 0x3ff);
Packit Bot 06c835
              r[0] = (unsigned char) wc1;
Packit Bot 06c835
              r[1] = (unsigned char) (wc1 >> 8);
Packit Bot 06c835
              r[2] = (unsigned char) wc2;
Packit Bot 06c835
              r[3] = (unsigned char) (wc2 >> 8);
Packit Bot 06c835
              return 4;
Packit Bot 06c835
            }
Packit Bot 06c835
          else
Packit Bot 06c835
            return RET_TOOSMALL;
Packit Bot 06c835
        }
Packit Bot 06c835
    }
Packit Bot 06c835
  return RET_ILUNI;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/*
Packit Bot 06c835
 * UTF-32BE
Packit Bot 06c835
 */
Packit Bot 06c835
Packit Bot 06c835
/* Specification: Unicode 3.1 Standard Annex #19 */
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
utf32be_mbtowc (ucs4_t *pwc, const unsigned char *s, size_t n)
Packit Bot 06c835
{
Packit Bot 06c835
  if (n >= 4)
Packit Bot 06c835
    {
Packit Bot 06c835
      ucs4_t wc = (s[0] << 24) + (s[1] << 16) + (s[2] << 8) + s[3];
Packit Bot 06c835
      if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000))
Packit Bot 06c835
        {
Packit Bot 06c835
          *pwc = wc;
Packit Bot 06c835
          return 4;
Packit Bot 06c835
        }
Packit Bot 06c835
      else
Packit Bot 06c835
        return RET_ILSEQ;
Packit Bot 06c835
    }
Packit Bot 06c835
  return RET_TOOFEW;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
utf32be_wctomb (unsigned char *r, ucs4_t wc, size_t n)
Packit Bot 06c835
{
Packit Bot 06c835
  if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000))
Packit Bot 06c835
    {
Packit Bot 06c835
      if (n >= 4)
Packit Bot 06c835
        {
Packit Bot 06c835
          r[0] = 0;
Packit Bot 06c835
          r[1] = (unsigned char) (wc >> 16);
Packit Bot 06c835
          r[2] = (unsigned char) (wc >> 8);
Packit Bot 06c835
          r[3] = (unsigned char) wc;
Packit Bot 06c835
          return 4;
Packit Bot 06c835
        }
Packit Bot 06c835
      else
Packit Bot 06c835
        return RET_TOOSMALL;
Packit Bot 06c835
    }
Packit Bot 06c835
  return RET_ILUNI;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
/*
Packit Bot 06c835
 * UTF-32LE
Packit Bot 06c835
 */
Packit Bot 06c835
Packit Bot 06c835
/* Specification: Unicode 3.1 Standard Annex #19 */
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
utf32le_mbtowc (ucs4_t *pwc, const unsigned char *s, size_t n)
Packit Bot 06c835
{
Packit Bot 06c835
  if (n >= 4)
Packit Bot 06c835
    {
Packit Bot 06c835
      ucs4_t wc = s[0] + (s[1] << 8) + (s[2] << 16) + (s[3] << 24);
Packit Bot 06c835
      if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000))
Packit Bot 06c835
        {
Packit Bot 06c835
          *pwc = wc;
Packit Bot 06c835
          return 4;
Packit Bot 06c835
        }
Packit Bot 06c835
      else
Packit Bot 06c835
        return RET_ILSEQ;
Packit Bot 06c835
    }
Packit Bot 06c835
  return RET_TOOFEW;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
static int
Packit Bot 06c835
utf32le_wctomb (unsigned char *r, ucs4_t wc, size_t n)
Packit Bot 06c835
{
Packit Bot 06c835
  if (wc < 0x110000 && !(wc >= 0xd800 && wc < 0xe000))
Packit Bot 06c835
    {
Packit Bot 06c835
      if (n >= 4)
Packit Bot 06c835
        {
Packit Bot 06c835
          r[0] = (unsigned char) wc;
Packit Bot 06c835
          r[1] = (unsigned char) (wc >> 8);
Packit Bot 06c835
          r[2] = (unsigned char) (wc >> 16);
Packit Bot 06c835
          r[3] = 0;
Packit Bot 06c835
          return 4;
Packit Bot 06c835
        }
Packit Bot 06c835
      else
Packit Bot 06c835
        return RET_TOOSMALL;
Packit Bot 06c835
    }
Packit Bot 06c835
  return RET_ILUNI;
Packit Bot 06c835
}
Packit Bot 06c835
Packit Bot 06c835
#endif
Packit Bot 06c835
Packit Bot 06c835
size_t
Packit Bot 06c835
rpl_iconv (iconv_t cd,
Packit Bot 06c835
           ICONV_CONST char **inbuf, size_t *inbytesleft,
Packit Bot 06c835
           char **outbuf, size_t *outbytesleft)
Packit Bot 06c835
#undef iconv
Packit Bot 06c835
{
Packit Bot 06c835
#if REPLACE_ICONV_UTF
Packit Bot 06c835
  switch ((uintptr_t) cd)
Packit Bot 06c835
    {
Packit Bot 06c835
      {
Packit Bot 06c835
        int (*xxx_wctomb) (unsigned char *, ucs4_t, size_t);
Packit Bot 06c835
Packit Bot 06c835
        case (uintptr_t) _ICONV_UTF8_UTF16BE:
Packit Bot 06c835
          xxx_wctomb = utf16be_wctomb;
Packit Bot 06c835
          goto loop_from_utf8;
Packit Bot 06c835
        case (uintptr_t) _ICONV_UTF8_UTF16LE:
Packit Bot 06c835
          xxx_wctomb = utf16le_wctomb;
Packit Bot 06c835
          goto loop_from_utf8;
Packit Bot 06c835
        case (uintptr_t) _ICONV_UTF8_UTF32BE:
Packit Bot 06c835
          xxx_wctomb = utf32be_wctomb;
Packit Bot 06c835
          goto loop_from_utf8;
Packit Bot 06c835
        case (uintptr_t) _ICONV_UTF8_UTF32LE:
Packit Bot 06c835
          xxx_wctomb = utf32le_wctomb;
Packit Bot 06c835
          goto loop_from_utf8;
Packit Bot 06c835
Packit Bot 06c835
       loop_from_utf8:
Packit Bot 06c835
        if (inbuf == NULL || *inbuf == NULL)
Packit Bot 06c835
          return 0;
Packit Bot 06c835
        {
Packit Bot 06c835
          ICONV_CONST char *inptr = *inbuf;
Packit Bot 06c835
          size_t inleft = *inbytesleft;
Packit Bot 06c835
          char *outptr = *outbuf;
Packit Bot 06c835
          size_t outleft = *outbytesleft;
Packit Bot 06c835
          size_t res = 0;
Packit Bot 06c835
          while (inleft > 0)
Packit Bot 06c835
            {
Packit Bot 06c835
              ucs4_t uc;
Packit Bot 06c835
              int m = u8_mbtoucr (&uc, (const uint8_t *) inptr, inleft);
Packit Bot 06c835
              if (m <= 0)
Packit Bot 06c835
                {
Packit Bot 06c835
                  if (m == -1)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      errno = EILSEQ;
Packit Bot 06c835
                      res = (size_t)(-1);
Packit Bot 06c835
                      break;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  if (m == -2)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      errno = EINVAL;
Packit Bot 06c835
                      res = (size_t)(-1);
Packit Bot 06c835
                      break;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  abort ();
Packit Bot 06c835
                }
Packit Bot 06c835
              else
Packit Bot 06c835
                {
Packit Bot 06c835
                  int n = xxx_wctomb ((uint8_t *) outptr, uc, outleft);
Packit Bot 06c835
                  if (n < 0)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      if (n == RET_ILUNI)
Packit Bot 06c835
                        {
Packit Bot 06c835
                          errno = EILSEQ;
Packit Bot 06c835
                          res = (size_t)(-1);
Packit Bot 06c835
                          break;
Packit Bot 06c835
                        }
Packit Bot 06c835
                      if (n == RET_TOOSMALL)
Packit Bot 06c835
                        {
Packit Bot 06c835
                          errno = E2BIG;
Packit Bot 06c835
                          res = (size_t)(-1);
Packit Bot 06c835
                          break;
Packit Bot 06c835
                        }
Packit Bot 06c835
                      abort ();
Packit Bot 06c835
                    }
Packit Bot 06c835
                  else
Packit Bot 06c835
                    {
Packit Bot 06c835
                      inptr += m;
Packit Bot 06c835
                      inleft -= m;
Packit Bot 06c835
                      outptr += n;
Packit Bot 06c835
                      outleft -= n;
Packit Bot 06c835
                    }
Packit Bot 06c835
                }
Packit Bot 06c835
            }
Packit Bot 06c835
          *inbuf = inptr;
Packit Bot 06c835
          *inbytesleft = inleft;
Packit Bot 06c835
          *outbuf = outptr;
Packit Bot 06c835
          *outbytesleft = outleft;
Packit Bot 06c835
          return res;
Packit Bot 06c835
        }
Packit Bot 06c835
      }
Packit Bot 06c835
Packit Bot 06c835
      {
Packit Bot 06c835
        int (*xxx_mbtowc) (ucs4_t *, const unsigned char *, size_t);
Packit Bot 06c835
Packit Bot 06c835
        case (uintptr_t) _ICONV_UTF16BE_UTF8:
Packit Bot 06c835
          xxx_mbtowc = utf16be_mbtowc;
Packit Bot 06c835
          goto loop_to_utf8;
Packit Bot 06c835
        case (uintptr_t) _ICONV_UTF16LE_UTF8:
Packit Bot 06c835
          xxx_mbtowc = utf16le_mbtowc;
Packit Bot 06c835
          goto loop_to_utf8;
Packit Bot 06c835
        case (uintptr_t) _ICONV_UTF32BE_UTF8:
Packit Bot 06c835
          xxx_mbtowc = utf32be_mbtowc;
Packit Bot 06c835
          goto loop_to_utf8;
Packit Bot 06c835
        case (uintptr_t) _ICONV_UTF32LE_UTF8:
Packit Bot 06c835
          xxx_mbtowc = utf32le_mbtowc;
Packit Bot 06c835
          goto loop_to_utf8;
Packit Bot 06c835
Packit Bot 06c835
       loop_to_utf8:
Packit Bot 06c835
        if (inbuf == NULL || *inbuf == NULL)
Packit Bot 06c835
          return 0;
Packit Bot 06c835
        {
Packit Bot 06c835
          ICONV_CONST char *inptr = *inbuf;
Packit Bot 06c835
          size_t inleft = *inbytesleft;
Packit Bot 06c835
          char *outptr = *outbuf;
Packit Bot 06c835
          size_t outleft = *outbytesleft;
Packit Bot 06c835
          size_t res = 0;
Packit Bot 06c835
          while (inleft > 0)
Packit Bot 06c835
            {
Packit Bot 06c835
              ucs4_t uc;
Packit Bot 06c835
              int m = xxx_mbtowc (&uc, (const uint8_t *) inptr, inleft);
Packit Bot 06c835
              if (m <= 0)
Packit Bot 06c835
                {
Packit Bot 06c835
                  if (m == RET_ILSEQ)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      errno = EILSEQ;
Packit Bot 06c835
                      res = (size_t)(-1);
Packit Bot 06c835
                      break;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  if (m == RET_TOOFEW)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      errno = EINVAL;
Packit Bot 06c835
                      res = (size_t)(-1);
Packit Bot 06c835
                      break;
Packit Bot 06c835
                    }
Packit Bot 06c835
                  abort ();
Packit Bot 06c835
                }
Packit Bot 06c835
              else
Packit Bot 06c835
                {
Packit Bot 06c835
                  int n = u8_uctomb ((uint8_t *) outptr, uc, outleft);
Packit Bot 06c835
                  if (n < 0)
Packit Bot 06c835
                    {
Packit Bot 06c835
                      if (n == -1)
Packit Bot 06c835
                        {
Packit Bot 06c835
                          errno = EILSEQ;
Packit Bot 06c835
                          res = (size_t)(-1);
Packit Bot 06c835
                          break;
Packit Bot 06c835
                        }
Packit Bot 06c835
                      if (n == -2)
Packit Bot 06c835
                        {
Packit Bot 06c835
                          errno = E2BIG;
Packit Bot 06c835
                          res = (size_t)(-1);
Packit Bot 06c835
                          break;
Packit Bot 06c835
                        }
Packit Bot 06c835
                      abort ();
Packit Bot 06c835
                    }
Packit Bot 06c835
                  else
Packit Bot 06c835
                    {
Packit Bot 06c835
                      inptr += m;
Packit Bot 06c835
                      inleft -= m;
Packit Bot 06c835
                      outptr += n;
Packit Bot 06c835
                      outleft -= n;
Packit Bot 06c835
                    }
Packit Bot 06c835
                }
Packit Bot 06c835
            }
Packit Bot 06c835
          *inbuf = inptr;
Packit Bot 06c835
          *inbytesleft = inleft;
Packit Bot 06c835
          *outbuf = outptr;
Packit Bot 06c835
          *outbytesleft = outleft;
Packit Bot 06c835
          return res;
Packit Bot 06c835
        }
Packit Bot 06c835
      }
Packit Bot 06c835
    }
Packit Bot 06c835
#endif
Packit Bot 06c835
  return iconv (cd, inbuf, inbytesleft, outbuf, outbytesleft);
Packit Bot 06c835
}