1 /*
2  * libxlsxwriter
3  *
4  * Copyright 2014-2021, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
5  */
6 
7 /**
8  * @file common.h
9  *
10  * @brief Common functions and defines for the libxlsxwriter library.
11  *
12  * <!-- Copyright 2014-2021, John McNamara, jmcnamara@cpan.org -->
13  *
14  */
15 #ifndef __LXW_COMMON_H__
16 #define __LXW_COMMON_H__
17 
18 #include <time.h>
19 #include "third_party/queue.h"
20 #include "third_party/tree.h"
21 
22 #ifndef TESTING
23 #define STATIC static
24 #else
25 #define STATIC
26 #endif
27 
28 #if __GNUC__ >= 5
29 #define DEPRECATED(func, msg) func __attribute__ ((deprecated(msg)))
30 #elif defined(_MSC_VER)
31 #define DEPRECATED(func, msg) __declspec(deprecated, msg) func
32 #else
33 #define DEPRECATED(func, msg) func
34 #endif
35 
36 /** Integer data type to represent a row value. Equivalent to `uint32_t`.
37  *
38  * The maximum row in Excel is 1,048,576.
39  */
40 typedef uint32_t lxw_row_t;
41 
42 /** Integer data type to represent a column value. Equivalent to `uint16_t`.
43  *
44  * The maximum column in Excel is 16,384.
45  */
46 typedef uint16_t lxw_col_t;
47 
48 /** Boolean values used in libxlsxwriter. */
49 enum lxw_boolean {
50     /** False value. */
51     LXW_FALSE,
52     /** True value. */
53     LXW_TRUE,
54     /** False value. Used to turn off a property that is default on, in order
55      *  to distinguish it from an uninitialized value. */
56     LXW_EXPLICIT_FALSE
57 };
58 
59 /**
60  * @brief Error codes from libxlsxwriter functions.
61  *
62  * See the `lxw_strerror()` function for an example of how to convert the
63  * enum number to a descriptive error message string.
64  */
65 typedef enum lxw_error {
66 
67     /** No error. */
68     LXW_NO_ERROR = 0,
69 
70     /** Memory error, failed to malloc() required memory. */
71     LXW_ERROR_MEMORY_MALLOC_FAILED,
72 
73     /** Error creating output xlsx file. Usually a permissions error. */
74     LXW_ERROR_CREATING_XLSX_FILE,
75 
76     /** Error encountered when creating a tmpfile during file assembly. */
77     LXW_ERROR_CREATING_TMPFILE,
78 
79     /** Error reading a tmpfile. */
80     LXW_ERROR_READING_TMPFILE,
81 
82     /** Zip generic error ZIP_ERRNO while creating the xlsx file. */
83     LXW_ERROR_ZIP_FILE_OPERATION,
84 
85     /** Zip error ZIP_PARAMERROR while creating the xlsx file. */
86     LXW_ERROR_ZIP_PARAMETER_ERROR,
87 
88     /** Zip error ZIP_BADZIPFILE (use_zip64 option may be required). */
89     LXW_ERROR_ZIP_BAD_ZIP_FILE,
90 
91     /** Zip error ZIP_INTERNALERROR while creating the xlsx file. */
92     LXW_ERROR_ZIP_INTERNAL_ERROR,
93 
94     /** File error or unknown zip error when adding sub file to xlsx file. */
95     LXW_ERROR_ZIP_FILE_ADD,
96 
97     /** Unknown zip error when closing xlsx file. */
98     LXW_ERROR_ZIP_CLOSE,
99 
100     /** Feature is not currently supported in this configuration. */
101     LXW_ERROR_FEATURE_NOT_SUPPORTED,
102 
103     /** NULL function parameter ignored. */
104     LXW_ERROR_NULL_PARAMETER_IGNORED,
105 
106     /** Function parameter validation error. */
107     LXW_ERROR_PARAMETER_VALIDATION,
108 
109     /** Worksheet name exceeds Excel's limit of 31 characters. */
110     LXW_ERROR_SHEETNAME_LENGTH_EXCEEDED,
111 
112     /** Worksheet name cannot contain invalid characters: '[ ] : * ? / \\' */
113     LXW_ERROR_INVALID_SHEETNAME_CHARACTER,
114 
115     /** Worksheet name cannot start or end with an apostrophe. */
116     LXW_ERROR_SHEETNAME_START_END_APOSTROPHE,
117 
118     /** Worksheet name is already in use. */
119     LXW_ERROR_SHEETNAME_ALREADY_USED,
120 
121     /** Parameter exceeds Excel's limit of 32 characters. */
122     LXW_ERROR_32_STRING_LENGTH_EXCEEDED,
123 
124     /** Parameter exceeds Excel's limit of 128 characters. */
125     LXW_ERROR_128_STRING_LENGTH_EXCEEDED,
126 
127     /** Parameter exceeds Excel's limit of 255 characters. */
128     LXW_ERROR_255_STRING_LENGTH_EXCEEDED,
129 
130     /** String exceeds Excel's limit of 32,767 characters. */
131     LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED,
132 
133     /** Error finding internal string index. */
134     LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND,
135 
136     /** Worksheet row or column index out of range. */
137     LXW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE,
138 
139     /** Maximum hyperlink length (2079) exceeded. */
140     LXW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED,
141 
142     /** Maximum number of worksheet URLs (65530) exceeded. */
143     LXW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED,
144 
145     /** Couldn't read image dimensions or DPI. */
146     LXW_ERROR_IMAGE_DIMENSIONS,
147 
148     LXW_MAX_ERRNO
149 } lxw_error;
150 
151 /** @brief Struct to represent a date and time in Excel.
152  *
153  * Struct to represent a date and time in Excel. See @ref working_with_dates.
154  */
155 typedef struct lxw_datetime {
156 
157     /** Year     : 1900 - 9999 */
158     int year;
159     /** Month    : 1 - 12 */
160     int month;
161     /** Day      : 1 - 31 */
162     int day;
163     /** Hour     : 0 - 23 */
164     int hour;
165     /** Minute   : 0 - 59 */
166     int min;
167     /** Seconds  : 0 - 59.999 */
168     double sec;
169 
170 } lxw_datetime;
171 
172 enum lxw_custom_property_types {
173     LXW_CUSTOM_NONE,
174     LXW_CUSTOM_STRING,
175     LXW_CUSTOM_DOUBLE,
176     LXW_CUSTOM_INTEGER,
177     LXW_CUSTOM_BOOLEAN,
178     LXW_CUSTOM_DATETIME
179 };
180 
181 /* Size of MD5 byte arrays. */
182 #define LXW_MD5_SIZE              16
183 
184 /* Excel sheetname max of 31 chars. */
185 #define LXW_SHEETNAME_MAX         31
186 
187 /* Max with all worksheet chars 4xUTF-8 bytes + start and end quotes + \0. */
188 #define LXW_MAX_SHEETNAME_LENGTH  ((LXW_SHEETNAME_MAX * 4) + 2 + 1)
189 
190 /* Max col string length. */
191 #define LXW_MAX_COL_NAME_LENGTH   sizeof("$XFD")
192 
193 /* Max row string length. */
194 #define LXW_MAX_ROW_NAME_LENGTH   sizeof("$1048576")
195 
196 /* Max cell string length. */
197 #define LXW_MAX_CELL_NAME_LENGTH  sizeof("$XFWD$1048576")
198 
199 /* Max range: $XFWD$1048576:$XFWD$1048576\0 */
200 #define LXW_MAX_CELL_RANGE_LENGTH (LXW_MAX_CELL_NAME_LENGTH * 2)
201 
202 /* Max range formula Sheet1!$A$1:$C$5$ style. */
203 #define LXW_MAX_FORMULA_RANGE_LENGTH (LXW_MAX_SHEETNAME_LENGTH + LXW_MAX_CELL_RANGE_LENGTH)
204 
205 /* Datetime string length. */
206 #define LXW_DATETIME_LENGTH       sizeof("2016-12-12T23:00:00Z")
207 
208 /* GUID string length. */
209 #define LXW_GUID_LENGTH           sizeof("{12345678-1234-1234-1234-1234567890AB}\0")
210 
211 #define LXW_EPOCH_1900            0
212 #define LXW_EPOCH_1904            1
213 
214 #define LXW_UINT32_T_LENGTH       sizeof("4294967296")
215 #define LXW_FILENAME_LENGTH       128
216 #define LXW_IGNORE                1
217 
218 #define LXW_PORTRAIT              1
219 #define LXW_LANDSCAPE             0
220 
221 #define LXW_SCHEMA_MS        "http://schemas.microsoft.com/office/2006/relationships"
222 #define LXW_SCHEMA_ROOT      "http://schemas.openxmlformats.org"
223 #define LXW_SCHEMA_DRAWING   LXW_SCHEMA_ROOT "/drawingml/2006"
224 #define LXW_SCHEMA_OFFICEDOC LXW_SCHEMA_ROOT "/officeDocument/2006"
225 #define LXW_SCHEMA_PACKAGE   LXW_SCHEMA_ROOT "/package/2006/relationships"
226 #define LXW_SCHEMA_DOCUMENT  LXW_SCHEMA_ROOT "/officeDocument/2006/relationships"
227 #define LXW_SCHEMA_CONTENT   LXW_SCHEMA_ROOT "/package/2006/content-types"
228 
229 /* Use REprintf() for error handling when compiled as an R library. */
230 #ifdef USE_R_LANG
231 #include <R.h>
232 #define LXW_PRINTF REprintf
233 #define LXW_STDERR
234 #else
235 #define LXW_PRINTF fprintf
236 #define LXW_STDERR stderr,
237 #endif
238 
239 #define LXW_ERROR(message)                      \
240     LXW_PRINTF(LXW_STDERR "[ERROR][%s:%d]: " message "\n", __FILE__, __LINE__)
241 
242 #define LXW_MEM_ERROR()                         \
243     LXW_ERROR("Memory allocation failed.")
244 
245 #define GOTO_LABEL_ON_MEM_ERROR(pointer, label) \
246     do {                                        \
247         if (!pointer) {                         \
248             LXW_MEM_ERROR();                    \
249             goto label;                         \
250         }                                       \
251     } while (0)
252 
253 #define RETURN_ON_MEM_ERROR(pointer, error)     \
254     do {                                        \
255         if (!pointer) {                         \
256             LXW_MEM_ERROR();                    \
257             return error;                       \
258         }                                       \
259     } while (0)
260 
261 #define RETURN_VOID_ON_MEM_ERROR(pointer)       \
262     do {                                        \
263         if (!pointer) {                         \
264             LXW_MEM_ERROR();                    \
265             return;                             \
266         }                                       \
267     } while (0)
268 
269 #define RETURN_ON_ERROR(error)                  \
270     do {                                        \
271         if (error)                              \
272             return error;                       \
273     } while (0)
274 
275 #define RETURN_AND_ZIPCLOSE_ON_ERROR(error)     \
276         do {                                    \
277             if (error) {                        \
278                 zipClose(self->zipfile, NULL);  \
279                 return error;                   \
280             }                                   \
281         } while (0)
282 
283 #define LXW_WARN(message)                       \
284     LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n")
285 
286 /* We can't use variadic macros here since we support ANSI C. */
287 #define LXW_WARN_FORMAT(message)                \
288     LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n")
289 
290 #define LXW_WARN_FORMAT1(message, var)          \
291     LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n", var)
292 
293 #define LXW_WARN_FORMAT2(message, var1, var2)    \
294     LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n", var1, var2)
295 
296 #define LXW_WARN_FORMAT3(message, var1, var2, var3) \
297     LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n", var1, var2, var3)
298 
299 /* Chart axis type checks. */
300 #define LXW_WARN_CAT_AXIS_ONLY(function)                                   \
301     do {                                                                   \
302         if (!axis->is_category) {                                          \
303             LXW_PRINTF(LXW_STDERR "[WARNING]: "                            \
304                     function "() is only valid for category axes\n");      \
305            return;                                                         \
306         }                                                                  \
307     } while (0)
308 
309 #define LXW_WARN_VALUE_AXIS_ONLY(function)                                 \
310     do {                                                                   \
311         if (!axis->is_value) {                                             \
312             LXW_PRINTF(LXW_STDERR "[WARNING]: "                            \
313                 function "() is only valid for value axes\n");             \
314                 return;                                                    \
315         }                                                                  \
316     } while (0)
317 
318 #define LXW_WARN_DATE_AXIS_ONLY(function)                                  \
319     do {                                                                   \
320         if (!axis->is_date) {                                              \
321             LXW_PRINTF(LXW_STDERR "[WARNING]: "                            \
322                     function "() is only valid for date axes\n");          \
323            return;                                                         \
324         }                                                                  \
325     } while (0)
326 
327 #define LXW_WARN_CAT_AND_DATE_AXIS_ONLY(function)                          \
328     do {                                                                   \
329         if (!axis->is_category && !axis->is_date) {                        \
330             LXW_PRINTF(LXW_STDERR "[WARNING]: "                            \
331                 function "() is only valid for category and date axes\n"); \
332            return;                                                         \
333         }                                                                  \
334     } while (0)
335 
336 #define LXW_WARN_VALUE_AND_DATE_AXIS_ONLY(function)                        \
337     do {                                                                   \
338         if (!axis->is_value && !axis->is_date) {                           \
339             LXW_PRINTF(LXW_STDERR "[WARNING]: "                            \
340                 function "() is only valid for value and date axes\n");    \
341             return;                                                        \
342         }                                                                  \
343     } while (0)
344 
345 #ifndef LXW_BIG_ENDIAN
346 #define LXW_UINT16_HOST(n)    (n)
347 #define LXW_UINT32_HOST(n)    (n)
348 #define LXW_UINT16_NETWORK(n) ((((n) & 0x00FF) << 8) | (((n) & 0xFF00) >> 8))
349 #define LXW_UINT32_NETWORK(n) ((((n) & 0xFF)       << 24) | \
350                                (((n) & 0xFF00)     <<  8) | \
351                                (((n) & 0xFF0000)   >>  8) | \
352                                (((n) & 0xFF000000) >> 24))
353 #else
354 #define LXW_UINT16_NETWORK(n) (n)
355 #define LXW_UINT32_NETWORK(n) (n)
356 #define LXW_UINT16_HOST(n)    ((((n) & 0x00FF) << 8) | (((n) & 0xFF00) >> 8))
357 #define LXW_UINT32_HOST(n)    ((((n) & 0xFF)       << 24) | \
358                                (((n) & 0xFF00)     <<  8) | \
359                                (((n) & 0xFF0000)   >>  8) | \
360                                (((n) & 0xFF000000) >> 24))
361 #endif
362 
363 /* *INDENT-OFF* */
364 #ifdef __cplusplus
365 extern "C" {
366 #endif
367 /* *INDENT-ON* */
368 
369 /* Compilers that have a native snprintf() can use it directly. */
370 #ifdef _MSC_VER
371 #define LXW_HAS_SNPRINTF
372 #endif
373 
374 #ifdef LXW_HAS_SNPRINTF
375 #define lxw_snprintf snprintf
376 #else
377 #define lxw_snprintf __builtin_snprintf
378 #endif
379 
380 /* Define a snprintf for MSVC 2010. */
381 #if defined(_MSC_VER) && _MSC_VER < 1900
382 
383 #include <stdarg.h>
384 #define snprintf msvc2010_snprintf
385 #define vsnprintf msvc2010_vsnprintf
386 
387 __inline int
msvc2010_vsnprintf(char * str,size_t size,const char * format,va_list ap)388 msvc2010_vsnprintf(char *str, size_t size, const char *format, va_list ap)
389 {
390     int count = -1;
391 
392     if (size != 0)
393         count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
394     if (count == -1)
395         count = _vscprintf(format, ap);
396 
397     return count;
398 }
399 
400 __inline int
msvc2010_snprintf(char * str,size_t size,const char * format,...)401 msvc2010_snprintf(char *str, size_t size, const char *format, ...)
402 {
403     int count;
404     va_list ap;
405 
406     va_start(ap, format);
407     count = msvc2010_vsnprintf(str, size, format, ap);
408     va_end(ap);
409 
410     return count;
411 }
412 
413 #endif
414 
415 /* Safer strcpy for fixed width char arrays. */
416 #define lxw_strcpy(dest, src) \
417     lxw_snprintf(dest, sizeof(dest), "%s", src)
418 
419 /* Define the queue.h structs for the formats list. */
420 STAILQ_HEAD(lxw_formats, lxw_format);
421 
422 /* Define the queue.h structs for the generic data structs. */
423 STAILQ_HEAD(lxw_tuples, lxw_tuple);
424 STAILQ_HEAD(lxw_custom_properties, lxw_custom_property);
425 
426 typedef struct lxw_tuple {
427     char *key;
428     char *value;
429 
430     STAILQ_ENTRY (lxw_tuple) list_pointers;
431 } lxw_tuple;
432 
433 /* Define custom property used in workbook.c and custom.c. */
434 typedef struct lxw_custom_property {
435 
436     enum lxw_custom_property_types type;
437     char *name;
438 
439     union {
440         char *string;
441         double number;
442         int32_t integer;
443         uint8_t boolean;
444         lxw_datetime datetime;
445     } u;
446 
447     STAILQ_ENTRY (lxw_custom_property) list_pointers;
448 
449 } lxw_custom_property;
450 
451 /* Declarations required for unit testing. */
452 #ifdef TESTING
453 
454 #endif /* TESTING */
455 
456 /* *INDENT-OFF* */
457 #ifdef __cplusplus
458 }
459 #endif
460 /* *INDENT-ON* */
461 
462 #endif /* __LXW_COMMON_H__ */
463