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