1/* Copyright (C) 1993-2016 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 <http://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
34void
35_IO_wstr_init_static (_IO_FILE *fp, wchar_t *ptr, _IO_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 ((_IO_size_t) ptr + size * sizeof (wchar_t) > (_IO_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 - (_IO_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) = (_IO_alloc_type)0;
67}
68
69_IO_wint_t
70_IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c)
71{
72 int flush_only = c == WEOF;
73 _IO_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 >= (_IO_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 _IO_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
99 = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size
100 * sizeof (wchar_t));
101 if (new_buf == NULL)
102 {
103 /* __ferror(fp) = 1; */
104 return WEOF;
105 }
106 if (old_buf)
107 {
108 __wmemcpy (new_buf, old_buf, old_wblen);
109 (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
110 /* Make sure _IO_setb won't try to delete _IO_buf_base. */
111 fp->_wide_data->_IO_buf_base = NULL;
112 }
113
114 wmemset (new_buf + old_wblen, L'\0', new_size - old_wblen);
115
116 _IO_wsetb (fp, new_buf, new_buf + new_size, 1);
117 fp->_wide_data->_IO_read_base =
118 new_buf + (fp->_wide_data->_IO_read_base - old_buf);
119 fp->_wide_data->_IO_read_ptr =
120 new_buf + (fp->_wide_data->_IO_read_ptr - old_buf);
121 fp->_wide_data->_IO_read_end =
122 new_buf + (fp->_wide_data->_IO_read_end - old_buf);
123 fp->_wide_data->_IO_write_ptr =
124 new_buf + (fp->_wide_data->_IO_write_ptr - old_buf);
125
126 fp->_wide_data->_IO_write_base = new_buf;
127 fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_end;
128 }
129 }
130
131 if (!flush_only)
132 *fp->_wide_data->_IO_write_ptr++ = c;
133 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
134 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
135 return c;
136}
137
138
139_IO_wint_t
140_IO_wstr_underflow (_IO_FILE *fp)
141{
142 if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
143 fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
144 if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
145 {
146 fp->_flags &= ~_IO_CURRENTLY_PUTTING;
147 fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
148 fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end;
149 }
150 if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
151 return *fp->_wide_data->_IO_read_ptr;
152 else
153 return WEOF;
154}
155
156
157/* The size of the valid part of the buffer. */
158_IO_ssize_t
159_IO_wstr_count (_IO_FILE *fp)
160{
161 struct _IO_wide_data *wd = fp->_wide_data;
162
163 return ((wd->_IO_write_ptr > wd->_IO_read_end
164 ? wd->_IO_write_ptr : wd->_IO_read_end)
165 - wd->_IO_read_base);
166}
167
168
169static int
170enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
171{
172 if ((_IO_ssize_t) offset <= _IO_blen (fp))
173 return 0;
174
175 struct _IO_wide_data *wd = fp->_wide_data;
176
177 _IO_ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
178
179 /* Try to enlarge the buffer. */
180 if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
181 /* User-provided buffer. */
182 return 1;
183
184 _IO_size_t newsize = offset + 100;
185 if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t)))
186 return 1;
187
188 wchar_t *oldbuf = wd->_IO_buf_base;
189 wchar_t *newbuf
190 = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize
191 * sizeof (wchar_t));
192 if (newbuf == NULL)
193 return 1;
194
195 if (oldbuf != NULL)
196 {
197 __wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
198 (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
199 /* Make sure _IO_setb won't try to delete
200 _IO_buf_base. */
201 wd->_IO_buf_base = NULL;
202 }
203
204 _IO_wsetb (fp, newbuf, newbuf + newsize, 1);
205
206 if (reading)
207 {
208 wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf);
209 wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
210 wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf);
211 wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
212
213 wd->_IO_read_base = newbuf;
214 wd->_IO_read_end = wd->_IO_buf_end;
215 }
216 else
217 {
218 wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf);
219 wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
220 wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf);
221 wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
222
223 wd->_IO_write_base = newbuf;
224 wd->_IO_write_end = wd->_IO_buf_end;
225 }
226
227 /* Clear the area between the last write position and th
228 new position. */
229 assert (offset >= oldend);
230 if (reading)
231 wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
232 else
233 wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
234
235 return 0;
236}
237
238
239_IO_off64_t
240_IO_wstr_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
241{
242 _IO_off64_t new_pos;
243
244 if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
245 mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
246
247 if (mode == 0)
248 {
249 /* Don't move any pointers. But there is no clear indication what
250 mode FP is in. Let's guess. */
251 if (fp->_IO_file_flags & _IO_NO_WRITES)
252 new_pos = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
253 else
254 new_pos = (fp->_wide_data->_IO_write_ptr
255 - fp->_wide_data->_IO_write_base);
256 }
257 else
258 {
259 _IO_ssize_t cur_size = _IO_wstr_count (fp);
260 new_pos = EOF;
261
262 /* Move the get pointer, if requested. */
263 if (mode & _IOS_INPUT)
264 {
265 switch (dir)
266 {
267 case _IO_seek_end:
268 offset += cur_size;
269 break;
270 case _IO_seek_cur:
271 offset += (fp->_wide_data->_IO_read_ptr
272 - fp->_wide_data->_IO_read_base);
273 break;
274 default: /* case _IO_seek_set: */
275 break;
276 }
277 if (offset < 0)
278 return EOF;
279 if ((_IO_ssize_t) offset > cur_size
280 && enlarge_userbuf (fp, offset, 1) != 0)
281 return EOF;
282 fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
283 + offset);
284 fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
285 + cur_size);
286 new_pos = offset;
287 }
288
289 /* Move the put pointer, if requested. */
290 if (mode & _IOS_OUTPUT)
291 {
292 switch (dir)
293 {
294 case _IO_seek_end:
295 offset += cur_size;
296 break;
297 case _IO_seek_cur:
298 offset += (fp->_wide_data->_IO_write_ptr
299 - fp->_wide_data->_IO_write_base);
300 break;
301 default: /* case _IO_seek_set: */
302 break;
303 }
304 if (offset < 0)
305 return EOF;
306 if ((_IO_ssize_t) offset > cur_size
307 && enlarge_userbuf (fp, offset, 0) != 0)
308 return EOF;
309 fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
310 + offset);
311 new_pos = offset;
312 }
313 }
314 return new_pos;
315}
316
317_IO_wint_t
318_IO_wstr_pbackfail (_IO_FILE *fp, _IO_wint_t c)
319{
320 if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
321 return WEOF;
322 return _IO_wdefault_pbackfail (fp, c);
323}
324
325void
326_IO_wstr_finish (_IO_FILE *fp, int dummy)
327{
328 if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
329 (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base);
330 fp->_wide_data->_IO_buf_base = NULL;
331
332 _IO_wdefault_finish (fp, 0);
333}
334
335const struct _IO_jump_t _IO_wstr_jumps =
336{
337 JUMP_INIT_DUMMY,
338 JUMP_INIT(finish, _IO_wstr_finish),
339 JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
340 JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
341 JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
342 JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
343 JUMP_INIT(xsputn, _IO_wdefault_xsputn),
344 JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
345 JUMP_INIT(seekoff, _IO_wstr_seekoff),
346 JUMP_INIT(seekpos, _IO_default_seekpos),
347 JUMP_INIT(setbuf, _IO_default_setbuf),
348 JUMP_INIT(sync, _IO_default_sync),
349 JUMP_INIT(doallocate, _IO_wdefault_doallocate),
350 JUMP_INIT(read, _IO_default_read),
351 JUMP_INIT(write, _IO_default_write),
352 JUMP_INIT(seek, _IO_default_seek),
353 JUMP_INIT(close, _IO_default_close),
354 JUMP_INIT(stat, _IO_default_stat),
355 JUMP_INIT(showmanyc, _IO_default_showmanyc),
356 JUMP_INIT(imbue, _IO_default_imbue)
357};
358