1*04e0dc4aSTimo Kreuzer //
2*04e0dc4aSTimo Kreuzer // _filbuf.cpp
3*04e0dc4aSTimo Kreuzer //
4*04e0dc4aSTimo Kreuzer // Copyright (c) Microsoft Corporation. All rights reserved.
5*04e0dc4aSTimo Kreuzer //
6*04e0dc4aSTimo Kreuzer // Functions that re-fill a stdio stream buffer and return the next character.
7*04e0dc4aSTimo Kreuzer //
8*04e0dc4aSTimo Kreuzer #include <corecrt_internal_stdio.h>
9*04e0dc4aSTimo Kreuzer
10*04e0dc4aSTimo Kreuzer
11*04e0dc4aSTimo Kreuzer
12*04e0dc4aSTimo Kreuzer namespace {
13*04e0dc4aSTimo Kreuzer
14*04e0dc4aSTimo Kreuzer struct filwbuf_context
15*04e0dc4aSTimo Kreuzer {
16*04e0dc4aSTimo Kreuzer bool _is_split_character;
17*04e0dc4aSTimo Kreuzer unsigned char _leftover_low_order_byte;
18*04e0dc4aSTimo Kreuzer };
19*04e0dc4aSTimo Kreuzer
20*04e0dc4aSTimo Kreuzer }
21*04e0dc4aSTimo Kreuzer
22*04e0dc4aSTimo Kreuzer
23*04e0dc4aSTimo Kreuzer
24*04e0dc4aSTimo Kreuzer // These functions store the pre-_read() state of the stream so that it can be
25*04e0dc4aSTimo Kreuzer // used later when we read a character from the newly-filled buffer.
get_context_nolock(__crt_stdio_stream const,char)26*04e0dc4aSTimo Kreuzer static int get_context_nolock(__crt_stdio_stream const, char) throw()
27*04e0dc4aSTimo Kreuzer {
28*04e0dc4aSTimo Kreuzer return 0;
29*04e0dc4aSTimo Kreuzer }
30*04e0dc4aSTimo Kreuzer
get_context_nolock(__crt_stdio_stream const stream,wchar_t)31*04e0dc4aSTimo Kreuzer static filwbuf_context get_context_nolock(__crt_stdio_stream const stream, wchar_t) throw()
32*04e0dc4aSTimo Kreuzer {
33*04e0dc4aSTimo Kreuzer // When reading wide character elements, we must handle the case where a two
34*04e0dc4aSTimo Kreuzer // byte character straddles the buffer boundary, with the low order byte at
35*04e0dc4aSTimo Kreuzer // the end of the old buffer and the high order byte at the start of the new
36*04e0dc4aSTimo Kreuzer // buffer.
37*04e0dc4aSTimo Kreuzer //
38*04e0dc4aSTimo Kreuzer // We do this here: if there is exactly one character left in the buffer, we
39*04e0dc4aSTimo Kreuzer // store that and set a flag so we know to pick it up later.
40*04e0dc4aSTimo Kreuzer filwbuf_context context;
41*04e0dc4aSTimo Kreuzer if (stream->_cnt == 1)
42*04e0dc4aSTimo Kreuzer {
43*04e0dc4aSTimo Kreuzer context._is_split_character = true;
44*04e0dc4aSTimo Kreuzer context._leftover_low_order_byte = static_cast<unsigned char>(*stream->_ptr);
45*04e0dc4aSTimo Kreuzer }
46*04e0dc4aSTimo Kreuzer else
47*04e0dc4aSTimo Kreuzer {
48*04e0dc4aSTimo Kreuzer context._is_split_character = false;
49*04e0dc4aSTimo Kreuzer context._leftover_low_order_byte = 0;
50*04e0dc4aSTimo Kreuzer }
51*04e0dc4aSTimo Kreuzer return context;
52*04e0dc4aSTimo Kreuzer }
53*04e0dc4aSTimo Kreuzer
54*04e0dc4aSTimo Kreuzer
55*04e0dc4aSTimo Kreuzer // These functions test whether a buffer is valid following a call to _read().
is_buffer_valid_nolock(__crt_stdio_stream const stream,char)56*04e0dc4aSTimo Kreuzer static bool is_buffer_valid_nolock(__crt_stdio_stream const stream, char) throw()
57*04e0dc4aSTimo Kreuzer {
58*04e0dc4aSTimo Kreuzer return stream->_cnt != 0
59*04e0dc4aSTimo Kreuzer && stream->_cnt != -1;
60*04e0dc4aSTimo Kreuzer }
61*04e0dc4aSTimo Kreuzer
is_buffer_valid_nolock(__crt_stdio_stream const stream,wchar_t)62*04e0dc4aSTimo Kreuzer static bool is_buffer_valid_nolock(__crt_stdio_stream const stream, wchar_t) throw()
63*04e0dc4aSTimo Kreuzer {
64*04e0dc4aSTimo Kreuzer return stream->_cnt != 0
65*04e0dc4aSTimo Kreuzer && stream->_cnt != 1
66*04e0dc4aSTimo Kreuzer && stream->_cnt != -1;
67*04e0dc4aSTimo Kreuzer }
68*04e0dc4aSTimo Kreuzer
69*04e0dc4aSTimo Kreuzer
70*04e0dc4aSTimo Kreuzer
71*04e0dc4aSTimo Kreuzer // These functions read a character from the stream after the _read() has
72*04e0dc4aSTimo Kreuzer // completed successfully.
read_character_nolock(__crt_stdio_stream const stream,int,char)73*04e0dc4aSTimo Kreuzer static unsigned char read_character_nolock(__crt_stdio_stream const stream, int, char) throw()
74*04e0dc4aSTimo Kreuzer {
75*04e0dc4aSTimo Kreuzer --stream->_cnt;
76*04e0dc4aSTimo Kreuzer return static_cast<unsigned char>(*stream->_ptr++);
77*04e0dc4aSTimo Kreuzer }
78*04e0dc4aSTimo Kreuzer
79*04e0dc4aSTimo Kreuzer
80*04e0dc4aSTimo Kreuzer
read_character_nolock(__crt_stdio_stream const stream,filwbuf_context const context,wchar_t)81*04e0dc4aSTimo Kreuzer static wchar_t read_character_nolock(
82*04e0dc4aSTimo Kreuzer __crt_stdio_stream const stream,
83*04e0dc4aSTimo Kreuzer filwbuf_context const context,
84*04e0dc4aSTimo Kreuzer wchar_t
85*04e0dc4aSTimo Kreuzer ) throw()
86*04e0dc4aSTimo Kreuzer {
87*04e0dc4aSTimo Kreuzer if (context._is_split_character)
88*04e0dc4aSTimo Kreuzer {
89*04e0dc4aSTimo Kreuzer // If the character was split across buffers, we read only one byte
90*04e0dc4aSTimo Kreuzer // from the new buffer and or it with the leftover byte from the old
91*04e0dc4aSTimo Kreuzer // buffer.
92*04e0dc4aSTimo Kreuzer unsigned char high_order_byte = static_cast<unsigned char>(*stream->_ptr);
93*04e0dc4aSTimo Kreuzer wchar_t result = (high_order_byte << 8) | context._leftover_low_order_byte;
94*04e0dc4aSTimo Kreuzer
95*04e0dc4aSTimo Kreuzer --stream->_cnt;
96*04e0dc4aSTimo Kreuzer ++stream->_ptr;
97*04e0dc4aSTimo Kreuzer return (result);
98*04e0dc4aSTimo Kreuzer }
99*04e0dc4aSTimo Kreuzer else
100*04e0dc4aSTimo Kreuzer {
101*04e0dc4aSTimo Kreuzer wchar_t const result = 0xffff & reinterpret_cast<wchar_t const&>(*stream->_ptr);
102*04e0dc4aSTimo Kreuzer
103*04e0dc4aSTimo Kreuzer stream->_cnt -= sizeof(wchar_t);
104*04e0dc4aSTimo Kreuzer stream->_ptr += sizeof(wchar_t);
105*04e0dc4aSTimo Kreuzer
106*04e0dc4aSTimo Kreuzer return result;
107*04e0dc4aSTimo Kreuzer }
108*04e0dc4aSTimo Kreuzer }
109*04e0dc4aSTimo Kreuzer
110*04e0dc4aSTimo Kreuzer
111*04e0dc4aSTimo Kreuzer
112*04e0dc4aSTimo Kreuzer // Fills a buffer and reads the first character. Allocates a buffer for the
113*04e0dc4aSTimo Kreuzer // stream if the stream does not yet have one. This function is intended for
114*04e0dc4aSTimo Kreuzer // internal usage only. This function assumes that the caller has acquired
115*04e0dc4aSTimo Kreuzer // the lock for the stream.
116*04e0dc4aSTimo Kreuzer //
117*04e0dc4aSTimo Kreuzer // Returns the first character from the new buffer. For the wide character
118*04e0dc4aSTimo Kreuzer // version, the case is handled where a character straddles the old and new
119*04e0dc4aSTimo Kreuzer // buffers. Returns EOF if the file is string-backed or is not open for
120*04e0dc4aSTimo Kreuzer // reading, or if there are no more characters to be read.
121*04e0dc4aSTimo Kreuzer template <typename Character>
common_refill_and_read_nolock(__crt_stdio_stream const stream)122*04e0dc4aSTimo Kreuzer static int __cdecl common_refill_and_read_nolock(__crt_stdio_stream const stream) throw()
123*04e0dc4aSTimo Kreuzer {
124*04e0dc4aSTimo Kreuzer typedef __acrt_stdio_char_traits<Character> stdio_traits;
125*04e0dc4aSTimo Kreuzer
126*04e0dc4aSTimo Kreuzer _VALIDATE_RETURN(stream.valid(), EINVAL, stdio_traits::eof);
127*04e0dc4aSTimo Kreuzer
128*04e0dc4aSTimo Kreuzer if (!stream.is_in_use() || stream.is_string_backed())
129*04e0dc4aSTimo Kreuzer return stdio_traits::eof;
130*04e0dc4aSTimo Kreuzer
131*04e0dc4aSTimo Kreuzer if (stream.has_all_of(_IOWRITE))
132*04e0dc4aSTimo Kreuzer {
133*04e0dc4aSTimo Kreuzer stream.set_flags(_IOERROR);
134*04e0dc4aSTimo Kreuzer return stdio_traits::eof;
135*04e0dc4aSTimo Kreuzer }
136*04e0dc4aSTimo Kreuzer
137*04e0dc4aSTimo Kreuzer stream.set_flags(_IOREAD);
138*04e0dc4aSTimo Kreuzer
139*04e0dc4aSTimo Kreuzer // Get a buffer, if necessary:
140*04e0dc4aSTimo Kreuzer if (!stream.has_any_buffer())
141*04e0dc4aSTimo Kreuzer __acrt_stdio_allocate_buffer_nolock(stream.public_stream());
142*04e0dc4aSTimo Kreuzer
143*04e0dc4aSTimo Kreuzer auto const context = get_context_nolock(stream, Character());
144*04e0dc4aSTimo Kreuzer
145*04e0dc4aSTimo Kreuzer stream->_ptr = stream->_base;
146*04e0dc4aSTimo Kreuzer stream->_cnt = _read(_fileno(stream.public_stream()), stream->_base, stream->_bufsiz);
147*04e0dc4aSTimo Kreuzer
148*04e0dc4aSTimo Kreuzer if (!is_buffer_valid_nolock(stream, Character()))
149*04e0dc4aSTimo Kreuzer {
150*04e0dc4aSTimo Kreuzer stream.set_flags(stream->_cnt != 0 ? _IOERROR : _IOEOF);
151*04e0dc4aSTimo Kreuzer stream->_cnt = 0;
152*04e0dc4aSTimo Kreuzer return stdio_traits::eof;
153*04e0dc4aSTimo Kreuzer }
154*04e0dc4aSTimo Kreuzer
155*04e0dc4aSTimo Kreuzer if (!stream.has_any_of(_IOWRITE | _IOUPDATE) &&
156*04e0dc4aSTimo Kreuzer ((_osfile_safe(_fileno(stream.public_stream())) & (FTEXT | FEOFLAG)) == (FTEXT | FEOFLAG)))
157*04e0dc4aSTimo Kreuzer {
158*04e0dc4aSTimo Kreuzer stream.set_flags(_IOCTRLZ);
159*04e0dc4aSTimo Kreuzer }
160*04e0dc4aSTimo Kreuzer
161*04e0dc4aSTimo Kreuzer // Check for small _bufsiz (_SMALL_BUFSIZ). If it is small and if it is our
162*04e0dc4aSTimo Kreuzer // buffer, then this must be the first call to this function after an fseek
163*04e0dc4aSTimo Kreuzer // on a read-access-only stream. Restore _bufsiz to its larger value
164*04e0dc4aSTimo Kreuzer // (_INTERNAL_BUFSIZ) so that the next call to this function, if one is made,
165*04e0dc4aSTimo Kreuzer // will fill the whole buffer.
166*04e0dc4aSTimo Kreuzer if (stream->_bufsiz == _SMALL_BUFSIZ &&
167*04e0dc4aSTimo Kreuzer stream.has_crt_buffer() &&
168*04e0dc4aSTimo Kreuzer !stream.has_all_of(_IOBUFFER_SETVBUF))
169*04e0dc4aSTimo Kreuzer {
170*04e0dc4aSTimo Kreuzer stream->_bufsiz = _INTERNAL_BUFSIZ;
171*04e0dc4aSTimo Kreuzer }
172*04e0dc4aSTimo Kreuzer
173*04e0dc4aSTimo Kreuzer return read_character_nolock(stream, context, Character());
174*04e0dc4aSTimo Kreuzer }
175*04e0dc4aSTimo Kreuzer
176*04e0dc4aSTimo Kreuzer
177*04e0dc4aSTimo Kreuzer
__acrt_stdio_refill_and_read_narrow_nolock(FILE * const stream)178*04e0dc4aSTimo Kreuzer extern "C" int __cdecl __acrt_stdio_refill_and_read_narrow_nolock(FILE* const stream)
179*04e0dc4aSTimo Kreuzer {
180*04e0dc4aSTimo Kreuzer return common_refill_and_read_nolock<char>(__crt_stdio_stream(stream));
181*04e0dc4aSTimo Kreuzer }
182*04e0dc4aSTimo Kreuzer
183*04e0dc4aSTimo Kreuzer
184*04e0dc4aSTimo Kreuzer
__acrt_stdio_refill_and_read_wide_nolock(FILE * const stream)185*04e0dc4aSTimo Kreuzer extern "C" int __cdecl __acrt_stdio_refill_and_read_wide_nolock(FILE* const stream)
186*04e0dc4aSTimo Kreuzer {
187*04e0dc4aSTimo Kreuzer return common_refill_and_read_nolock<wchar_t>(__crt_stdio_stream(stream));
188*04e0dc4aSTimo Kreuzer }
189