iconv_open.c 5.5 KB

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