LCOV - code coverage report
Current view: top level - cmdline - stream.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 38 42 90.5 %
Date: 2026-04-29 15:04:44 Functions: 10 11 90.9 %

          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             : 

Generated by: LCOV version 1.0