wstrops.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /* Copyright (C) 1993-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library 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 GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, see
  13. <https://www.gnu.org/licenses/>.
  14. As a special exception, if you link the code in this file with
  15. files compiled with a GNU compiler to produce an executable,
  16. that does not cause the resulting executable to be covered by
  17. the GNU Lesser General Public License. This exception does not
  18. however invalidate any other reasons why the executable file
  19. might be covered by the GNU Lesser General Public License.
  20. This exception applies to code released by its copyright holders
  21. in files containing the exception. */
  22. #include <assert.h>
  23. #include "strfile.h"
  24. #include "libioP.h"
  25. #include <string.h>
  26. #include <wchar.h>
  27. #include <stdio_ext.h>
  28. void
  29. _IO_wstr_init_static (FILE *fp, wchar_t *ptr, size_t size,
  30. wchar_t *pstart)
  31. {
  32. wchar_t *end;
  33. if (size == 0)
  34. end = ptr + __wcslen (ptr);
  35. else if ((size_t) ptr + size * sizeof (wchar_t) > (size_t) ptr)
  36. end = ptr + size;
  37. else
  38. /* Even for misaligned ptr make sure there is integral number of wide
  39. characters. */
  40. end = ptr + (-1 - (size_t) ptr) / sizeof (wchar_t);
  41. _IO_wsetb (fp, ptr, end, 0);
  42. fp->_wide_data->_IO_write_base = ptr;
  43. fp->_wide_data->_IO_read_base = ptr;
  44. fp->_wide_data->_IO_read_ptr = ptr;
  45. if (pstart)
  46. {
  47. fp->_wide_data->_IO_write_ptr = pstart;
  48. fp->_wide_data->_IO_write_end = end;
  49. fp->_wide_data->_IO_read_end = pstart;
  50. }
  51. else
  52. {
  53. fp->_wide_data->_IO_write_ptr = ptr;
  54. fp->_wide_data->_IO_write_end = ptr;
  55. fp->_wide_data->_IO_read_end = end;
  56. }
  57. /* A null _allocate_buffer function flags the strfile as being static. */
  58. (((_IO_strfile *) fp)->_s._allocate_buffer_unused) = (_IO_alloc_type)0;
  59. }
  60. wint_t
  61. _IO_wstr_overflow (FILE *fp, wint_t c)
  62. {
  63. int flush_only = c == WEOF;
  64. size_t pos;
  65. if (fp->_flags & _IO_NO_WRITES)
  66. return flush_only ? 0 : WEOF;
  67. if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
  68. {
  69. fp->_flags |= _IO_CURRENTLY_PUTTING;
  70. fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_read_ptr;
  71. fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
  72. }
  73. pos = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
  74. if (pos >= (size_t) (_IO_wblen (fp) + flush_only))
  75. {
  76. if (fp->_flags2 & _IO_FLAGS2_USER_WBUF) /* not allowed to enlarge */
  77. return WEOF;
  78. else
  79. {
  80. wchar_t *new_buf;
  81. wchar_t *old_buf = fp->_wide_data->_IO_buf_base;
  82. size_t old_wblen = _IO_wblen (fp);
  83. size_t new_size = 2 * old_wblen + 100;
  84. if (__glibc_unlikely (new_size < old_wblen)
  85. || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t)))
  86. return EOF;
  87. new_buf = malloc (new_size * sizeof (wchar_t));
  88. if (new_buf == NULL)
  89. {
  90. /* __ferror(fp) = 1; */
  91. return WEOF;
  92. }
  93. if (old_buf)
  94. {
  95. __wmemcpy (new_buf, old_buf, old_wblen);
  96. free (old_buf);
  97. /* Make sure _IO_setb won't try to delete _IO_buf_base. */
  98. fp->_wide_data->_IO_buf_base = NULL;
  99. }
  100. __wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen);
  101. _IO_wsetb (fp, new_buf, new_buf + new_size, 1);
  102. fp->_wide_data->_IO_read_base =
  103. new_buf + (fp->_wide_data->_IO_read_base - old_buf);
  104. fp->_wide_data->_IO_read_ptr =
  105. new_buf + (fp->_wide_data->_IO_read_ptr - old_buf);
  106. fp->_wide_data->_IO_read_end =
  107. new_buf + (fp->_wide_data->_IO_read_end - old_buf);
  108. fp->_wide_data->_IO_write_ptr =
  109. new_buf + (fp->_wide_data->_IO_write_ptr - old_buf);
  110. fp->_wide_data->_IO_write_base = new_buf;
  111. fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end;
  112. }
  113. }
  114. if (!flush_only)
  115. *fp->_wide_data->_IO_write_ptr++ = c;
  116. if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
  117. fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
  118. if (flush_only)
  119. return 0;
  120. else
  121. return c;
  122. }
  123. wint_t
  124. _IO_wstr_underflow (FILE *fp)
  125. {
  126. if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
  127. fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
  128. if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
  129. {
  130. fp->_flags &= ~_IO_CURRENTLY_PUTTING;
  131. fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
  132. fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end;
  133. }
  134. if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
  135. return *fp->_wide_data->_IO_read_ptr;
  136. else
  137. return WEOF;
  138. }
  139. /* The size of the valid part of the buffer. */
  140. ssize_t
  141. _IO_wstr_count (FILE *fp)
  142. {
  143. struct _IO_wide_data *wd = fp->_wide_data;
  144. return ((wd->_IO_write_ptr > wd->_IO_read_end
  145. ? wd->_IO_write_ptr : wd->_IO_read_end)
  146. - wd->_IO_read_base);
  147. }
  148. static int
  149. enlarge_userbuf (FILE *fp, off64_t offset, int reading)
  150. {
  151. if ((ssize_t) offset <= _IO_wblen (fp))
  152. return 0;
  153. struct _IO_wide_data *wd = fp->_wide_data;
  154. ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
  155. /* Try to enlarge the buffer. */
  156. if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
  157. /* User-provided buffer. */
  158. return 1;
  159. size_t newsize = offset + 100;
  160. if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t)))
  161. return 1;
  162. wchar_t *oldbuf = wd->_IO_buf_base;
  163. wchar_t *newbuf = malloc (newsize * sizeof (wchar_t));
  164. if (newbuf == NULL)
  165. return 1;
  166. if (oldbuf != NULL)
  167. {
  168. __wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
  169. free (oldbuf);
  170. /* Make sure _IO_setb won't try to delete
  171. _IO_buf_base. */
  172. wd->_IO_buf_base = NULL;
  173. }
  174. _IO_wsetb (fp, newbuf, newbuf + newsize, 1);
  175. if (reading)
  176. {
  177. wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf);
  178. wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
  179. wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf);
  180. wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
  181. wd->_IO_read_base = newbuf;
  182. wd->_IO_read_end = wd->_IO_buf_end;
  183. }
  184. else
  185. {
  186. wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf);
  187. wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
  188. wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf);
  189. wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
  190. wd->_IO_write_base = newbuf;
  191. wd->_IO_write_end = wd->_IO_buf_end;
  192. }
  193. /* Clear the area between the last write position and th
  194. new position. */
  195. assert (offset >= oldend);
  196. if (reading)
  197. __wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
  198. else
  199. __wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
  200. return 0;
  201. }
  202. static void
  203. _IO_wstr_switch_to_get_mode (FILE *fp)
  204. {
  205. if (_IO_in_backup (fp))
  206. fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
  207. else
  208. {
  209. fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
  210. if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
  211. fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
  212. }
  213. fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
  214. fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
  215. fp->_flags &= ~_IO_CURRENTLY_PUTTING;
  216. }
  217. off64_t
  218. _IO_wstr_seekoff (FILE *fp, off64_t offset, int dir, int mode)
  219. {
  220. off64_t new_pos;
  221. if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
  222. mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
  223. bool was_writing = ((fp->_wide_data->_IO_write_ptr
  224. > fp->_wide_data->_IO_write_base)
  225. || _IO_in_put_mode (fp));
  226. if (was_writing)
  227. _IO_wstr_switch_to_get_mode (fp);
  228. if (mode == 0)
  229. {
  230. new_pos = (fp->_wide_data->_IO_write_ptr
  231. - fp->_wide_data->_IO_write_base);
  232. }
  233. else
  234. {
  235. ssize_t cur_size = _IO_wstr_count (fp);
  236. new_pos = EOF;
  237. /* Move the get pointer, if requested. */
  238. if (mode & _IOS_INPUT)
  239. {
  240. ssize_t base;
  241. switch (dir)
  242. {
  243. case _IO_seek_set:
  244. base = 0;
  245. break;
  246. case _IO_seek_cur:
  247. base = (fp->_wide_data->_IO_read_ptr
  248. - fp->_wide_data->_IO_read_base);
  249. break;
  250. default: /* case _IO_seek_end: */
  251. base = cur_size;
  252. break;
  253. }
  254. ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
  255. if (offset < -base || offset > maxval)
  256. {
  257. __set_errno (EINVAL);
  258. return EOF;
  259. }
  260. base += offset;
  261. if (base > cur_size
  262. && enlarge_userbuf (fp, base, 1) != 0)
  263. return EOF;
  264. fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
  265. + base);
  266. fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
  267. + cur_size);
  268. new_pos = offset;
  269. }
  270. /* Move the put pointer, if requested. */
  271. if (mode & _IOS_OUTPUT)
  272. {
  273. ssize_t base;
  274. switch (dir)
  275. {
  276. case _IO_seek_set:
  277. base = 0;
  278. break;
  279. case _IO_seek_cur:
  280. base = (fp->_wide_data->_IO_write_ptr
  281. - fp->_wide_data->_IO_write_base);
  282. break;
  283. default: /* case _IO_seek_end: */
  284. base = cur_size;
  285. break;
  286. }
  287. ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
  288. if (offset < -base || offset > maxval)
  289. {
  290. __set_errno (EINVAL);
  291. return EOF;
  292. }
  293. base += offset;
  294. if (base > cur_size
  295. && enlarge_userbuf (fp, base, 0) != 0)
  296. return EOF;
  297. fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
  298. + base);
  299. new_pos = base;
  300. }
  301. }
  302. return new_pos;
  303. }
  304. wint_t
  305. _IO_wstr_pbackfail (FILE *fp, wint_t c)
  306. {
  307. if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
  308. return WEOF;
  309. return _IO_wdefault_pbackfail (fp, c);
  310. }
  311. void
  312. _IO_wstr_finish (FILE *fp, int dummy)
  313. {
  314. if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
  315. free (fp->_wide_data->_IO_buf_base);
  316. fp->_wide_data->_IO_buf_base = NULL;
  317. _IO_wdefault_finish (fp, 0);
  318. }