(root)/
gettext-0.22.4/
gettext-tools/
libgettextpo/
iconv_open.c
       1  /* Character set conversion.
       2     Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  /* Specification.  */
      20  #include <iconv.h>
      21  
      22  #include <errno.h>
      23  #include <string.h>
      24  #include "c-ctype.h"
      25  #include "c-strcase.h"
      26  
      27  #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
      28  
      29  /* Namespace cleanliness.  */
      30  #define mapping_lookup rpl_iconv_open_mapping_lookup
      31  
      32  /* The macro ICONV_FLAVOR is defined to one of these or undefined.  */
      33  
      34  #define ICONV_FLAVOR_AIX "iconv_open-aix.h"
      35  #define ICONV_FLAVOR_HPUX "iconv_open-hpux.h"
      36  #define ICONV_FLAVOR_IRIX "iconv_open-irix.h"
      37  #define ICONV_FLAVOR_OSF "iconv_open-osf.h"
      38  #define ICONV_FLAVOR_SOLARIS "iconv_open-solaris.h"
      39  #define ICONV_FLAVOR_ZOS "iconv_open-zos.h"
      40  
      41  #ifdef ICONV_FLAVOR
      42  # include ICONV_FLAVOR
      43  #endif
      44  
      45  iconv_t
      46  rpl_iconv_open (const char *tocode, const char *fromcode)
      47  #undef iconv_open
      48  {
      49    char fromcode_upper[32];
      50    char tocode_upper[32];
      51    char *fromcode_upper_end;
      52    char *tocode_upper_end;
      53  
      54  #if REPLACE_ICONV_UTF
      55    /* Special handling of conversion between UTF-8 and UTF-{16,32}{BE,LE}.
      56       Do this here, before calling the real iconv_open(), because  OSF/1 5.1
      57       iconv() to these encoding inserts a BOM, which is wrong.
      58       We do not need to handle conversion between arbitrary encodings and
      59       UTF-{16,32}{BE,LE}, because the 'striconveh' module implements two-step
      60       conversion through UTF-8.
      61       The _ICONV_* constants are chosen to be disjoint from any iconv_t
      62       returned by the system's iconv_open() functions.  Recall that iconv_t
      63       is a scalar type.  */
      64    if (c_toupper (fromcode[0]) == 'U'
      65        && c_toupper (fromcode[1]) == 'T'
      66        && c_toupper (fromcode[2]) == 'F'
      67        && fromcode[3] == '-')
      68      {
      69        if (c_toupper (tocode[0]) == 'U'
      70            && c_toupper (tocode[1]) == 'T'
      71            && c_toupper (tocode[2]) == 'F'
      72            && tocode[3] == '-')
      73          {
      74            if (strcmp (fromcode + 4, "8") == 0)
      75              {
      76                if (c_strcasecmp (tocode + 4, "16BE") == 0)
      77                  return _ICONV_UTF8_UTF16BE;
      78                if (c_strcasecmp (tocode + 4, "16LE") == 0)
      79                  return _ICONV_UTF8_UTF16LE;
      80                if (c_strcasecmp (tocode + 4, "32BE") == 0)
      81                  return _ICONV_UTF8_UTF32BE;
      82                if (c_strcasecmp (tocode + 4, "32LE") == 0)
      83                  return _ICONV_UTF8_UTF32LE;
      84              }
      85            else if (strcmp (tocode + 4, "8") == 0)
      86              {
      87                if (c_strcasecmp (fromcode + 4, "16BE") == 0)
      88                  return _ICONV_UTF16BE_UTF8;
      89                if (c_strcasecmp (fromcode + 4, "16LE") == 0)
      90                  return _ICONV_UTF16LE_UTF8;
      91                if (c_strcasecmp (fromcode + 4, "32BE") == 0)
      92                  return _ICONV_UTF32BE_UTF8;
      93                if (c_strcasecmp (fromcode + 4, "32LE") == 0)
      94                  return _ICONV_UTF32LE_UTF8;
      95              }
      96          }
      97      }
      98  #endif
      99  
     100    /* Do *not* add special support for 8-bit encodings like ASCII or ISO-8859-1
     101       here.  This would lead to programs that work in some locales (such as the
     102       "C" or "en_US" locales) but do not work in East Asian locales.  It is
     103       better if programmers make their programs depend on GNU libiconv (except
     104       on glibc systems), e.g. by using the AM_ICONV macro and documenting the
     105       dependency in an INSTALL or DEPENDENCIES file.  */
     106  
     107    /* Try with the original names first.
     108       This covers the case when fromcode or tocode is a lowercase encoding name
     109       that is understood by the system's iconv_open but not listed in our
     110       mappings table.  */
     111    {
     112      iconv_t cd = iconv_open (tocode, fromcode);
     113      if (cd != (iconv_t)(-1))
     114        return cd;
     115    }
     116  
     117    /* Convert the encodings to upper case, because
     118         1. in the arguments of iconv_open() on AIX, HP-UX, and OSF/1 the case
     119            matters,
     120         2. it makes searching in the table faster.  */
     121    {
     122      const char *p = fromcode;
     123      char *q = fromcode_upper;
     124      while ((*q = c_toupper (*p)) != '\0')
     125        {
     126          p++;
     127          q++;
     128          if (q == &fromcode_upper[SIZEOF (fromcode_upper)])
     129            {
     130              errno = EINVAL;
     131              return (iconv_t)(-1);
     132            }
     133        }
     134      fromcode_upper_end = q;
     135    }
     136  
     137    {
     138      const char *p = tocode;
     139      char *q = tocode_upper;
     140      while ((*q = c_toupper (*p)) != '\0')
     141        {
     142          p++;
     143          q++;
     144          if (q == &tocode_upper[SIZEOF (tocode_upper)])
     145            {
     146              errno = EINVAL;
     147              return (iconv_t)(-1);
     148            }
     149        }
     150      tocode_upper_end = q;
     151    }
     152  
     153  #ifdef ICONV_FLAVOR
     154    /* Apply the mappings.  */
     155    {
     156      const struct mapping *m =
     157        mapping_lookup (fromcode_upper, fromcode_upper_end - fromcode_upper);
     158  
     159      fromcode = (m != NULL ? m->vendor_name : fromcode_upper);
     160    }
     161    {
     162      const struct mapping *m =
     163        mapping_lookup (tocode_upper, tocode_upper_end - tocode_upper);
     164  
     165      tocode = (m != NULL ? m->vendor_name : tocode_upper);
     166    }
     167  #else
     168    fromcode = fromcode_upper;
     169    tocode = tocode_upper;
     170  #endif
     171  
     172    return iconv_open (tocode, fromcode);
     173  }