Line data Source code
1 : // SPDX-License-Identifier: GPL-3.0-or-later
2 : // Copyright (C) 2011 Andrea Mazzoleni
3 :
4 : #ifndef __STREAM_H
5 : #define __STREAM_H
6 :
7 : #include "util.h"
8 :
9 : /****************************************************************************/
10 : /* stream */
11 :
12 : #define STREAM_FLAGS_SEQUENTIAL 1 /**< Advise a squential read. */
13 : #define STREAM_FLAGS_CRC 2 /**< Enable the CRC computation. */
14 :
15 : /**
16 : * Size of the buffer of the stream.
17 : *
18 : * It's not a constant for testing purpose.
19 : */
20 : extern unsigned STREAM_SIZE;
21 :
22 : #define STREAM_STATE_READ 0 /**< The stream is in a normal state of read. */
23 : #define STREAM_STATE_WRITE 1 /**< The stream is in a normal state of write. */
24 : #define STREAM_STATE_ERROR -1 /**< An error was encountered. */
25 : #define STREAM_STATE_EOF 2 /**< The end of file was encountered. */
26 :
27 : struct stream_handle {
28 : int f; /**< Handle of the file. */
29 : char path[PATH_MAX]; /**< Path of the file. */
30 : };
31 :
32 : struct stream {
33 : unsigned char* buffer; /**< Buffer of the stream. */
34 : off_t buffer_size; /**< Size of the buffer */
35 : unsigned char* pos; /**< Current position in the buffer. */
36 : unsigned char* end; /**< End position of the buffer. */
37 : struct stream_handle* handle; /**< Set of handles. */
38 : off_t offset; /**< Offset into the file. */
39 : off_t offset_uncached; /**< Offset into the file excluding the cached data. */
40 : off_t size; /**< File size, only in read */
41 :
42 : int flags; /**< Flags passed on open */
43 : int state; /**< State of the stream. One of STREAM_STATE. */
44 : int state_index; /**< Index of the handle causing a state change. */
45 : unsigned handle_size; /**< Number of handles. */
46 :
47 : /**
48 : * CRC of the data read or written in the file.
49 : *
50 : * If reading, it's the CRC of all data read from the file,
51 : * including the one in the buffer.
52 : * If writing it's all the data wrote to the file,
53 : * excluding the one still in buffer yet to be written.
54 : */
55 : uint32_t crc;
56 :
57 : /**
58 : * CRC of the file excluding the cached data in the buffer.
59 : *
60 : * If reading, it's the CRC of the data read from the file,
61 : * excluding the one in the buffer.
62 : * If writing it's all the data wrote to the file,
63 : * excluding the one still in buffer yet to be written.
64 : */
65 : uint32_t crc_uncached;
66 :
67 : /**
68 : * CRC of the data written to the stream.
69 : *
70 : * This is an extra check of the data that is written to
71 : * file to ensure that it's consistent even in case
72 : * of memory errors.
73 : *
74 : * This extra check takes about 2 seconds for each GB of
75 : * content file with the Intel CRC instruction,
76 : * and about 4 seconds without it.
77 : * But usually this doesn't slow down the write process,
78 : * as the disk is the bottle-neck.
79 : *
80 : * Note that this CRC doesn't have the IV processing.
81 : *
82 : * Not used in reading.
83 : * In writing, it's all the data wrote calling sput() functions.
84 : */
85 : uint32_t crc_stream;
86 : };
87 :
88 : /**
89 : * Opaque STREAM type. Like ::FILE.
90 : */
91 : typedef struct stream STREAM;
92 :
93 : /**
94 : * Open a stream for reading. Like fopen("r").
95 : */
96 : STREAM* sopen_read(const char* file, int flags);
97 :
98 : /**
99 : * Open a stream for writing. Like fopen("w").
100 : */
101 : STREAM* sopen_write(const char* file, int flags);
102 :
103 : /**
104 : * Open a set of streams for writing. Like fopen("w").
105 : */
106 : STREAM* sopen_multi_write(unsigned count, int flags);
107 :
108 : /**
109 : * Specify the file to open.
110 : */
111 : int sopen_multi_file(STREAM* s, unsigned i, const char* file);
112 :
113 : /**
114 : * Close a stream. Like fclose().
115 : */
116 : int sclose(STREAM* s);
117 :
118 : /**
119 : * Return the handle of the file.
120 : * In case of multi file, the first one is returned.
121 : */
122 : int shandle(STREAM* s);
123 :
124 : /**
125 : * Read the stream until the end, and return the latest 4 chars.
126 : * The CRC of the file is also computed, and you can get it using scrc().
127 : * \return 0 on success, or EOF on error.
128 : */
129 : int sdeplete(STREAM* s, unsigned char* last);
130 :
131 : /**
132 : * Flush the write stream buffer.
133 : * \return 0 on success, or EOF on error.
134 : */
135 : int sflush(STREAM* s);
136 :
137 : /**
138 : * Get the file pointer.
139 : */
140 : int64_t stell(STREAM* s);
141 :
142 : /**
143 : * Get the CRC of the processed data.
144 : */
145 : uint32_t scrc(STREAM* s);
146 :
147 : /**
148 : * Get the CRC of the processed data in put.
149 : */
150 : uint32_t scrc_stream(STREAM* s);
151 :
152 : /**
153 : * Check if the buffer has enough data loaded.
154 : */
155 37099286 : static inline int sptrlookup(STREAM* s, int size)
156 : {
157 37099286 : return s->pos + size <= s->end;
158 : }
159 :
160 : /**
161 : * Get the current stream ptr.
162 : */
163 37060123 : static inline unsigned char* sptrget(STREAM* s)
164 : {
165 37060123 : return s->pos;
166 : }
167 :
168 : /**
169 : * Set the current stream ptr.
170 : */
171 37060123 : static inline void sptrset(STREAM* s, unsigned char* ptr)
172 : {
173 37060123 : s->pos = ptr;
174 37060123 : }
175 :
176 : /**
177 : * Check the error status. Like ferror().
178 : */
179 4025551 : static inline int serror(STREAM* s)
180 : {
181 4025551 : return s->state == STREAM_STATE_ERROR;
182 : }
183 :
184 : /**
185 : * Check the eof status. Like feof().
186 : */
187 1 : static inline int seof(STREAM* s)
188 : {
189 1 : return s->state == STREAM_STATE_EOF;
190 : }
191 :
192 : /**
193 : * Get the index of the handle that caused the error.
194 : */
195 : static inline int serrorindex(STREAM* s)
196 : {
197 : return s->state_index;
198 : }
199 :
200 : /**
201 : * Get the path of the handle that caused the error.
202 : */
203 0 : static inline const char* serrorfile(STREAM* s)
204 : {
205 0 : return s->handle[s->state_index].path;
206 : }
207 :
208 : /**
209 : * Sync the stream. Like fsync().
210 : */
211 : int ssync(STREAM* s);
212 :
213 : /****************************************************************************/
214 : /* get */
215 :
216 : /**
217 : * \internal Used by sgetc().
218 : * \note Don't call this directly, but use sgetc().
219 : */
220 : int sgetc_uncached(STREAM* s);
221 :
222 : /**
223 : * Read a char. Like fgetc().
224 : */
225 91121938 : static inline int sgetc(STREAM* s)
226 : {
227 91121938 : if (tommy_unlikely(s->pos == s->end))
228 299844 : return sgetc_uncached(s);
229 90822094 : return *s->pos++;
230 : }
231 :
232 : /**
233 : * Unread a char.
234 : * Like ungetc() but you have to unget the same char read.
235 : */
236 43118 : static inline void sungetc(int c, STREAM* s)
237 : {
238 43118 : if (c != EOF)
239 42107 : --s->pos;
240 43118 : }
241 :
242 : /**
243 : * Read a fixed amount of chars.
244 : * Return 0 on success, or -1 on error.
245 : */
246 : int sread(STREAM* f, void* void_data, unsigned size);
247 :
248 : /**
249 : * Get a char from a stream, ignoring one '\r'.
250 : */
251 7599 : static inline int sgeteol(STREAM* f)
252 : {
253 : int c;
254 :
255 7599 : c = sgetc(f);
256 7599 : if (c == '\r')
257 0 : c = sgetc(f);
258 :
259 7599 : return c;
260 : }
261 :
262 : /**
263 : * Read all the spaces and tabs.
264 : * Return the number of spaces and tabs read.
265 : */
266 25559 : static inline int sgetspace(STREAM* f)
267 : {
268 25559 : int count = 0;
269 : int c;
270 :
271 25559 : c = sgetc(f);
272 35216 : while (c == ' ' || c == '\t') {
273 9657 : ++count;
274 9657 : c = sgetc(f);
275 : }
276 :
277 25559 : sungetc(c, f);
278 25559 : return count;
279 : }
280 :
281 : /**
282 : * Read until the first space or tab.
283 : * Stop at the first ' ', '\t', '\n' or EOF.
284 : * Return <0 if the buffer is too small, or the number of chars read.
285 : */
286 : int sgettok(STREAM* f, char* str, int size);
287 :
288 : /**
289 : * Read until the end of line.
290 : * Stop at the first '\n' or EOF. Note that '\n' is left in the stream.
291 : * Return <0 if the buffer is too small, or the number of chars read.
292 : */
293 : int sgetline(STREAM* f, char* str, int size);
294 :
295 : /**
296 : * Like sgetline() but remove ' ' and '\t' at the end.
297 : */
298 : int sgetlasttok(STREAM* f, char* str, int size);
299 :
300 : /**
301 : * Read a 32 bit number.
302 : * Stop at the first not digit char or EOF.
303 : * Return <0 if there isn't enough to read.
304 : */
305 : int sgetu32(STREAM* f, uint32_t* value);
306 :
307 : /****************************************************************************/
308 : /* binary get */
309 :
310 : /**
311 : * Read a binary 32 bit number in packet format.
312 : * Return <0 if there isn't enough to read.
313 : */
314 : int sgetb32(STREAM* f, uint32_t* value);
315 :
316 : /**
317 : * Read a binary 64 bit number in packet format.
318 : * Return <0 if there isn't enough to read.
319 : */
320 : int sgetb64(STREAM* f, uint64_t* value);
321 :
322 : /**
323 : * Read a binary 32 bit number in little endian format.
324 : * Return <0 if there isn't enough to read.
325 : */
326 : int sgetble32(STREAM* f, uint32_t* value);
327 :
328 : /**
329 : * Read a binary string.
330 : * Return -1 on error or if the buffer is too small, or the number of chars read.
331 : */
332 : int sgetbs(STREAM* f, char* str, int size);
333 :
334 : /****************************************************************************/
335 : /* put */
336 :
337 : /**
338 : * Write a char. Like fputc().
339 : * Return 0 on success or -1 on error.
340 : */
341 4202652 : static inline int sputc(int c, STREAM* s)
342 : {
343 4202652 : if (s->pos == s->end) {
344 38819 : if (sflush(s) != 0)
345 0 : return -1;
346 : }
347 :
348 : /**
349 : * Update the crc *before* writing the data in the buffer
350 : *
351 : * This must be done before the memory write,
352 : * to be able to detect memory errors on the buffer,
353 : * happening before we write it on the file.
354 : */
355 4202652 : if (s->flags & STREAM_FLAGS_CRC)
356 4202652 : s->crc_stream = crc32c_plain_char(s->crc_stream, c);
357 :
358 4202652 : *s->pos++ = c;
359 :
360 4202652 : return 0;
361 : }
362 :
363 : /**
364 : * Write a end of line.
365 : * Return 0 on success or -1 on error.
366 : */
367 : static inline int sputeol(STREAM* s)
368 : {
369 : #ifdef _WIN32
370 : if (sputc('\r', s) != 0)
371 : return -1;
372 : #endif
373 : return sputc('\n', s);
374 : }
375 :
376 : /**
377 : * Write a sized string.
378 : * Return 0 on success or -1 on error.
379 : */
380 : int swrite(const void* data, unsigned size, STREAM* f);
381 :
382 : /****************************************************************************/
383 : /* binary put */
384 :
385 : /**
386 : * Write a binary 32 bit number in packed format.
387 : * Return 0 on success or -1 on error.
388 : */
389 : int sputb32(uint32_t value, STREAM* s);
390 :
391 : /**
392 : * Write a binary 64 bit number in packed format.
393 : * Return 0 on success or -1 on error.
394 : */
395 : int sputb64(uint64_t value, STREAM* s);
396 :
397 : /**
398 : * Write a binary 32 bit number in little endian format.
399 : * Return 0 on success or -1 on error.
400 : */
401 : int sputble32(uint32_t value, STREAM* s);
402 :
403 : /**
404 : * Write a binary string.
405 : * Return 0 on success or -1 on error.
406 : */
407 : int sputbs(const char* str, STREAM* s);
408 :
409 : #endif
410 :
|