Blame lib/iconv.c

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