ReactOS 0.4.16-dev-814-g656a5dc
fread.cpp
Go to the documentation of this file.
1//
2// fread.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines fread() and related functions, which read unformatted data from a
7// stdio stream.
8//
10
11#ifdef _DEBUG
12 #define _BUFFER_FILL_PATTERN _SECURECRT_FILL_BUFFER_PATTERN
13#else
14 #define _BUFFER_FILL_PATTERN 0
15#endif
16
17
18
19// Reads data from a stream into the result buffer. The function reads elements
20// of size 'element_size' until it has read 'element_count' elements, until the
21// buffer is full, or until EOF is reached.
22//
23// Returns the number of "whole" elements that were read into the buffer. This
24// may be fewer than the requested number of elements if an error occurs or if
25// EOF is encountered. In this case, ferror() or feof() should be used to
26// distinguish between the two conditions.
27//
28// If the result buffer becomes full before the requested number of elements are
29// read, the buffer is zero-filled, zero is returned, and errno is set to ERANGE.
30extern "C" size_t __cdecl fread_s(
31 void* const buffer,
32 size_t const buffer_size,
33 size_t const element_size,
34 size_t const element_count,
35 FILE* const stream
36 )
37{
38 if (element_size == 0 || element_count == 0)
39 return 0;
40
41 // The rest of the argument validation is done in the _nolock function. Here
42 // we only need to validate that the stream is non-null before we lock it.
43 if (stream == nullptr)
44 {
47
48 _VALIDATE_RETURN(stream != nullptr, EINVAL, 0);
49 }
50
51 size_t return_value = 0;
52
54 __try
55 {
56 return_value = _fread_nolock_s(buffer, buffer_size, element_size, element_count, stream);
57 }
59 {
61 }
63
64 return return_value;
65}
66
67
68
69extern "C" size_t __cdecl _fread_nolock_s(
70 void* const buffer,
71 size_t const buffer_size,
72 size_t const element_size,
73 size_t const element_count,
74 FILE* const public_stream
75 )
76{
77 __crt_stdio_stream const stream(public_stream);
78
79 if (element_size == 0 || element_count == 0)
80 return 0;
81
82 _VALIDATE_RETURN(buffer != nullptr, EINVAL, 0);
83 if (!stream.valid() || element_count > (SIZE_MAX / element_size))
84 {
87
88 _VALIDATE_RETURN(stream.valid(), EINVAL, 0);
89 _VALIDATE_RETURN(element_count <= (SIZE_MAX / element_size), EINVAL, 0);
90 }
91
92 // Figure out how big the buffer is; if the stream doesn't currently have a
93 // buffer, we assume that we'll get one with the usual internal buffer size:
94 unsigned stream_buffer_size = stream.has_any_buffer()
95 ? stream->_bufsiz
97
98 // The total number of bytes to be read into the buffer:
99 size_t const total_bytes = element_size * element_count;
100
101 char* data = static_cast<char*>(buffer);
102
103 // Read blocks of data from the stream until we have read the requested
104 // number of elements or we fill the buffer.
105 size_t remaining_bytes = total_bytes;
106 size_t remaining_buffer = buffer_size;
107 while (remaining_bytes != 0)
108 {
109 // If the stream is buffered and has characters, copy them into the
110 // result buffer:
111 if (stream.has_any_buffer() && stream->_cnt != 0)
112 {
113 if(stream->_cnt < 0)
114 {
115 _ASSERTE(("Inconsistent Stream Count. Flush between consecutive read and write", stream->_cnt >= 0));
116 stream.set_flags(_IOERROR);
117 return (total_bytes - remaining_bytes) / element_size;
118 }
119
120 unsigned const bytes_to_read = remaining_bytes < static_cast<size_t>(stream->_cnt)
121 ? static_cast<unsigned>(remaining_bytes)
122 : static_cast<unsigned>(stream->_cnt);
123
124 if (bytes_to_read > remaining_buffer)
125 {
128
129 _VALIDATE_RETURN(("buffer too small", 0), ERANGE, 0)
130 }
131
132 memcpy_s(data, remaining_buffer, stream->_ptr, bytes_to_read);
133
134 // Update the stream and local tracking variables to account for the
135 // read. Note that the number of bytes actually read is always equal
136 // to the number of bytes that we expected to read, because the data
137 // was already buffered in the stream.
138 remaining_bytes -= bytes_to_read;
139 stream->_cnt -= bytes_to_read;
140 stream->_ptr += bytes_to_read;
141 data += bytes_to_read;
142 remaining_buffer -= bytes_to_read;
143 }
144 // There is no data remaining in the stream buffer to be read, and we
145 // need to read more data than will fit in the buffer (or we need to read
146 // at least enough data to fill the buffer completely):
147 else if (remaining_bytes >= stream_buffer_size)
148 {
149 // We can read at most INT_MAX bytes at a time. This is a hard limit
150 // of the lowio _read() function.
151 unsigned const maximum_bytes_to_read = remaining_bytes > INT_MAX
152 ? static_cast<unsigned>(INT_MAX)
153 : static_cast<unsigned>(remaining_bytes);
154
155 // If the stream has a buffer, we want to read the largest chunk that
156 // is a multiple of the buffer size, to keep the stream buffer state
157 // consistent. If the stream is not buffered, we can read the maximum
158 // number of bytes that we can:
159 unsigned const bytes_to_read = stream_buffer_size != 0
160 ? static_cast<unsigned>(maximum_bytes_to_read - maximum_bytes_to_read % stream_buffer_size)
161 : maximum_bytes_to_read;
162
163 if (bytes_to_read > remaining_buffer)
164 {
167
168 _VALIDATE_RETURN(("buffer too small", 0), ERANGE, 0)
169 }
170
171 // We are about to read data directly from the underlying file
172 // descriptor, bypassing the stream buffer. We reset the stream
173 // buffer state to ensure that future seeks do not incorrectly
174 // assume that the buffer contents are valid.
176
177 // Do the read. Note that if the stream is open in text mode, the
178 // bytes_read may not be the same as the bytes_to_read, due to
179 // newline translation.
180 int const bytes_read = _read_nolock(_fileno(stream.public_stream()), data, bytes_to_read);
181 if (bytes_read == 0)
182 {
183 // We encountered EOF:
184 stream.set_flags(_IOEOF);
185 return (total_bytes - remaining_bytes) / element_size;
186 }
187 else if (bytes_read < 0)
188 {
189 // The _read failed:
190 stream.set_flags(_IOERROR);
191 return (total_bytes - remaining_bytes) / element_size;
192 }
193
194 // Update the iteration state to reflect the read:
195 remaining_bytes -= bytes_read;
196 data += bytes_read;
197 remaining_buffer -= bytes_read;
198 }
199 // Otherwise, the stream does not have a buffer, or the stream buffer
200 // is full and there is insufficient space to do a direct read, so use
201 // __acrt_stdio_refill_and_read_narrow_nolock:
202 else
203 {
204 int const c = __acrt_stdio_refill_and_read_narrow_nolock(stream.public_stream());
205 if (c == EOF)
206 return (total_bytes - remaining_bytes) / element_size;
207
208 // If we have filled the result buffer before we have read the
209 // requested number of elements or reached EOF, it is an error:
210 if (remaining_buffer == 0)
211 {
214
215 _VALIDATE_RETURN(("buffer too small", 0), ERANGE, 0)
216 }
217
218 *data++ = static_cast<char>(c);
219 --remaining_bytes;
220 --remaining_buffer;
221
222 stream_buffer_size = stream->_bufsiz;
223 }
224 }
225
226 return element_count; // Success!
227}
228
229
230
231extern "C" size_t __cdecl fread(
232 void* const buffer,
233 size_t const element_size,
234 size_t const element_count,
235 FILE* const stream
236 )
237{
238 // Assume there is enough space in the destination buffer
239#pragma warning(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY) // 26015 - fread is unsafe
241}
242
243
244
245extern "C" size_t __cdecl _fread_nolock(
246 void* const buffer,
247 size_t const element_size,
248 size_t const element_count,
249 FILE* const stream
250 )
251{
252 // Assume there is enough space in the destination buffer
253#pragma warning(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY) // 26015 - _fread_nolock is unsafe
255}
int __cdecl __acrt_stdio_refill_and_read_narrow_nolock(FILE *const stream)
Definition: _filbuf.cpp:178
#define EINVAL
Definition: acclib.h:90
#define ERANGE
Definition: acclib.h:92
#define __cdecl
Definition: accygwin.h:79
#define _CRT_UNBOUNDED_BUFFER_SIZE
#define _INTERNAL_BUFSIZ
void __cdecl __acrt_stdio_reset_buffer(__crt_stdio_stream const stream)
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
#define _ASSERTE(expr)
Definition: crtdbg.h:114
size_t const element_size
Definition: debug_heap.cpp:510
#define _BUFFER_FILL_PATTERN
Definition: fread.cpp:14
size_t __cdecl fread(void *const buffer, size_t const element_size, size_t const element_count, FILE *const stream)
Definition: fread.cpp:231
size_t __cdecl fread_s(void *const buffer, size_t const buffer_size, size_t const element_size, size_t const element_count, FILE *const stream)
Definition: fread.cpp:30
size_t __cdecl _fread_nolock(void *const buffer, size_t const element_size, size_t const element_count, FILE *const stream)
Definition: fread.cpp:245
size_t __cdecl _fread_nolock_s(void *const buffer, size_t const buffer_size, size_t const element_size, size_t const element_count, FILE *const public_stream)
Definition: fread.cpp:69
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLuint buffer
Definition: glext.h:5915
const GLubyte * c
Definition: glext.h:8905
_Check_return_ _CRTIMP int __cdecl _fileno(_In_ FILE *_File)
#define EOF
Definition: stdio.h:24
_CRTIMP void __cdecl _unlock_file(_Inout_ FILE *_File)
#define _IOEOF
Definition: stdio.h:132
_CRTIMP void __cdecl _lock_file(_Inout_ FILE *_File)
#define INT_MAX
Definition: intsafe.h:150
#define c
Definition: ke_i.h:80
#define __try
Definition: pseh2_64.h:172
#define __endtry
Definition: pseh2_64.h:175
#define __finally
Definition: pseh2_64.h:174
#define SIZE_MAX
Definition: compat.h:66
int CDECL memcpy_s(void *dest, size_t numberOfElements, const void *src, size_t count)
Definition: heap.c:800
#define memset(x, y, z)
Definition: compat.h:39
int __cdecl _read_nolock(int const fh, void *const result_buffer, unsigned const result_buffer_size)
Definition: read.cpp:408
wchar_t const *const size_t const buffer_size
Definition: stat.cpp:95
Definition: parse.h:23