fast_excel 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -7
  3. data/CHANGELOG.md +9 -0
  4. data/Gemfile +1 -1
  5. data/examples/example.rb +2 -0
  6. data/examples/example_date_time.rb +38 -0
  7. data/fast_excel.gemspec +2 -2
  8. data/lib/fast_excel/binding/format.rb +17 -0
  9. data/lib/fast_excel/binding/workbook.rb +39 -17
  10. data/lib/fast_excel/binding/worksheet.rb +57 -13
  11. data/lib/fast_excel/binding.rb +7 -7
  12. data/lib/fast_excel.rb +27 -20
  13. data/libxlsxwriter/.github/FUNDING.yml +1 -0
  14. data/libxlsxwriter/.github/ISSUE_TEMPLATE.md +85 -0
  15. data/libxlsxwriter/.github/PULL_REQUEST_TEMPLATE.md +130 -0
  16. data/libxlsxwriter/.github/workflows/cmake_actions.yml +48 -0
  17. data/libxlsxwriter/.github/workflows/code_style.yml +23 -0
  18. data/libxlsxwriter/.github/workflows/coverity.yml +22 -0
  19. data/libxlsxwriter/.github/workflows/make_actions.yml +52 -0
  20. data/libxlsxwriter/.github/workflows/valgrind.yml +23 -0
  21. data/libxlsxwriter/.github/workflows/windows_build.yml +54 -0
  22. data/libxlsxwriter/.github/workflows/zig_build.yml +22 -0
  23. data/libxlsxwriter/.gitignore +16 -1
  24. data/libxlsxwriter/.indent.pro +24 -0
  25. data/libxlsxwriter/CMakeLists.txt +156 -56
  26. data/libxlsxwriter/CONTRIBUTING.md +2 -2
  27. data/libxlsxwriter/Changes.txt +344 -2
  28. data/libxlsxwriter/LICENSE.txt +66 -8
  29. data/libxlsxwriter/Makefile +151 -54
  30. data/libxlsxwriter/Package.swift +42 -0
  31. data/libxlsxwriter/Readme.md +4 -2
  32. data/libxlsxwriter/build.zig +324 -0
  33. data/libxlsxwriter/build.zig.zon +11 -0
  34. data/libxlsxwriter/cmake/FindMINIZIP.cmake +3 -3
  35. data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +6 -0
  36. data/libxlsxwriter/include/xlsxwriter/app.h +2 -1
  37. data/libxlsxwriter/include/xlsxwriter/chart.h +236 -32
  38. data/libxlsxwriter/include/xlsxwriter/chartsheet.h +7 -7
  39. data/libxlsxwriter/include/xlsxwriter/comment.h +76 -0
  40. data/libxlsxwriter/include/xlsxwriter/common.h +111 -50
  41. data/libxlsxwriter/include/xlsxwriter/content_types.h +8 -1
  42. data/libxlsxwriter/include/xlsxwriter/core.h +1 -1
  43. data/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
  44. data/libxlsxwriter/include/xlsxwriter/drawing.h +11 -20
  45. data/libxlsxwriter/include/xlsxwriter/format.h +121 -8
  46. data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
  47. data/libxlsxwriter/include/xlsxwriter/metadata.h +49 -0
  48. data/libxlsxwriter/include/xlsxwriter/packager.h +27 -16
  49. data/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
  50. data/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
  51. data/libxlsxwriter/include/xlsxwriter/styles.h +13 -7
  52. data/libxlsxwriter/include/xlsxwriter/table.h +51 -0
  53. data/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
  54. data/libxlsxwriter/include/xlsxwriter/third_party/emyg_dtoa.h +26 -0
  55. data/libxlsxwriter/include/xlsxwriter/third_party/ioapi.h +27 -25
  56. data/libxlsxwriter/include/xlsxwriter/third_party/md5.h +45 -0
  57. data/libxlsxwriter/include/xlsxwriter/third_party/zip.h +155 -153
  58. data/libxlsxwriter/include/xlsxwriter/utility.h +70 -8
  59. data/libxlsxwriter/include/xlsxwriter/vml.h +55 -0
  60. data/libxlsxwriter/include/xlsxwriter/workbook.h +218 -47
  61. data/libxlsxwriter/include/xlsxwriter/worksheet.h +2770 -241
  62. data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +12 -8
  63. data/libxlsxwriter/include/xlsxwriter.h +4 -2
  64. data/libxlsxwriter/libxlsxwriter.podspec +8 -5
  65. data/libxlsxwriter/src/Makefile +58 -21
  66. data/libxlsxwriter/src/app.c +5 -2
  67. data/libxlsxwriter/src/chart.c +396 -81
  68. data/libxlsxwriter/src/chartsheet.c +22 -22
  69. data/libxlsxwriter/src/comment.c +443 -0
  70. data/libxlsxwriter/src/content_types.c +40 -1
  71. data/libxlsxwriter/src/core.c +2 -2
  72. data/libxlsxwriter/src/custom.c +1 -1
  73. data/libxlsxwriter/src/drawing.c +160 -40
  74. data/libxlsxwriter/src/format.c +109 -25
  75. data/libxlsxwriter/src/hash_table.c +1 -1
  76. data/libxlsxwriter/src/metadata.c +283 -0
  77. data/libxlsxwriter/src/packager.c +794 -94
  78. data/libxlsxwriter/src/relationships.c +1 -1
  79. data/libxlsxwriter/src/shared_strings.c +2 -4
  80. data/libxlsxwriter/src/styles.c +353 -58
  81. data/libxlsxwriter/src/table.c +304 -0
  82. data/libxlsxwriter/src/theme.c +1 -1
  83. data/libxlsxwriter/src/utility.c +143 -43
  84. data/libxlsxwriter/src/vml.c +1062 -0
  85. data/libxlsxwriter/src/workbook.c +567 -77
  86. data/libxlsxwriter/src/worksheet.c +6668 -1462
  87. data/libxlsxwriter/src/xmlwriter.c +95 -5
  88. data/libxlsxwriter/third_party/dtoa/Makefile +42 -0
  89. data/libxlsxwriter/third_party/dtoa/emyg_dtoa.c +461 -0
  90. data/libxlsxwriter/third_party/dtoa/emyg_dtoa.h +26 -0
  91. data/libxlsxwriter/third_party/md5/Makefile +42 -0
  92. data/libxlsxwriter/third_party/md5/md5.c +291 -0
  93. data/libxlsxwriter/third_party/md5/md5.h +45 -0
  94. data/libxlsxwriter/third_party/minizip/Makefile +3 -8
  95. data/libxlsxwriter/third_party/minizip/Makefile.orig +8 -4
  96. data/libxlsxwriter/third_party/minizip/MiniZip64_Changes.txt +1 -1
  97. data/libxlsxwriter/third_party/minizip/configure.ac +1 -1
  98. data/libxlsxwriter/third_party/minizip/crypt.h +13 -16
  99. data/libxlsxwriter/third_party/minizip/ioapi.c +31 -57
  100. data/libxlsxwriter/third_party/minizip/ioapi.h +31 -23
  101. data/libxlsxwriter/third_party/minizip/iowin32.c +29 -45
  102. data/libxlsxwriter/third_party/minizip/iowin32.h +4 -4
  103. data/libxlsxwriter/third_party/minizip/miniunz.c +29 -56
  104. data/libxlsxwriter/third_party/minizip/minizip.c +38 -49
  105. data/libxlsxwriter/third_party/minizip/mztools.c +1 -7
  106. data/libxlsxwriter/third_party/minizip/unzip.c +202 -342
  107. data/libxlsxwriter/third_party/minizip/unzip.h +74 -74
  108. data/libxlsxwriter/third_party/minizip/zip.c +165 -218
  109. data/libxlsxwriter/third_party/minizip/zip.h +164 -154
  110. data/libxlsxwriter/third_party/tmpfileplus/Makefile +3 -3
  111. data/libxlsxwriter/version.txt +1 -1
  112. data/test/auto_width_test.rb +20 -0
  113. data/test/default_format_test.rb +1 -1
  114. data/test/validations_test.rb +3 -3
  115. data/test/worksheet_test.rb +6 -1
  116. metadata +33 -7
  117. data/libxlsxwriter/.travis.yml +0 -37
