gconv_open.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* Find matching transformation algorithms and initialize steps.
  2. Copyright (C) 1997-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #include <errno.h>
  16. #include <locale.h>
  17. #include "../locale/localeinfo.h"
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <gconv_int.h>
  21. /* How many character should be converted in one call? */
  22. #define GCONV_NCHAR_GOAL 8160
  23. int
  24. __gconv_open (struct gconv_spec *conv_spec, __gconv_t *handle,
  25. int flags)
  26. {
  27. struct __gconv_step *steps;
  28. size_t nsteps;
  29. __gconv_t result = NULL;
  30. size_t cnt = 0;
  31. int res;
  32. int conv_flags = 0;
  33. bool translit = false;
  34. char *tocode, *fromcode;
  35. /* Find out whether any error handling method is specified. */
  36. translit = conv_spec->translit;
  37. if (conv_spec->ignore)
  38. conv_flags |= __GCONV_IGNORE_ERRORS;
  39. tocode = conv_spec->tocode;
  40. fromcode = conv_spec->fromcode;
  41. /* If the string is empty define this to mean the charset of the
  42. currently selected locale. */
  43. if (strcmp (tocode, "//") == 0)
  44. {
  45. const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
  46. size_t len = strlen (codeset);
  47. char *dest;
  48. tocode = dest = (char *) alloca (len + 3);
  49. memcpy (__mempcpy (dest, codeset, len), "//", 3);
  50. }
  51. if (strcmp (fromcode, "//") == 0)
  52. {
  53. const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
  54. size_t len = strlen (codeset);
  55. char *dest;
  56. fromcode = dest = (char *) alloca (len + 3);
  57. memcpy (__mempcpy (dest, codeset, len), "//", 3);
  58. }
  59. res = __gconv_find_transform (tocode, fromcode, &steps, &nsteps, flags);
  60. if (res == __GCONV_OK)
  61. {
  62. /* Allocate room for handle. */
  63. result = (__gconv_t) malloc (sizeof (struct __gconv_info)
  64. + (nsteps
  65. * sizeof (struct __gconv_step_data)));
  66. if (result == NULL)
  67. res = __GCONV_NOMEM;
  68. else
  69. {
  70. /* Remember the list of steps. */
  71. result->__steps = steps;
  72. result->__nsteps = nsteps;
  73. /* Clear the array for the step data. */
  74. memset (result->__data, '\0',
  75. nsteps * sizeof (struct __gconv_step_data));
  76. /* Call all initialization functions for the transformation
  77. step implementations. */
  78. for (cnt = 0; cnt < nsteps; ++cnt)
  79. {
  80. size_t size;
  81. /* Would have to be done if we would not clear the whole
  82. array above. */
  83. #if 0
  84. /* Reset the counter. */
  85. result->__data[cnt].__invocation_counter = 0;
  86. /* It's a regular use. */
  87. result->__data[cnt].__internal_use = 0;
  88. #endif
  89. /* We use the `mbstate_t' member in DATA. */
  90. result->__data[cnt].__statep = &result->__data[cnt].__state;
  91. /* The builtin transliteration handling only
  92. supports the internal encoding. */
  93. if (translit
  94. && __strcasecmp_l (steps[cnt].__from_name,
  95. "INTERNAL", _nl_C_locobj_ptr) == 0)
  96. conv_flags |= __GCONV_TRANSLIT;
  97. /* If this is the last step we must not allocate an
  98. output buffer. */
  99. if (cnt < nsteps - 1)
  100. {
  101. result->__data[cnt].__flags = conv_flags;
  102. /* Allocate the buffer. */
  103. size = (GCONV_NCHAR_GOAL * steps[cnt].__max_needed_to);
  104. result->__data[cnt].__outbuf = malloc (size);
  105. if (result->__data[cnt].__outbuf == NULL)
  106. {
  107. res = __GCONV_NOMEM;
  108. goto bail;
  109. }
  110. result->__data[cnt].__outbufend =
  111. result->__data[cnt].__outbuf + size;
  112. }
  113. else
  114. {
  115. /* Handle the last entry. */
  116. result->__data[cnt].__flags = conv_flags | __GCONV_IS_LAST;
  117. break;
  118. }
  119. }
  120. }
  121. if (res != __GCONV_OK)
  122. {
  123. /* Something went wrong. Free all the resources. */
  124. int serrno;
  125. bail:
  126. serrno = errno;
  127. if (result != NULL)
  128. {
  129. while (cnt-- > 0)
  130. free (result->__data[cnt].__outbuf);
  131. free (result);
  132. result = NULL;
  133. }
  134. __gconv_close_transform (steps, nsteps);
  135. __set_errno (serrno);
  136. }
  137. }
  138. *handle = result;
  139. return res;
  140. }
  141. libc_hidden_def (__gconv_open)