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