@@ -0,0 +1,304 @@
1
+ /*****************************************************************************
2
+ * table - A library for creating Excel XLSX table files.
3
+ *
4
+ * Used in conjunction with the libxlsxwriter library.
5
+ *
6
+ * Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
+ *
8
+ */
9
+
10
+ #include "xlsxwriter/xmlwriter.h"
11
+ #include "xlsxwriter/worksheet.h"
12
+ #include "xlsxwriter/table.h"
13
+ #include "xlsxwriter/utility.h"
14
+
15
+ /*
16
+ * Forward declarations.
17
+ */
18
+
19
+ /*****************************************************************************
20
+ *
21
+ * Private functions.
22
+ *
23
+ ****************************************************************************/
24
+
25
+ /*
26
+ * Create a new table object.
27
+ */
28
+ lxw_table *
29
+ lxw_table_new(void)
30
+ {
31
+ lxw_table *table = calloc(1, sizeof(lxw_table));
32
+ GOTO_LABEL_ON_MEM_ERROR(table, mem_error);
33
+
34
+ return table;
35
+
36
+ mem_error:
37
+ lxw_table_free(table);
38
+ return NULL;
39
+ }
40
+
41
+ /*
42
+ * Free a table object.
43
+ */
44
+ void
45
+ lxw_table_free(lxw_table *table)
46
+ {
47
+ if (!table)
48
+ return;
49
+
50
+ free(table);
51
+ }
52
+
53
+ /*****************************************************************************
54
+ *
55
+ * XML functions.
56
+ *
57
+ ****************************************************************************/
58
+
59
+ /*
60
+ * Write the XML declaration.
61
+ */
62
+ STATIC void
63
+ _table_xml_declaration(lxw_table *self)
64
+ {
65
+ lxw_xml_declaration(self->file);
66
+ }
67
+
68
+ /*
69
+ * Write the <table> element.
70
+ */
71
+ STATIC void
72
+ _table_write_table(lxw_table *self)
73
+ {
74
+ struct xml_attribute_list attributes;
75
+ struct xml_attribute *attribute;
76
+ char xmlns[] =
77
+ "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
78
+ lxw_table_obj *table_obj = self->table_obj;
79
+
80
+ LXW_INIT_ATTRIBUTES();
81
+
82
+ LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
83
+ LXW_PUSH_ATTRIBUTES_INT("id", table_obj->id);
84
+
85
+ if (table_obj->name)
86
+ LXW_PUSH_ATTRIBUTES_STR("name", table_obj->name);
87
+ else
88
+ LXW_PUSH_ATTRIBUTES_STR("name", "Table1");
89
+
90
+ if (table_obj->name)
91
+ LXW_PUSH_ATTRIBUTES_STR("displayName", table_obj->name);
92
+ else
93
+ LXW_PUSH_ATTRIBUTES_STR("displayName", "Table1");
94
+
95
+ LXW_PUSH_ATTRIBUTES_STR("ref", table_obj->sqref);
96
+
97
+ if (table_obj->no_header_row)
98
+ LXW_PUSH_ATTRIBUTES_STR("headerRowCount", "0");
99
+
100
+ if (table_obj->total_row)
101
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowCount", "1");
102
+ else
103
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowShown", "0");
104
+
105
+ lxw_xml_start_tag(self->file, "table", &attributes);
106
+
107
+ LXW_FREE_ATTRIBUTES();
108
+ }
109
+
110
+ /*
111
+ * Write the <autoFilter> element.
112
+ */
113
+ STATIC void
114
+ _table_write_auto_filter(lxw_table *self)
115
+ {
116
+ struct xml_attribute_list attributes;
117
+ struct xml_attribute *attribute;
118
+
119
+ if (self->table_obj->no_autofilter)
120
+ return;
121
+
122
+ LXW_INIT_ATTRIBUTES();
123
+ LXW_PUSH_ATTRIBUTES_STR("ref", self->table_obj->filter_sqref);
124
+
125
+ lxw_xml_empty_tag(self->file, "autoFilter", &attributes);
126
+
127
+ LXW_FREE_ATTRIBUTES();
128
+ }
129
+
130
+ /*
131
+ * Write the <tableColumn> element.
132
+ */
133
+ STATIC void
134
+ _table_write_table_column(lxw_table *self, uint16_t id,
135
+ lxw_table_column *column)
136
+ {
137
+ struct xml_attribute_list attributes;
138
+ struct xml_attribute *attribute;
139
+ int32_t dfx_id;
140
+
141
+ LXW_INIT_ATTRIBUTES();
142
+ LXW_PUSH_ATTRIBUTES_INT("id", id);
143
+
144
+ LXW_PUSH_ATTRIBUTES_STR("name", column->header);
145
+
146
+ if (column->total_string) {
147
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowLabel", column->total_string);
148
+ }
149
+ else if (column->total_function) {
150
+ if (column->total_function == LXW_TABLE_FUNCTION_AVERAGE)
151
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "average");
152
+ if (column->total_function == LXW_TABLE_FUNCTION_COUNT_NUMS)
153
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "countNums");
154
+ if (column->total_function == LXW_TABLE_FUNCTION_COUNT)
155
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "count");
156
+ if (column->total_function == LXW_TABLE_FUNCTION_MAX)
157
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "max");
158
+ if (column->total_function == LXW_TABLE_FUNCTION_MIN)
159
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "min");
160
+ if (column->total_function == LXW_TABLE_FUNCTION_STD_DEV)
161
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "stdDev");
162
+ if (column->total_function == LXW_TABLE_FUNCTION_SUM)
163
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "sum");
164
+ if (column->total_function == LXW_TABLE_FUNCTION_VAR)
165
+ LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "var");
166
+ }
167
+
168
+ if (column->format) {
169
+ dfx_id = lxw_format_get_dxf_index(column->format);
170
+ LXW_PUSH_ATTRIBUTES_INT("dataDxfId", dfx_id);
171
+ }
172
+
173
+ if (column->formula) {
174
+ lxw_xml_start_tag(self->file, "tableColumn", &attributes);
175
+ lxw_xml_data_element(self->file, "calculatedColumnFormula",
176
+ column->formula, NULL);
177
+ lxw_xml_end_tag(self->file, "tableColumn");
178
+ }
179
+ else {
180
+ lxw_xml_empty_tag(self->file, "tableColumn", &attributes);
181
+ }
182
+
183
+ LXW_FREE_ATTRIBUTES();
184
+ }
185
+
186
+ /*
187
+ * Write the <tableColumns> element.
188
+ */
189
+ STATIC void
190
+ _table_write_table_columns(lxw_table *self)
191
+ {
192
+ struct xml_attribute_list attributes;
193
+ struct xml_attribute *attribute;
194
+ uint16_t i;
195
+ uint16_t num_cols = self->table_obj->num_cols;
196
+ lxw_table_column **columns = self->table_obj->columns;
197
+
198
+ LXW_INIT_ATTRIBUTES();
199
+ LXW_PUSH_ATTRIBUTES_INT("count", num_cols);
200
+
201
+ lxw_xml_start_tag(self->file, "tableColumns", &attributes);
202
+
203
+ for (i = 0; i < num_cols; i++)
204
+ _table_write_table_column(self, i + 1, columns[i]);
205
+
206
+ lxw_xml_end_tag(self->file, "tableColumns");
207
+
208
+ LXW_FREE_ATTRIBUTES();
209
+ }
210
+
211
+ /*
212
+ * Write the <tableStyleInfo> element.
213
+ */
214
+ STATIC void
215
+ _table_write_table_style_info(lxw_table *self)
216
+ {
217
+ struct xml_attribute_list attributes;
218
+ struct xml_attribute *attribute;
219
+ char name[LXW_ATTR_32];
220
+ lxw_table_obj *table_obj = self->table_obj;
221
+
222
+ LXW_INIT_ATTRIBUTES();
223
+
224
+ if (table_obj->style_type == LXW_TABLE_STYLE_TYPE_LIGHT) {
225
+ if (table_obj->style_type_number != 0) {
226
+ lxw_snprintf(name, LXW_ATTR_32, "TableStyleLight%d",
227
+ table_obj->style_type_number);
228
+ LXW_PUSH_ATTRIBUTES_STR("name", name);
229
+ }
230
+ }
231
+ else if (table_obj->style_type == LXW_TABLE_STYLE_TYPE_MEDIUM) {
232
+ lxw_snprintf(name, LXW_ATTR_32, "TableStyleMedium%d",
233
+ table_obj->style_type_number);
234
+ LXW_PUSH_ATTRIBUTES_STR("name", name);
235
+ }
236
+ else if (table_obj->style_type == LXW_TABLE_STYLE_TYPE_DARK) {
237
+ lxw_snprintf(name, LXW_ATTR_32, "TableStyleDark%d",
238
+ table_obj->style_type_number);
239
+ LXW_PUSH_ATTRIBUTES_STR("name", name);
240
+ }
241
+ else {
242
+ LXW_PUSH_ATTRIBUTES_STR("name", "TableStyleMedium9");
243
+ }
244
+
245
+ if (table_obj->first_column)
246
+ LXW_PUSH_ATTRIBUTES_STR("showFirstColumn", "1");
247
+ else
248
+ LXW_PUSH_ATTRIBUTES_STR("showFirstColumn", "0");
249
+
250
+ if (table_obj->last_column)
251
+ LXW_PUSH_ATTRIBUTES_STR("showLastColumn", "1");
252
+ else
253
+ LXW_PUSH_ATTRIBUTES_STR("showLastColumn", "0");
254
+
255
+ if (table_obj->no_banded_rows)
256
+ LXW_PUSH_ATTRIBUTES_STR("showRowStripes", "0");
257
+ else
258
+ LXW_PUSH_ATTRIBUTES_STR("showRowStripes", "1");
259
+
260
+ if (table_obj->banded_columns)
261
+ LXW_PUSH_ATTRIBUTES_STR("showColumnStripes", "1");
262
+ else
263
+ LXW_PUSH_ATTRIBUTES_STR("showColumnStripes", "0");
264
+
265
+ lxw_xml_empty_tag(self->file, "tableStyleInfo", &attributes);
266
+
267
+ LXW_FREE_ATTRIBUTES();
268
+ }
269
+
270
+ /*****************************************************************************
271
+ *
272
+ * XML file assembly functions.
273
+ *
274
+ ****************************************************************************/
275
+
276
+ /*
277
+ * Assemble and write the XML file.
278
+ */
279
+ void
280
+ lxw_table_assemble_xml_file(lxw_table *self)
281
+ {
282
+ /* Write the XML declaration. */
283
+ _table_xml_declaration(self);
284
+
285
+ /* Write the table element. */
286
+ _table_write_table(self);
287
+
288
+ /* Write the autoFilter element. */
289
+ _table_write_auto_filter(self);
290
+
291
+ /* Write the tableColumns element. */
292
+ _table_write_table_columns(self);
293
+
294
+ /* Write the tableStyleInfo element. */
295
+ _table_write_table_style_info(self);
296
+
297
+ lxw_xml_end_tag(self->file, "table");
298
+ }
299
+
300
+ /*****************************************************************************
301
+ *
302
+ * Public functions.
303
+ *
304
+ ****************************************************************************/
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
7
  *
