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