iconv.c 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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 <stddef.h> /* for NULL */
  17. #include <errno.h>
  18. #include <iconv.h>
  19. #include <gconv_int.h>
  20. #include <assert.h>
  21. size_t
  22. iconv (iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf,
  23. size_t *outbytesleft)
  24. {
  25. __gconv_t gcd = (__gconv_t) cd;
  26. char *outstart = outbuf ? *outbuf : NULL;
  27. size_t irreversible;
  28. int result;
  29. if (__glibc_unlikely (inbuf == NULL || *inbuf == NULL))
  30. {
  31. if (outbuf == NULL || *outbuf == NULL)
  32. result = __gconv (gcd, NULL, NULL, NULL, NULL, &irreversible);
  33. else
  34. result = __gconv (gcd, NULL, NULL, (unsigned char **) outbuf,
  35. (unsigned char *) (outstart + *outbytesleft),
  36. &irreversible);
  37. }
  38. else
  39. {
  40. const char *instart = *inbuf;
  41. result = __gconv (gcd, (const unsigned char **) inbuf,
  42. (const unsigned char *) (*inbuf + *inbytesleft),
  43. (unsigned char **) outbuf,
  44. (unsigned char *) (*outbuf + *outbytesleft),
  45. &irreversible);
  46. *inbytesleft -= *inbuf - instart;
  47. }
  48. if (outstart != NULL)
  49. *outbytesleft -= *outbuf - outstart;
  50. switch (__builtin_expect (result, __GCONV_OK))
  51. {
  52. case __GCONV_ILLEGAL_DESCRIPTOR:
  53. __set_errno (EBADF);
  54. irreversible = (size_t) -1L;
  55. break;
  56. case __GCONV_ILLEGAL_INPUT:
  57. __set_errno (EILSEQ);
  58. irreversible = (size_t) -1L;
  59. break;
  60. case __GCONV_FULL_OUTPUT:
  61. __set_errno (E2BIG);
  62. irreversible = (size_t) -1L;
  63. break;
  64. case __GCONV_INCOMPLETE_INPUT:
  65. __set_errno (EINVAL);
  66. irreversible = (size_t) -1L;
  67. break;
  68. case __GCONV_EMPTY_INPUT:
  69. case __GCONV_OK:
  70. /* Nothing. */
  71. break;
  72. default:
  73. assert (!"Nothing like this should happen");
  74. }
  75. return irreversible;
  76. }