8
8
  */
9
9
 
@@ -3,18 +3,27 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
7
  *
8
8
  */
9
9
 
10
+ #ifdef USE_FMEMOPEN
11
+ #define _POSIX_C_SOURCE 200809L
12
+ #endif
13
+
10
14
  #include <ctype.h>
11
15
  #include <stdio.h>
12
16
  #include <string.h>
13
17
  #include <stdint.h>
14
18
  #include <stdlib.h>
15
19
  #include "xlsxwriter.h"
20
+ #include "xlsxwriter/common.h"
16
21
  #include "xlsxwriter/third_party/tmpfileplus.h"
17
22
 
23
+ #ifdef USE_DTOA_LIBRARY
24
+ #include "xlsxwriter/third_party/emyg_dtoa.h"
25
+ #endif
26
+
18
27
  char *error_strings[LXW_MAX_ERRNO + 1] = {
19
28
  "No error.",
20
29
  "Memory error, failed to malloc() required memory.",
@@ -27,19 +36,20 @@ char *error_strings[LXW_MAX_ERRNO + 1] = {
27
36
  "Zip error ZIP_INTERNALERROR while creating the xlsx file.",
28
37
  "File error or unknown zip error when adding sub file to xlsx file.",
29
38
  "Unknown zip error when closing xlsx file.",
39
+ "Feature is not currently supported in this configuration.",
30
40
  "NULL function parameter ignored.",
31
41
  "Function parameter validation error.",
32
42
  "Worksheet name exceeds Excel's limit of 31 characters.",
33
43
  "Worksheet name cannot contain invalid characters: '[ ] : * ? / \\'",
34
44
  "Worksheet name cannot start or end with an apostrophe.",
35
45
  "Worksheet name is already in use.",
36
- "Worksheet name 'History' is reserved by Excel.",
37
46
  "Parameter exceeds Excel's limit of 32 characters.",
38
47
  "Parameter exceeds Excel's limit of 128 characters.",
39
48
  "Parameter exceeds Excel's limit of 255 characters.",
40
49
  "String exceeds Excel's limit of 32,767 characters.",
41
50
  "Error finding internal string index.",
42
51
  "Worksheet row or column index out of range.",
52
+ "Maximum hyperlink length (2079) exceeded.",
43
53
  "Maximum number of worksheet URLs (65530) exceeded.",
44
54
  "Couldn't read image dimensions or DPI.",
45
55
  "Unknown error number."
@@ -62,7 +72,7 @@ lxw_col_to_name(char *col_name, lxw_col_t col_num, uint8_t absolute)
62
72
  {
63
73
  uint8_t pos = 0;
64
74
  size_t len;
65
- uint8_t i;
75
+ size_t i;
66
76
 
67
77
  /* Change from 0 index to 1 index. */
68
78
  col_num++;
@@ -312,10 +322,11 @@ lxw_name_to_col_2(const char *col_str)
312
322
  }
313
323
 
314
324
  /*
315
- * Convert a lxw_datetime struct to an Excel serial date.
325
+ * Convert a lxw_datetime struct to an Excel serial date, with a 1900
326
+ * or 1904 epoch.
316
327
  */
317
328
  double
318
- lxw_datetime_to_excel_date(lxw_datetime *datetime, uint8_t date_1904)
329
+ lxw_datetime_to_excel_date_epoch(lxw_datetime *datetime, uint8_t date_1904)
319
330
  {
320
331
  int year = datetime->year;
321
332
  int month = datetime->month;
@@ -392,7 +403,7 @@ lxw_datetime_to_excel_date(lxw_datetime *datetime, uint8_t date_1904)
392
403
  /* Add days for all previous years. */
393
404
  days += range * 365;
394
405
  /* Add 4 year leapdays. */
395
- days += (range) / 4;
406
+ days += range / 4;
396
407
  /* Remove 100 year leapdays. */
397
408
  days -= (range + offset) / 100;
398
409
  /* Add 400 year leapdays. */
@@ -407,6 +418,43 @@ lxw_datetime_to_excel_date(lxw_datetime *datetime, uint8_t date_1904)
407
418
  return days + seconds;
408
419
  }
409
420
 
421
+ /*
422
+ * Convert a lxw_datetime struct to an Excel serial date, for the 1900 epoch.
423
+ */
424
+ double
425
+ lxw_datetime_to_excel_datetime(lxw_datetime *datetime)
426
+ {
427
+ return lxw_datetime_to_excel_date_epoch(datetime, LXW_FALSE);
428
+ }
429
+
430
+ /*
431
+ * Convert a unix datetime (1970/01/01 epoch) to an Excel serial date, with a
432
+ * 1900 epoch.
433
+ */
434
+ double
435
+ lxw_unixtime_to_excel_date(int64_t unixtime)
436
+ {
437
+ return lxw_unixtime_to_excel_date_epoch(unixtime, LXW_FALSE);
438
+ }
439
+
440
+ /*
441
+ * Convert a unix datetime (1970/01/01 epoch) to an Excel serial date, with a
442
+ * 1900 or 1904 epoch.
443
+ */
444
+ double
445
+ lxw_unixtime_to_excel_date_epoch(int64_t unixtime, uint8_t date_1904)
446
+ {
447
+ double excel_datetime = 0.0;
448
+ double epoch = date_1904 ? 24107.0 : 25568.0;
449
+
450
+ excel_datetime = epoch + (unixtime / (24 * 60 * 60.0));
451
+
452
+ if (!date_1904 && excel_datetime >= 60.0)
453
+ excel_datetime = excel_datetime + 1.0;
454
+
455
+ return excel_datetime;
456
+ }
457
+
410
458
  /* Simple strdup() implementation since it isn't ANSI C. */
411
459
  char *
412
460
  lxw_strdup(const char *str)
@@ -524,7 +572,7 @@ lxw_quote_sheetname(const char *str)
524
572
  * version if required for safety or portability.
525
573
  */
526
574
  FILE *
527
- lxw_tmpfile(char *tmpdir)
575
+ lxw_tmpfile(const char *tmpdir)
528
576
  {
529
577
  #ifndef USE_STANDARD_TMPFILE
530
578
  return tmpfileplus(tmpdir, NULL, NULL, 0);
@@ -534,34 +582,40 @@ lxw_tmpfile(char *tmpdir)
534
582
  #endif
535
583
  }
536
584
 
585
+ /**
586
+ * Return a memory-backed file if supported, otherwise a temporary one
587
+ */
588
+ FILE *
589
+ lxw_get_filehandle(char **buf, size_t *size, const char *tmpdir)
590
+ {
591
+ static size_t s;
592
+ if (!size)
593
+ size = &s;
594
+ *buf = NULL;
595
+ *size = 0;
596
+ #ifdef USE_FMEMOPEN
597
+ (void) tmpdir;
598
+ return open_memstream(buf, size);
599
+ #else
600
+ return lxw_tmpfile(tmpdir);
601
+ #endif
602
+ }
603
+
537
604
  /*
538
- * Sample function to handle sprintf of doubles for locale portable code. This
539
- * is usually handled by a lxw_sprintf_dbl() macro but it can be replaced with
540
- * a function of the same name.
541
- *
542
- * The code below is a simplified example that changes numbers like 123,45 to
543
- * 123.45. End-users can replace this with something more rigorous if
544
- * required.
605
+ * Use third party function to handle sprintf of doubles for locale portable
606
+ * code.
545
607
  */
546
- #ifdef USE_DOUBLE_FUNCTION
608
+ #ifdef USE_DTOA_LIBRARY
547
609
  int
548
610
  lxw_sprintf_dbl(char *data, double number)
549
611
  {
550
- char *tmp;
551
-
552
- lxw_snprintf(data, LXW_ATTR_32, "%.16g", number);
553
-
554
- /* Replace comma with decimal point. */
555
- tmp = strchr(data, ',');
556
- if (tmp)
557
- *tmp = '.';
558
-
612
+ emyg_dtoa(number, data);
559
613
  return 0;
560
614
  }
561
615
  #endif
562
616
 
563
617
  /*
564
- * Retrieve runtime library version
618
+ * Retrieve runtime library version.
565
619
  */
566
620
  const char *
567
621
  lxw_version(void)
@@ -570,33 +624,79 @@ lxw_version(void)
570
624
  }
571
625
 
572
626
  /*
573
- * Hash a worksheet password. Based on the algorithm provided by Daniel Rentz
574
- * of OpenOffice.
627
+ * Retrieve runtime library version ID.
575
628
  */
576
629
  uint16_t
577
- lxw_hash_password(const char *password)
630
+ lxw_version_id(void)
578
631
  {
579
- size_t count;
580
- uint8_t i;
581
- uint16_t hash = 0x0000;
582
-
583
- count = strlen(password);
632
+ return LXW_VERSION_ID;
633
+ }
584
634
 
585
- for (i = 0; i < count; i++) {
586
- uint32_t low_15;
587
- uint32_t high_15;
588
- uint32_t letter = password[i] << (i + 1);
635
+ /*
636
+ * Hash a worksheet password. Based on the algorithm in ECMA-376-4:2016,
637
+ * Office Open XML File Formats - Transitional Migration Features,
638
+ * Additional attributes for workbookProtection element (Part 1, §18.2.29).
639
+ */
640
+ uint16_t
641
+ lxw_hash_password(const char *password)
642
+ {
643
+ uint16_t byte_count = (uint16_t) strlen(password);
644
+ uint16_t hash = 0;
645
+ const char *p = &password[byte_count];
589
646
 
590
- low_15 = letter & 0x7fff;
591
- high_15 = letter & (0x7fff << 15);
592
- high_15 = high_15 >> 15;
593
- letter = low_15 | high_15;
647
+ if (!byte_count)
648
+ return hash;
594
649
 
595
- hash ^= letter;
650
+ while (p-- != password) {
651
+ hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
652
+ hash ^= *p & 0xFF;
596
653
  }
597
654
 
598
- hash ^= count;
655
+ hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
656
+ hash ^= byte_count;
599
657
  hash ^= 0xCE4B;
600
658
 
601
659
  return hash;
602
660
  }
661
+
662
+ /* Make a simple portable version of fopen() for Windows. */
663
+ #ifdef __MINGW32__
664
+ #undef _WIN32
665
+ #endif
666
+
667
+ #ifdef _WIN32
668
+
669
+ #include <windows.h>
670
+
671
+ FILE *
672
+ lxw_fopen(const char *filename, const char *mode)
673
+ {
674
+ int n;
675
+ wchar_t wide_filename[_MAX_PATH + 1] = L"";
676
+ wchar_t wide_mode[_MAX_PATH + 1] = L"";
677
+
678
+ n = MultiByteToWideChar(CP_UTF8, 0, filename, (int) strlen(filename),
679
+ wide_filename, _MAX_PATH);
680
+
681
+ if (n == 0) {
682
+ LXW_ERROR("MultiByteToWideChar error: filename");
683
+ return NULL;
684
+ }
685
+
686
+ n = MultiByteToWideChar(CP_UTF8, 0, mode, (int) strlen(mode),
687
+ wide_mode, _MAX_PATH);
688
+
689
+ if (n == 0) {
690
+ LXW_ERROR("MultiByteToWideChar error: mode");
691
+ return NULL;
692
+ }
693
+
694
+ return _wfopen(wide_filename, wide_mode);
695
+ }
696
+ #else
697
+ FILE *
698
+ lxw_fopen(const char *filename, const char *mode)
699
+ {
700
+ return fopen(filename, mode);
701
+ }
702
+ #endif