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