1*2b9c00cbSConrad Meyer /* 2*2b9c00cbSConrad Meyer * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. 3*2b9c00cbSConrad Meyer * All rights reserved. 4*2b9c00cbSConrad Meyer * 5*2b9c00cbSConrad Meyer * This source code is licensed under both the BSD-style license (found in the 6*2b9c00cbSConrad Meyer * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*2b9c00cbSConrad Meyer * in the COPYING file in the root directory of this source tree). 8*2b9c00cbSConrad Meyer * You may select, at your option, one of the above-listed licenses. 9*2b9c00cbSConrad Meyer */ 10*2b9c00cbSConrad Meyer 11*2b9c00cbSConrad Meyer /* 12*2b9c00cbSConrad Meyer * This header file has common utility functions used in examples. 13*2b9c00cbSConrad Meyer */ 14*2b9c00cbSConrad Meyer #ifndef COMMON_H 15*2b9c00cbSConrad Meyer #define COMMON_H 16*2b9c00cbSConrad Meyer 17*2b9c00cbSConrad Meyer #include <stdlib.h> // malloc, free, exit 18*2b9c00cbSConrad Meyer #include <stdio.h> // fprintf, perror, fopen, etc. 19*2b9c00cbSConrad Meyer #include <string.h> // strerror 20*2b9c00cbSConrad Meyer #include <errno.h> // errno 21*2b9c00cbSConrad Meyer #include <sys/stat.h> // stat 22*2b9c00cbSConrad Meyer #include <zstd.h> 23*2b9c00cbSConrad Meyer 24*2b9c00cbSConrad Meyer /* 25*2b9c00cbSConrad Meyer * Define the returned error code from utility functions. 26*2b9c00cbSConrad Meyer */ 27*2b9c00cbSConrad Meyer typedef enum { 28*2b9c00cbSConrad Meyer ERROR_fsize = 1, 29*2b9c00cbSConrad Meyer ERROR_fopen = 2, 30*2b9c00cbSConrad Meyer ERROR_fclose = 3, 31*2b9c00cbSConrad Meyer ERROR_fread = 4, 32*2b9c00cbSConrad Meyer ERROR_fwrite = 5, 33*2b9c00cbSConrad Meyer ERROR_loadFile = 6, 34*2b9c00cbSConrad Meyer ERROR_saveFile = 7, 35*2b9c00cbSConrad Meyer ERROR_malloc = 8, 36*2b9c00cbSConrad Meyer ERROR_largeFile = 9, 37*2b9c00cbSConrad Meyer } COMMON_ErrorCode; 38*2b9c00cbSConrad Meyer 39*2b9c00cbSConrad Meyer /*! CHECK 40*2b9c00cbSConrad Meyer * Check that the condition holds. If it doesn't print a message and die. 41*2b9c00cbSConrad Meyer */ 42*2b9c00cbSConrad Meyer #define CHECK(cond, ...) \ 43*2b9c00cbSConrad Meyer do { \ 44*2b9c00cbSConrad Meyer if (!(cond)) { \ 45*2b9c00cbSConrad Meyer fprintf(stderr, \ 46*2b9c00cbSConrad Meyer "%s:%d CHECK(%s) failed: ", \ 47*2b9c00cbSConrad Meyer __FILE__, \ 48*2b9c00cbSConrad Meyer __LINE__, \ 49*2b9c00cbSConrad Meyer #cond); \ 50*2b9c00cbSConrad Meyer fprintf(stderr, "" __VA_ARGS__); \ 51*2b9c00cbSConrad Meyer fprintf(stderr, "\n"); \ 52*2b9c00cbSConrad Meyer exit(1); \ 53*2b9c00cbSConrad Meyer } \ 54*2b9c00cbSConrad Meyer } while (0) 55*2b9c00cbSConrad Meyer 56*2b9c00cbSConrad Meyer /*! CHECK_ZSTD 57*2b9c00cbSConrad Meyer * Check the zstd error code and die if an error occurred after printing a 58*2b9c00cbSConrad Meyer * message. 59*2b9c00cbSConrad Meyer */ 60*2b9c00cbSConrad Meyer #define CHECK_ZSTD(fn, ...) \ 61*2b9c00cbSConrad Meyer do { \ 62*2b9c00cbSConrad Meyer size_t const err = (fn); \ 63*2b9c00cbSConrad Meyer CHECK(!ZSTD_isError(err), "%s", ZSTD_getErrorName(err)); \ 64*2b9c00cbSConrad Meyer } while (0) 65*2b9c00cbSConrad Meyer 66*2b9c00cbSConrad Meyer /*! fsize_orDie() : 67*2b9c00cbSConrad Meyer * Get the size of a given file path. 68*2b9c00cbSConrad Meyer * 69*2b9c00cbSConrad Meyer * @return The size of a given file path. 70*2b9c00cbSConrad Meyer */ 71*2b9c00cbSConrad Meyer static size_t fsize_orDie(const char *filename) 72*2b9c00cbSConrad Meyer { 73*2b9c00cbSConrad Meyer struct stat st; 74*2b9c00cbSConrad Meyer if (stat(filename, &st) != 0) { 75*2b9c00cbSConrad Meyer /* error */ 76*2b9c00cbSConrad Meyer perror(filename); 77*2b9c00cbSConrad Meyer exit(ERROR_fsize); 78*2b9c00cbSConrad Meyer } 79*2b9c00cbSConrad Meyer 80*2b9c00cbSConrad Meyer off_t const fileSize = st.st_size; 81*2b9c00cbSConrad Meyer size_t const size = (size_t)fileSize; 82*2b9c00cbSConrad Meyer /* 1. fileSize should be non-negative, 83*2b9c00cbSConrad Meyer * 2. if off_t -> size_t type conversion results in discrepancy, 84*2b9c00cbSConrad Meyer * the file size is too large for type size_t. 85*2b9c00cbSConrad Meyer */ 86*2b9c00cbSConrad Meyer if ((fileSize < 0) || (fileSize != (off_t)size)) { 87*2b9c00cbSConrad Meyer fprintf(stderr, "%s : filesize too large \n", filename); 88*2b9c00cbSConrad Meyer exit(ERROR_largeFile); 89*2b9c00cbSConrad Meyer } 90*2b9c00cbSConrad Meyer return size; 91*2b9c00cbSConrad Meyer } 92*2b9c00cbSConrad Meyer 93*2b9c00cbSConrad Meyer /*! fopen_orDie() : 94*2b9c00cbSConrad Meyer * Open a file using given file path and open option. 95*2b9c00cbSConrad Meyer * 96*2b9c00cbSConrad Meyer * @return If successful this function will return a FILE pointer to an 97*2b9c00cbSConrad Meyer * opened file otherwise it sends an error to stderr and exits. 98*2b9c00cbSConrad Meyer */ 99*2b9c00cbSConrad Meyer static FILE* fopen_orDie(const char *filename, const char *instruction) 100*2b9c00cbSConrad Meyer { 101*2b9c00cbSConrad Meyer FILE* const inFile = fopen(filename, instruction); 102*2b9c00cbSConrad Meyer if (inFile) return inFile; 103*2b9c00cbSConrad Meyer /* error */ 104*2b9c00cbSConrad Meyer perror(filename); 105*2b9c00cbSConrad Meyer exit(ERROR_fopen); 106*2b9c00cbSConrad Meyer } 107*2b9c00cbSConrad Meyer 108*2b9c00cbSConrad Meyer /*! fclose_orDie() : 109*2b9c00cbSConrad Meyer * Close an opened file using given FILE pointer. 110*2b9c00cbSConrad Meyer */ 111*2b9c00cbSConrad Meyer static void fclose_orDie(FILE* file) 112*2b9c00cbSConrad Meyer { 113*2b9c00cbSConrad Meyer if (!fclose(file)) { return; }; 114*2b9c00cbSConrad Meyer /* error */ 115*2b9c00cbSConrad Meyer perror("fclose"); 116*2b9c00cbSConrad Meyer exit(ERROR_fclose); 117*2b9c00cbSConrad Meyer } 118*2b9c00cbSConrad Meyer 119*2b9c00cbSConrad Meyer /*! fread_orDie() : 120*2b9c00cbSConrad Meyer * 121*2b9c00cbSConrad Meyer * Read sizeToRead bytes from a given file, storing them at the 122*2b9c00cbSConrad Meyer * location given by buffer. 123*2b9c00cbSConrad Meyer * 124*2b9c00cbSConrad Meyer * @return The number of bytes read. 125*2b9c00cbSConrad Meyer */ 126*2b9c00cbSConrad Meyer static size_t fread_orDie(void* buffer, size_t sizeToRead, FILE* file) 127*2b9c00cbSConrad Meyer { 128*2b9c00cbSConrad Meyer size_t const readSize = fread(buffer, 1, sizeToRead, file); 129*2b9c00cbSConrad Meyer if (readSize == sizeToRead) return readSize; /* good */ 130*2b9c00cbSConrad Meyer if (feof(file)) return readSize; /* good, reached end of file */ 131*2b9c00cbSConrad Meyer /* error */ 132*2b9c00cbSConrad Meyer perror("fread"); 133*2b9c00cbSConrad Meyer exit(ERROR_fread); 134*2b9c00cbSConrad Meyer } 135*2b9c00cbSConrad Meyer 136*2b9c00cbSConrad Meyer /*! fwrite_orDie() : 137*2b9c00cbSConrad Meyer * 138*2b9c00cbSConrad Meyer * Write sizeToWrite bytes to a file pointed to by file, obtaining 139*2b9c00cbSConrad Meyer * them from a location given by buffer. 140*2b9c00cbSConrad Meyer * 141*2b9c00cbSConrad Meyer * Note: This function will send an error to stderr and exit if it 142*2b9c00cbSConrad Meyer * cannot write data to the given file pointer. 143*2b9c00cbSConrad Meyer * 144*2b9c00cbSConrad Meyer * @return The number of bytes written. 145*2b9c00cbSConrad Meyer */ 146*2b9c00cbSConrad Meyer static size_t fwrite_orDie(const void* buffer, size_t sizeToWrite, FILE* file) 147*2b9c00cbSConrad Meyer { 148*2b9c00cbSConrad Meyer size_t const writtenSize = fwrite(buffer, 1, sizeToWrite, file); 149*2b9c00cbSConrad Meyer if (writtenSize == sizeToWrite) return sizeToWrite; /* good */ 150*2b9c00cbSConrad Meyer /* error */ 151*2b9c00cbSConrad Meyer perror("fwrite"); 152*2b9c00cbSConrad Meyer exit(ERROR_fwrite); 153*2b9c00cbSConrad Meyer } 154*2b9c00cbSConrad Meyer 155*2b9c00cbSConrad Meyer /*! malloc_orDie() : 156*2b9c00cbSConrad Meyer * Allocate memory. 157*2b9c00cbSConrad Meyer * 158*2b9c00cbSConrad Meyer * @return If successful this function returns a pointer to allo- 159*2b9c00cbSConrad Meyer * cated memory. If there is an error, this function will send that 160*2b9c00cbSConrad Meyer * error to stderr and exit. 161*2b9c00cbSConrad Meyer */ 162*2b9c00cbSConrad Meyer static void* malloc_orDie(size_t size) 163*2b9c00cbSConrad Meyer { 164*2b9c00cbSConrad Meyer void* const buff = malloc(size); 165*2b9c00cbSConrad Meyer if (buff) return buff; 166*2b9c00cbSConrad Meyer /* error */ 167*2b9c00cbSConrad Meyer perror("malloc"); 168*2b9c00cbSConrad Meyer exit(ERROR_malloc); 169*2b9c00cbSConrad Meyer } 170*2b9c00cbSConrad Meyer 171*2b9c00cbSConrad Meyer /*! loadFile_orDie() : 172*2b9c00cbSConrad Meyer * load file into buffer (memory). 173*2b9c00cbSConrad Meyer * 174*2b9c00cbSConrad Meyer * Note: This function will send an error to stderr and exit if it 175*2b9c00cbSConrad Meyer * cannot read data from the given file path. 176*2b9c00cbSConrad Meyer * 177*2b9c00cbSConrad Meyer * @return If successful this function will load file into buffer and 178*2b9c00cbSConrad Meyer * return file size, otherwise it will printout an error to stderr and exit. 179*2b9c00cbSConrad Meyer */ 180*2b9c00cbSConrad Meyer static size_t loadFile_orDie(const char* fileName, void* buffer, size_t bufferSize) 181*2b9c00cbSConrad Meyer { 182*2b9c00cbSConrad Meyer size_t const fileSize = fsize_orDie(fileName); 183*2b9c00cbSConrad Meyer CHECK(fileSize <= bufferSize, "File too large!"); 184*2b9c00cbSConrad Meyer 185*2b9c00cbSConrad Meyer FILE* const inFile = fopen_orDie(fileName, "rb"); 186*2b9c00cbSConrad Meyer size_t const readSize = fread(buffer, 1, fileSize, inFile); 187*2b9c00cbSConrad Meyer if (readSize != (size_t)fileSize) { 188*2b9c00cbSConrad Meyer fprintf(stderr, "fread: %s : %s \n", fileName, strerror(errno)); 189*2b9c00cbSConrad Meyer exit(ERROR_fread); 190*2b9c00cbSConrad Meyer } 191*2b9c00cbSConrad Meyer fclose(inFile); /* can't fail, read only */ 192*2b9c00cbSConrad Meyer return fileSize; 193*2b9c00cbSConrad Meyer } 194*2b9c00cbSConrad Meyer 195*2b9c00cbSConrad Meyer /*! mallocAndLoadFile_orDie() : 196*2b9c00cbSConrad Meyer * allocate memory buffer and then load file into it. 197*2b9c00cbSConrad Meyer * 198*2b9c00cbSConrad Meyer * Note: This function will send an error to stderr and exit if memory allocation 199*2b9c00cbSConrad Meyer * fails or it cannot read data from the given file path. 200*2b9c00cbSConrad Meyer * 201*2b9c00cbSConrad Meyer * @return If successful this function will return buffer and bufferSize(=fileSize), 202*2b9c00cbSConrad Meyer * otherwise it will printout an error to stderr and exit. 203*2b9c00cbSConrad Meyer */ 204*2b9c00cbSConrad Meyer static void* mallocAndLoadFile_orDie(const char* fileName, size_t* bufferSize) { 205*2b9c00cbSConrad Meyer size_t const fileSize = fsize_orDie(fileName); 206*2b9c00cbSConrad Meyer *bufferSize = fileSize; 207*2b9c00cbSConrad Meyer void* const buffer = malloc_orDie(*bufferSize); 208*2b9c00cbSConrad Meyer loadFile_orDie(fileName, buffer, *bufferSize); 209*2b9c00cbSConrad Meyer return buffer; 210*2b9c00cbSConrad Meyer } 211*2b9c00cbSConrad Meyer 212*2b9c00cbSConrad Meyer /*! saveFile_orDie() : 213*2b9c00cbSConrad Meyer * 214*2b9c00cbSConrad Meyer * Save buffSize bytes to a given file path, obtaining them from a location pointed 215*2b9c00cbSConrad Meyer * to by buff. 216*2b9c00cbSConrad Meyer * 217*2b9c00cbSConrad Meyer * Note: This function will send an error to stderr and exit if it 218*2b9c00cbSConrad Meyer * cannot write to a given file. 219*2b9c00cbSConrad Meyer */ 220*2b9c00cbSConrad Meyer static void saveFile_orDie(const char* fileName, const void* buff, size_t buffSize) 221*2b9c00cbSConrad Meyer { 222*2b9c00cbSConrad Meyer FILE* const oFile = fopen_orDie(fileName, "wb"); 223*2b9c00cbSConrad Meyer size_t const wSize = fwrite(buff, 1, buffSize, oFile); 224*2b9c00cbSConrad Meyer if (wSize != (size_t)buffSize) { 225*2b9c00cbSConrad Meyer fprintf(stderr, "fwrite: %s : %s \n", fileName, strerror(errno)); 226*2b9c00cbSConrad Meyer exit(ERROR_fwrite); 227*2b9c00cbSConrad Meyer } 228*2b9c00cbSConrad Meyer if (fclose(oFile)) { 229*2b9c00cbSConrad Meyer perror(fileName); 230*2b9c00cbSConrad Meyer exit(ERROR_fclose); 231*2b9c00cbSConrad Meyer } 232*2b9c00cbSConrad Meyer } 233*2b9c00cbSConrad Meyer 234*2b9c00cbSConrad Meyer #endif 235