Blame lib/iconv_open.c

Packit 33f14e
/* Character set conversion.
Packit 33f14e
   Copyright (C) 2007, 2009-2017 Free Software Foundation, Inc.
Packit 33f14e
Packit 33f14e
   This program is free software; you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation; either version 3, or (at your option)
Packit 33f14e
   any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License along
Packit 33f14e
   with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
#include <config.h>
Packit 33f14e
Packit 33f14e
/* Specification.  */
Packit 33f14e
#include <iconv.h>
Packit 33f14e
Packit 33f14e
#include <errno.h>
Packit 33f14e
#include <string.h>
Packit 33f14e
#include "c-ctype.h"
Packit 33f14e
#include "c-strcase.h"
Packit 33f14e
Packit 33f14e
#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
Packit 33f14e
Packit 33f14e
/* Namespace cleanliness.  */
Packit 33f14e
#define mapping_lookup rpl_iconv_open_mapping_lookup
Packit 33f14e
Packit 33f14e
/* The macro ICONV_FLAVOR is defined to one of these or undefined.  */
Packit 33f14e
Packit 33f14e
#define ICONV_FLAVOR_AIX "iconv_open-aix.h"
Packit 33f14e
#define ICONV_FLAVOR_HPUX "iconv_open-hpux.h"
Packit 33f14e
#define ICONV_FLAVOR_IRIX "iconv_open-irix.h"
Packit 33f14e
#define ICONV_FLAVOR_OSF "iconv_open-osf.h"
Packit 33f14e
#define ICONV_FLAVOR_SOLARIS "iconv_open-solaris.h"
Packit 33f14e
Packit 33f14e
#ifdef ICONV_FLAVOR
Packit 33f14e
# include ICONV_FLAVOR
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
iconv_t
Packit 33f14e
rpl_iconv_open (const char *tocode, const char *fromcode)
Packit 33f14e
#undef iconv_open
Packit 33f14e
{
Packit 33f14e
  char fromcode_upper[32];
Packit 33f14e
  char tocode_upper[32];
Packit 33f14e
  char *fromcode_upper_end;
Packit 33f14e
  char *tocode_upper_end;
Packit 33f14e
Packit 33f14e
#if REPLACE_ICONV_UTF
Packit 33f14e
  /* Special handling of conversion between UTF-8 and UTF-{16,32}{BE,LE}.
Packit 33f14e
     Do this here, before calling the real iconv_open(), because  OSF/1 5.1
Packit 33f14e
     iconv() to these encoding inserts a BOM, which is wrong.
Packit 33f14e
     We do not need to handle conversion between arbitrary encodings and
Packit 33f14e
     UTF-{16,32}{BE,LE}, because the 'striconveh' module implements two-step
Packit 33f14e
     conversion through UTF-8.
Packit 33f14e
     The _ICONV_* constants are chosen to be disjoint from any iconv_t
Packit 33f14e
     returned by the system's iconv_open() functions.  Recall that iconv_t
Packit 33f14e
     is a scalar type.  */
Packit 33f14e
  if (c_toupper (fromcode[0]) == 'U'
Packit 33f14e
      && c_toupper (fromcode[1]) == 'T'
Packit 33f14e
      && c_toupper (fromcode[2]) == 'F'
Packit 33f14e
      && fromcode[3] == '-')
Packit 33f14e
    {
Packit 33f14e
      if (c_toupper (tocode[0]) == 'U'
Packit 33f14e
          && c_toupper (tocode[1]) == 'T'
Packit 33f14e
          && c_toupper (tocode[2]) == 'F'
Packit 33f14e
          && tocode[3] == '-')
Packit 33f14e
        {
Packit 33f14e
          if (strcmp (fromcode + 4, "8") == 0)
Packit 33f14e
            {
Packit 33f14e
              if (c_strcasecmp (tocode + 4, "16BE") == 0)
Packit 33f14e
                return _ICONV_UTF8_UTF16BE;
Packit 33f14e
              if (c_strcasecmp (tocode + 4, "16LE") == 0)
Packit 33f14e
                return _ICONV_UTF8_UTF16LE;
Packit 33f14e
              if (c_strcasecmp (tocode + 4, "32BE") == 0)
Packit 33f14e
                return _ICONV_UTF8_UTF32BE;
Packit 33f14e
              if (c_strcasecmp (tocode + 4, "32LE") == 0)
Packit 33f14e
                return _ICONV_UTF8_UTF32LE;
Packit 33f14e
            }
Packit 33f14e
          else if (strcmp (tocode + 4, "8") == 0)
Packit 33f14e
            {
Packit 33f14e
              if (c_strcasecmp (fromcode + 4, "16BE") == 0)
Packit 33f14e
                return _ICONV_UTF16BE_UTF8;
Packit 33f14e
              if (c_strcasecmp (fromcode + 4, "16LE") == 0)
Packit 33f14e
                return _ICONV_UTF16LE_UTF8;
Packit 33f14e
              if (c_strcasecmp (fromcode + 4, "32BE") == 0)
Packit 33f14e
                return _ICONV_UTF32BE_UTF8;
Packit 33f14e
              if (c_strcasecmp (fromcode + 4, "32LE") == 0)
Packit 33f14e
                return _ICONV_UTF32LE_UTF8;
Packit 33f14e
            }
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
  /* Do *not* add special support for 8-bit encodings like ASCII or ISO-8859-1
Packit 33f14e
     here.  This would lead to programs that work in some locales (such as the
Packit 33f14e
     "C" or "en_US" locales) but do not work in East Asian locales.  It is
Packit 33f14e
     better if programmers make their programs depend on GNU libiconv (except
Packit 33f14e
     on glibc systems), e.g. by using the AM_ICONV macro and documenting the
Packit 33f14e
     dependency in an INSTALL or DEPENDENCIES file.  */
Packit 33f14e
Packit 33f14e
  /* Try with the original names first.
Packit 33f14e
     This covers the case when fromcode or tocode is a lowercase encoding name
Packit 33f14e
     that is understood by the system's iconv_open but not listed in our
Packit 33f14e
     mappings table.  */
Packit 33f14e
  {
Packit 33f14e
    iconv_t cd = iconv_open (tocode, fromcode);
Packit 33f14e
    if (cd != (iconv_t)(-1))
Packit 33f14e
      return cd;
Packit 33f14e
  }
Packit 33f14e
Packit 33f14e
  /* Convert the encodings to upper case, because
Packit 33f14e
       1. in the arguments of iconv_open() on AIX, HP-UX, and OSF/1 the case
Packit 33f14e
          matters,
Packit 33f14e
       2. it makes searching in the table faster.  */
Packit 33f14e
  {
Packit 33f14e
    const char *p = fromcode;
Packit 33f14e
    char *q = fromcode_upper;
Packit 33f14e
    while ((*q = c_toupper (*p)) != '\0')
Packit 33f14e
      {
Packit 33f14e
        p++;
Packit 33f14e
        q++;
Packit 33f14e
        if (q == &fromcode_upper[SIZEOF (fromcode_upper)])
Packit 33f14e
          {
Packit 33f14e
            errno = EINVAL;
Packit 33f14e
            return (iconv_t)(-1);
Packit 33f14e
          }
Packit 33f14e
      }
Packit 33f14e
    fromcode_upper_end = q;
Packit 33f14e
  }
Packit 33f14e
Packit 33f14e
  {
Packit 33f14e
    const char *p = tocode;
Packit 33f14e
    char *q = tocode_upper;
Packit 33f14e
    while ((*q = c_toupper (*p)) != '\0')
Packit 33f14e
      {
Packit 33f14e
        p++;
Packit 33f14e
        q++;
Packit 33f14e
        if (q == &tocode_upper[SIZEOF (tocode_upper)])
Packit 33f14e
          {
Packit 33f14e
            errno = EINVAL;
Packit 33f14e
            return (iconv_t)(-1);
Packit 33f14e
          }
Packit 33f14e
      }
Packit 33f14e
    tocode_upper_end = q;
Packit 33f14e
  }
Packit 33f14e
Packit 33f14e
#ifdef ICONV_FLAVOR
Packit 33f14e
  /* Apply the mappings.  */
Packit 33f14e
  {
Packit 33f14e
    const struct mapping *m =
Packit 33f14e
      mapping_lookup (fromcode_upper, fromcode_upper_end - fromcode_upper);
Packit 33f14e
Packit 33f14e
    fromcode = (m != NULL ? m->vendor_name : fromcode_upper);
Packit 33f14e
  }
Packit 33f14e
  {
Packit 33f14e
    const struct mapping *m =
Packit 33f14e
      mapping_lookup (tocode_upper, tocode_upper_end - tocode_upper);
Packit 33f14e
Packit 33f14e
    tocode = (m != NULL ? m->vendor_name : tocode_upper);
Packit 33f14e
  }
Packit 33f14e
#else
Packit 33f14e
  fromcode = fromcode_upper;
Packit 33f14e
  tocode = tocode_upper;
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
  return iconv_open (tocode, fromcode);
Packit 33f14e
}