xref: /reactos/sdk/lib/ucrt/stdio/_filbuf.cpp (revision 04e0dc4a)
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