(root)/
glibc-2.38/
libio/
wstrops.c
       1  /* Copyright (C) 1993-2023 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
      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
      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    if (flush_only)
     134      return 0;
     135    else
     136      return c;
     137  }
     138  
     139  
     140  wint_t
     141  _IO_wstr_underflow (FILE *fp)
     142  {
     143    if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
     144      fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
     145    if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
     146      {
     147        fp->_flags &= ~_IO_CURRENTLY_PUTTING;
     148        fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
     149        fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_end;
     150      }
     151    if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
     152      return *fp->_wide_data->_IO_read_ptr;
     153    else
     154      return WEOF;
     155  }
     156  
     157  
     158  /* The size of the valid part of the buffer.  */
     159  ssize_t
     160  _IO_wstr_count (FILE *fp)
     161  {
     162    struct _IO_wide_data *wd = fp->_wide_data;
     163  
     164    return ((wd->_IO_write_ptr > wd->_IO_read_end
     165  	   ? wd->_IO_write_ptr : wd->_IO_read_end)
     166  	  - wd->_IO_read_base);
     167  }
     168  
     169  
     170  static int
     171  enlarge_userbuf (FILE *fp, off64_t offset, int reading)
     172  {
     173    if ((ssize_t) offset <= _IO_wblen (fp))
     174      return 0;
     175  
     176    struct _IO_wide_data *wd = fp->_wide_data;
     177  
     178    ssize_t oldend = wd->_IO_write_end - wd->_IO_write_base;
     179  
     180    /* Try to enlarge the buffer.  */
     181    if (fp->_flags2 & _IO_FLAGS2_USER_WBUF)
     182      /* User-provided buffer.  */
     183      return 1;
     184  
     185    size_t newsize = offset + 100;
     186    if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t)))
     187      return 1;
     188  
     189    wchar_t *oldbuf = wd->_IO_buf_base;
     190    wchar_t *newbuf = malloc (newsize * sizeof (wchar_t));
     191    if (newbuf == NULL)
     192      return 1;
     193  
     194    if (oldbuf != NULL)
     195      {
     196        __wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
     197        free (oldbuf);
     198        /* Make sure _IO_setb won't try to delete
     199  	 _IO_buf_base. */
     200        wd->_IO_buf_base = NULL;
     201      }
     202  
     203    _IO_wsetb (fp, newbuf, newbuf + newsize, 1);
     204  
     205    if (reading)
     206      {
     207        wd->_IO_write_base = newbuf + (wd->_IO_write_base - oldbuf);
     208        wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
     209        wd->_IO_write_end = newbuf + (wd->_IO_write_end - oldbuf);
     210        wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
     211  
     212        wd->_IO_read_base = newbuf;
     213        wd->_IO_read_end = wd->_IO_buf_end;
     214      }
     215    else
     216      {
     217        wd->_IO_read_base = newbuf + (wd->_IO_read_base - oldbuf);
     218        wd->_IO_read_ptr = newbuf + (wd->_IO_read_ptr - oldbuf);
     219        wd->_IO_read_end = newbuf + (wd->_IO_read_end - oldbuf);
     220        wd->_IO_write_ptr = newbuf + (wd->_IO_write_ptr - oldbuf);
     221  
     222        wd->_IO_write_base = newbuf;
     223        wd->_IO_write_end = wd->_IO_buf_end;
     224      }
     225  
     226    /* Clear the area between the last write position and th
     227       new position.  */
     228    assert (offset >= oldend);
     229    if (reading)
     230      __wmemset (wd->_IO_read_base + oldend, L'\0', offset - oldend);
     231    else
     232      __wmemset (wd->_IO_write_base + oldend, L'\0', offset - oldend);
     233  
     234    return 0;
     235  }
     236  
     237  static void
     238  _IO_wstr_switch_to_get_mode (FILE *fp)
     239  {
     240    if (_IO_in_backup (fp))
     241      fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_backup_base;
     242    else
     243      {
     244        fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_buf_base;
     245        if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_read_end)
     246          fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
     247      }
     248    fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_write_ptr;
     249    fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_write_ptr;
     250  
     251    fp->_flags &= ~_IO_CURRENTLY_PUTTING;
     252  }
     253  
     254  off64_t
     255  _IO_wstr_seekoff (FILE *fp, off64_t offset, int dir, int mode)
     256  {
     257    off64_t new_pos;
     258  
     259    if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
     260      mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
     261  
     262    bool was_writing = ((fp->_wide_data->_IO_write_ptr
     263  		       > fp->_wide_data->_IO_write_base)
     264  		     || _IO_in_put_mode (fp));
     265    if (was_writing)
     266      _IO_wstr_switch_to_get_mode (fp);
     267  
     268    if (mode == 0)
     269      {
     270        new_pos = (fp->_wide_data->_IO_write_ptr
     271  		 - fp->_wide_data->_IO_write_base);
     272      }
     273    else
     274      {
     275        ssize_t cur_size = _IO_wstr_count (fp);
     276        new_pos = EOF;
     277  
     278        /* Move the get pointer, if requested. */
     279        if (mode & _IOS_INPUT)
     280  	{
     281  	  ssize_t base;
     282  	  switch (dir)
     283  	    {
     284  	    case _IO_seek_set:
     285  	      base = 0;
     286  	      break;
     287  	    case _IO_seek_cur:
     288  	      base = (fp->_wide_data->_IO_read_ptr
     289  		     - fp->_wide_data->_IO_read_base);
     290  	      break;
     291  	    default: /* case _IO_seek_end: */
     292  	      base = cur_size;
     293  	      break;
     294  	    }
     295  	  ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
     296  	  if (offset < -base || offset > maxval)
     297  	    {
     298  	      __set_errno (EINVAL);
     299  	      return EOF;
     300  	    }
     301  	  base += offset;
     302  	  if (base > cur_size
     303  	      && enlarge_userbuf (fp, base, 1) != 0)
     304  	    return EOF;
     305  	  fp->_wide_data->_IO_read_ptr = (fp->_wide_data->_IO_read_base
     306  					  + base);
     307  	  fp->_wide_data->_IO_read_end = (fp->_wide_data->_IO_read_base
     308  					  + cur_size);
     309  	  new_pos = offset;
     310  	}
     311  
     312        /* Move the put pointer, if requested. */
     313        if (mode & _IOS_OUTPUT)
     314  	{
     315  	  ssize_t base;
     316  	  switch (dir)
     317  	    {
     318  	    case _IO_seek_set:
     319  	      base = 0;
     320  	      break;
     321  	    case _IO_seek_cur:
     322  	      base = (fp->_wide_data->_IO_write_ptr
     323  		     - fp->_wide_data->_IO_write_base);
     324  	      break;
     325  	    default: /* case _IO_seek_end: */
     326  	      base = cur_size;
     327  	      break;
     328  	    }
     329  	  ssize_t maxval = SSIZE_MAX/sizeof (wchar_t) - base;
     330  	  if (offset < -base || offset > maxval)
     331  	    {
     332  	      __set_errno (EINVAL);
     333  	      return EOF;
     334  	    }
     335  	  base += offset;
     336  	  if (base > cur_size
     337  	      && enlarge_userbuf (fp, base, 0) != 0)
     338  	    return EOF;
     339  	  fp->_wide_data->_IO_write_ptr = (fp->_wide_data->_IO_write_base
     340  					   + base);
     341  	  new_pos = base;
     342  	}
     343      }
     344    return new_pos;
     345  }
     346  
     347  wint_t
     348  _IO_wstr_pbackfail (FILE *fp, wint_t c)
     349  {
     350    if ((fp->_flags & _IO_NO_WRITES) && c != WEOF)
     351      return WEOF;
     352    return _IO_wdefault_pbackfail (fp, c);
     353  }
     354  
     355  void
     356  _IO_wstr_finish (FILE *fp, int dummy)
     357  {
     358    if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
     359      free (fp->_wide_data->_IO_buf_base);
     360    fp->_wide_data->_IO_buf_base = NULL;
     361  
     362    _IO_wdefault_finish (fp, 0);
     363  }