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

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