212 lines
6.7 KiB
C
212 lines
6.7 KiB
C
|
/***
|
||
|
*_filbuf.c - fill buffer and get character
|
||
|
*
|
||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
*
|
||
|
*Purpose:
|
||
|
* defines _filbuf() - fill buffer and read first character, allocate
|
||
|
* buffer if there is none. Used from getc().
|
||
|
* defines _filwbuf() - fill buffer and read first wide character, allocate
|
||
|
* buffer if there is none. Used from getwc().
|
||
|
*
|
||
|
*Note:
|
||
|
* this file is included in safecrt.lib build directly, plese refer
|
||
|
* to safecrt_filwbuf.c
|
||
|
*
|
||
|
*******************************************************************************/
|
||
|
|
||
|
#include <cruntime.h>
|
||
|
#include <stdio.h>
|
||
|
#include <file2.h>
|
||
|
#include <io.h>
|
||
|
#include <dbgint.h>
|
||
|
#include <malloc.h>
|
||
|
#include <internal.h>
|
||
|
#include <msdos.h>
|
||
|
#include <wchar.h>
|
||
|
#include <mtdll.h>
|
||
|
#include <tchar.h>
|
||
|
|
||
|
#ifndef _UNICODE
|
||
|
|
||
|
/***
|
||
|
*int _filbuf(stream) - fill buffer and get first character
|
||
|
*
|
||
|
*Purpose:
|
||
|
* get a buffer if the file doesn't have one, read into it, return first
|
||
|
* char. try to get a buffer, if a user buffer is not assigned. called
|
||
|
* only from getc; intended for use only within library. assume no input
|
||
|
* stream is to remain unbuffered when memory is available unless it is
|
||
|
* marked _IONBF. at worst, give it a single char buffer. the need for a
|
||
|
* buffer, no matter how small, becomes evident when we consider the
|
||
|
* ungetc's necessary in scanf
|
||
|
*
|
||
|
* [NOTE: Multi-thread - _filbuf() assumes that the caller has aquired
|
||
|
* the stream lock, if needed.]
|
||
|
*
|
||
|
*Entry:
|
||
|
* FILE *stream - stream to read from
|
||
|
*
|
||
|
*Exit:
|
||
|
* returns first character from buffer (next character to be read)
|
||
|
* returns EOF if the FILE is actually a string, or not open for reading,
|
||
|
* or if open for writing or if no more chars to read.
|
||
|
* all fields in FILE structure may be changed except _file.
|
||
|
*
|
||
|
*Exceptions:
|
||
|
*
|
||
|
*******************************************************************************/
|
||
|
|
||
|
int __cdecl _filbuf (
|
||
|
FILE *str
|
||
|
)
|
||
|
|
||
|
#else /* _UNICODE */
|
||
|
|
||
|
/***
|
||
|
*int _filwbuf(stream) - fill buffer and get first wide character
|
||
|
*
|
||
|
*Purpose:
|
||
|
* get a buffer if the file doesn't have one, read into it, return first
|
||
|
* char. try to get a buffer, if a user buffer is not assigned. called
|
||
|
* only from getc; intended for use only within library. assume no input
|
||
|
* stream is to remain unbuffered when memory is available unless it is
|
||
|
* marked _IONBF. at worst, give it a single char buffer. the need for a
|
||
|
* buffer, no matter how small, becomes evident when we consider the
|
||
|
* ungetc's necessary in scanf
|
||
|
*
|
||
|
* [NOTE: Multi-thread - _filwbuf() assumes that the caller has aquired
|
||
|
* the stream lock, if needed.]
|
||
|
*
|
||
|
*Entry:
|
||
|
* FILE *stream - stream to read from
|
||
|
*
|
||
|
*Exit:
|
||
|
* returns first wide character from buffer (next character to be read)
|
||
|
* returns WEOF if the FILE is actually a string, or not open for reading,
|
||
|
* or if open for writing or if no more chars to read.
|
||
|
* all fields in FILE structure may be changed except _file.
|
||
|
*
|
||
|
*Exceptions:
|
||
|
*
|
||
|
*******************************************************************************/
|
||
|
|
||
|
int __cdecl _filwbuf (
|
||
|
FILE *str
|
||
|
)
|
||
|
|
||
|
#endif /* _UNICODE */
|
||
|
|
||
|
{
|
||
|
FILE *stream=NULL;
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
int is_split_character = 0;
|
||
|
unsigned char leftover_low_order_byte = 0;
|
||
|
#endif /* _UNICODE */
|
||
|
|
||
|
/* In safecrt, we assume we always have a buffer */
|
||
|
_VALIDATE_RETURN(str != NULL, EINVAL, _TEOF);
|
||
|
|
||
|
/* Init pointer to _iob2 entry. */
|
||
|
stream = str;
|
||
|
|
||
|
if (!inuse(stream) || stream->_flag & _IOSTRG)
|
||
|
return(_TEOF);
|
||
|
|
||
|
if (stream->_flag & _IOWRT)
|
||
|
{
|
||
|
stream->_flag |= _IOERR;
|
||
|
return(_TEOF);
|
||
|
}
|
||
|
|
||
|
stream->_flag |= _IOREAD;
|
||
|
|
||
|
/* Get a buffer, if necessary. */
|
||
|
|
||
|
if (!anybuf(stream))
|
||
|
{
|
||
|
#ifndef _SAFECRT_IMPL
|
||
|
_getbuf(stream);
|
||
|
#else /* _SAFECRT_IMPL */
|
||
|
/* In safecrt, we assume we always have a buffer */
|
||
|
_VALIDATE_RETURN(FALSE, EINVAL, _TEOF);
|
||
|
#endif /* _SAFECRT_IMPL */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifdef _UNICODE
|
||
|
/* When reading wchar_t elements, we must handle the case where a
|
||
|
two-byte character straddles the buffer boundary, with the low
|
||
|
order byte at the end of the old buffer and the high order byte
|
||
|
at the start of the new buffer.
|
||
|
|
||
|
We do this here: if there is exactly one character left in the
|
||
|
buffer, we store that and set the is_split_character flag. After
|
||
|
we load the new buffer, we'll or this low order byte into the
|
||
|
result. */
|
||
|
if (stream->_cnt == 1)
|
||
|
{
|
||
|
is_split_character = 1;
|
||
|
leftover_low_order_byte = (unsigned char)*stream->_ptr;
|
||
|
}
|
||
|
#endif /* _UNICODE */
|
||
|
|
||
|
stream->_ptr = stream->_base;
|
||
|
}
|
||
|
|
||
|
stream->_cnt = _read(_fileno(stream), stream->_base, stream->_bufsiz);
|
||
|
|
||
|
#ifndef _UNICODE
|
||
|
if ((stream->_cnt == 0) || (stream->_cnt == -1)) {
|
||
|
#else /* _UNICODE */
|
||
|
if ((stream->_cnt == 0) || (stream->_cnt == 1) || stream->_cnt == -1) {
|
||
|
#endif /* _UNICODE */
|
||
|
stream->_flag |= stream->_cnt ? _IOERR : _IOEOF;
|
||
|
stream->_cnt = 0;
|
||
|
return(_TEOF);
|
||
|
}
|
||
|
|
||
|
if ( !(stream->_flag & (_IOWRT|_IORW)) &&
|
||
|
((_osfile_safe(_fileno(stream)) & (FTEXT|FEOFLAG)) ==
|
||
|
(FTEXT|FEOFLAG)) )
|
||
|
{
|
||
|
stream->_flag |= _IOCTRLZ;
|
||
|
}
|
||
|
|
||
|
/* Check for small _bufsiz (_SMALL_BUFSIZ). If it is small and
|
||
|
if it is our buffer, then this must be the first _filbuf after
|
||
|
an fseek on a read-access-only stream. Restore _bufsiz to its
|
||
|
larger value (_INTERNAL_BUFSIZ) so that the next _filbuf call,
|
||
|
if one is made, will fill the whole buffer. */
|
||
|
if ( (stream->_bufsiz == _SMALL_BUFSIZ) && (stream->_flag &
|
||
|
_IOMYBUF) && !(stream->_flag & _IOSETVBUF) )
|
||
|
{
|
||
|
stream->_bufsiz = _INTERNAL_BUFSIZ;
|
||
|
}
|
||
|
|
||
|
#ifndef _UNICODE
|
||
|
stream->_cnt--;
|
||
|
return(0xff & *stream->_ptr++);
|
||
|
#else /* _UNICODE */
|
||
|
if (is_split_character)
|
||
|
{
|
||
|
/* If the character was split across buffers, we read only one byte
|
||
|
from the new buffer and or it with the leftover byte from the old
|
||
|
buffer. */
|
||
|
unsigned char high_order_byte = (unsigned char)(*stream->_ptr);
|
||
|
wchar_t result = (high_order_byte << 8) | leftover_low_order_byte;
|
||
|
|
||
|
--stream->_cnt;
|
||
|
++stream->_ptr;
|
||
|
return (result);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
stream->_cnt -= sizeof(wchar_t);
|
||
|
return (0xffff & *((wchar_t *)(stream->_ptr))++);
|
||
|
}
|
||
|
#endif /* _UNICODE */
|
||
|
|
||
|
}
|