gconv.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /* Convert characters in input buffer using conversion descriptor to
  2. output buffer.
  3. Copyright (C) 1997-2026 Free Software Foundation, Inc.
  4. This file is part of the GNU C Library.
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. The GNU C Library 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 GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with the GNU C Library; if not, see
  15. <https://www.gnu.org/licenses/>. */
  16. #include <assert.h>
  17. #include <dlfcn.h>
  18. #include <stddef.h>
  19. #include <sys/param.h>
  20. #include <gconv_int.h>
  21. #include <pointer_guard.h>
  22. int
  23. __gconv (__gconv_t cd, const unsigned char **inbuf,
  24. const unsigned char *inbufend, unsigned char **outbuf,
  25. unsigned char *outbufend, size_t *irreversible)
  26. {
  27. size_t last_step;
  28. int result;
  29. if (cd == (__gconv_t) -1L)
  30. return __GCONV_ILLEGAL_DESCRIPTOR;
  31. last_step = cd->__nsteps - 1;
  32. assert (irreversible != NULL);
  33. *irreversible = 0;
  34. cd->__data[last_step].__outbuf = outbuf != NULL ? *outbuf : NULL;
  35. cd->__data[last_step].__outbufend = outbufend;
  36. __gconv_fct fct = cd->__steps->__fct;
  37. if (cd->__steps->__shlib_handle != NULL)
  38. PTR_DEMANGLE (fct);
  39. if (inbuf == NULL || *inbuf == NULL)
  40. {
  41. /* We just flush. */
  42. result = DL_CALL_FCT (fct,
  43. (cd->__steps, cd->__data, NULL, NULL, NULL,
  44. irreversible,
  45. cd->__data[last_step].__outbuf == NULL ? 2 : 1,
  46. 0));
  47. /* If the flush was successful clear the rest of the state. */
  48. if (result == __GCONV_OK)
  49. for (size_t cnt = 0; cnt <= last_step; ++cnt)
  50. cd->__data[cnt].__invocation_counter = 0;
  51. }
  52. else
  53. {
  54. const unsigned char *last_start;
  55. assert (outbuf != NULL && *outbuf != NULL);
  56. do
  57. {
  58. last_start = *inbuf;
  59. result = DL_CALL_FCT (fct,
  60. (cd->__steps, cd->__data, inbuf, inbufend,
  61. NULL, irreversible, 0, 0));
  62. }
  63. while (result == __GCONV_EMPTY_INPUT && last_start != *inbuf
  64. && *inbuf + cd->__steps->__min_needed_from <= inbufend);
  65. }
  66. if (outbuf != NULL && *outbuf != NULL)
  67. *outbuf = cd->__data[last_step].__outbuf;
  68. return result;
  69. }