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