fast_excel 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -7
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -1
- data/examples/example.rb +2 -0
- data/examples/example_date_time.rb +38 -0
- data/fast_excel.gemspec +2 -2
- data/lib/fast_excel/binding/format.rb +17 -0
- data/lib/fast_excel/binding/workbook.rb +39 -17
- data/lib/fast_excel/binding/worksheet.rb +57 -13
- data/lib/fast_excel/binding.rb +7 -7
- data/lib/fast_excel.rb +27 -20
- data/libxlsxwriter/.github/FUNDING.yml +1 -0
- data/libxlsxwriter/.github/ISSUE_TEMPLATE.md +85 -0
- data/libxlsxwriter/.github/PULL_REQUEST_TEMPLATE.md +130 -0
- data/libxlsxwriter/.github/workflows/cmake_actions.yml +48 -0
- data/libxlsxwriter/.github/workflows/code_style.yml +23 -0
- data/libxlsxwriter/.github/workflows/coverity.yml +22 -0
- data/libxlsxwriter/.github/workflows/make_actions.yml +52 -0
- data/libxlsxwriter/.github/workflows/valgrind.yml +23 -0
- data/libxlsxwriter/.github/workflows/windows_build.yml +54 -0
- data/libxlsxwriter/.github/workflows/zig_build.yml +22 -0
- data/libxlsxwriter/.gitignore +16 -1
- data/libxlsxwriter/.indent.pro +24 -0
- data/libxlsxwriter/CMakeLists.txt +156 -56
- data/libxlsxwriter/CONTRIBUTING.md +2 -2
- data/libxlsxwriter/Changes.txt +344 -2
- data/libxlsxwriter/LICENSE.txt +66 -8
- data/libxlsxwriter/Makefile +151 -54
- data/libxlsxwriter/Package.swift +42 -0
- data/libxlsxwriter/Readme.md +4 -2
- data/libxlsxwriter/build.zig +324 -0
- data/libxlsxwriter/build.zig.zon +11 -0
- data/libxlsxwriter/cmake/FindMINIZIP.cmake +3 -3
- data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +6 -0
- data/libxlsxwriter/include/xlsxwriter/app.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/chart.h +236 -32
- data/libxlsxwriter/include/xlsxwriter/chartsheet.h +7 -7
- data/libxlsxwriter/include/xlsxwriter/comment.h +76 -0
- data/libxlsxwriter/include/xlsxwriter/common.h +111 -50
- data/libxlsxwriter/include/xlsxwriter/content_types.h +8 -1
- data/libxlsxwriter/include/xlsxwriter/core.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/drawing.h +11 -20
- data/libxlsxwriter/include/xlsxwriter/format.h +121 -8
- data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/metadata.h +49 -0
- data/libxlsxwriter/include/xlsxwriter/packager.h +27 -16
- data/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/styles.h +13 -7
- data/libxlsxwriter/include/xlsxwriter/table.h +51 -0
- data/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/third_party/emyg_dtoa.h +26 -0
- data/libxlsxwriter/include/xlsxwriter/third_party/ioapi.h +27 -25
- data/libxlsxwriter/include/xlsxwriter/third_party/md5.h +45 -0
- data/libxlsxwriter/include/xlsxwriter/third_party/zip.h +155 -153
- data/libxlsxwriter/include/xlsxwriter/utility.h +70 -8
- data/libxlsxwriter/include/xlsxwriter/vml.h +55 -0
- data/libxlsxwriter/include/xlsxwriter/workbook.h +218 -47
- data/libxlsxwriter/include/xlsxwriter/worksheet.h +2770 -241
- data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +12 -8
- data/libxlsxwriter/include/xlsxwriter.h +4 -2
- data/libxlsxwriter/libxlsxwriter.podspec +8 -5
- data/libxlsxwriter/src/Makefile +58 -21
- data/libxlsxwriter/src/app.c +5 -2
- data/libxlsxwriter/src/chart.c +396 -81
- data/libxlsxwriter/src/chartsheet.c +22 -22
- data/libxlsxwriter/src/comment.c +443 -0
- data/libxlsxwriter/src/content_types.c +40 -1
- data/libxlsxwriter/src/core.c +2 -2
- data/libxlsxwriter/src/custom.c +1 -1
- data/libxlsxwriter/src/drawing.c +160 -40
- data/libxlsxwriter/src/format.c +109 -25
- data/libxlsxwriter/src/hash_table.c +1 -1
- data/libxlsxwriter/src/metadata.c +283 -0
- data/libxlsxwriter/src/packager.c +794 -94
- data/libxlsxwriter/src/relationships.c +1 -1
- data/libxlsxwriter/src/shared_strings.c +2 -4
- data/libxlsxwriter/src/styles.c +353 -58
- data/libxlsxwriter/src/table.c +304 -0
- data/libxlsxwriter/src/theme.c +1 -1
- data/libxlsxwriter/src/utility.c +143 -43
- data/libxlsxwriter/src/vml.c +1062 -0
- data/libxlsxwriter/src/workbook.c +567 -77
- data/libxlsxwriter/src/worksheet.c +6668 -1462
- data/libxlsxwriter/src/xmlwriter.c +95 -5
- data/libxlsxwriter/third_party/dtoa/Makefile +42 -0
- data/libxlsxwriter/third_party/dtoa/emyg_dtoa.c +461 -0
- data/libxlsxwriter/third_party/dtoa/emyg_dtoa.h +26 -0
- data/libxlsxwriter/third_party/md5/Makefile +42 -0
- data/libxlsxwriter/third_party/md5/md5.c +291 -0
- data/libxlsxwriter/third_party/md5/md5.h +45 -0
- data/libxlsxwriter/third_party/minizip/Makefile +3 -8
- data/libxlsxwriter/third_party/minizip/Makefile.orig +8 -4
- data/libxlsxwriter/third_party/minizip/MiniZip64_Changes.txt +1 -1
- data/libxlsxwriter/third_party/minizip/configure.ac +1 -1
- data/libxlsxwriter/third_party/minizip/crypt.h +13 -16
- data/libxlsxwriter/third_party/minizip/ioapi.c +31 -57
- data/libxlsxwriter/third_party/minizip/ioapi.h +31 -23
- data/libxlsxwriter/third_party/minizip/iowin32.c +29 -45
- data/libxlsxwriter/third_party/minizip/iowin32.h +4 -4
- data/libxlsxwriter/third_party/minizip/miniunz.c +29 -56
- data/libxlsxwriter/third_party/minizip/minizip.c +38 -49
- data/libxlsxwriter/third_party/minizip/mztools.c +1 -7
- data/libxlsxwriter/third_party/minizip/unzip.c +202 -342
- data/libxlsxwriter/third_party/minizip/unzip.h +74 -74
- data/libxlsxwriter/third_party/minizip/zip.c +165 -218
- data/libxlsxwriter/third_party/minizip/zip.h +164 -154
- data/libxlsxwriter/third_party/tmpfileplus/Makefile +3 -3
- data/libxlsxwriter/version.txt +1 -1
- data/test/auto_width_test.rb +20 -0
- data/test/default_format_test.rb +1 -1
- data/test/validations_test.rb +3 -3
- data/test/worksheet_test.rb +6 -1
- metadata +33 -7
- data/libxlsxwriter/.travis.yml +0 -37
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
|
5
5
|
*
|
|
6
|
-
* Copyright 2014-
|
|
6
|
+
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -17,11 +17,15 @@ STATIC int _worksheet_name_cmp(lxw_worksheet_name *name1,
|
|
|
17
17
|
lxw_worksheet_name *name2);
|
|
18
18
|
STATIC int _chartsheet_name_cmp(lxw_chartsheet_name *name1,
|
|
19
19
|
lxw_chartsheet_name *name2);
|
|
20
|
+
STATIC int _image_md5_cmp(lxw_image_md5 *tuple1, lxw_image_md5 *tuple2);
|
|
21
|
+
|
|
20
22
|
#ifndef __clang_analyzer__
|
|
21
23
|
LXW_RB_GENERATE_WORKSHEET_NAMES(lxw_worksheet_names, lxw_worksheet_name,
|
|
22
24
|
tree_pointers, _worksheet_name_cmp);
|
|
23
25
|
LXW_RB_GENERATE_CHARTSHEET_NAMES(lxw_chartsheet_names, lxw_chartsheet_name,
|
|
24
26
|
tree_pointers, _chartsheet_name_cmp);
|
|
27
|
+
LXW_RB_GENERATE_IMAGE_MD5S(lxw_image_md5s, lxw_image_md5,
|
|
28
|
+
tree_pointers, _image_md5_cmp);
|
|
25
29
|
#endif
|
|
26
30
|
|
|
27
31
|
/*
|
|
@@ -49,6 +53,12 @@ _chartsheet_name_cmp(lxw_chartsheet_name *name1, lxw_chartsheet_name *name2)
|
|
|
49
53
|
return lxw_strcasecmp(name1->name, name2->name);
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
STATIC int
|
|
57
|
+
_image_md5_cmp(lxw_image_md5 *tuple1, lxw_image_md5 *tuple2)
|
|
58
|
+
{
|
|
59
|
+
return strcmp(tuple1->md5, tuple2->md5);
|
|
60
|
+
}
|
|
61
|
+
|
|
52
62
|
/*
|
|
53
63
|
* Free workbook properties.
|
|
54
64
|
*/
|
|
@@ -56,16 +66,16 @@ STATIC void
|
|
|
56
66
|
_free_doc_properties(lxw_doc_properties *properties)
|
|
57
67
|
{
|
|
58
68
|
if (properties) {
|
|
59
|
-
free(properties->title);
|
|
60
|
-
free(properties->subject);
|
|
61
|
-
free(properties->author);
|
|
62
|
-
free(properties->manager);
|
|
63
|
-
free(properties->company);
|
|
64
|
-
free(properties->category);
|
|
65
|
-
free(properties->keywords);
|
|
66
|
-
free(properties->comments);
|
|
67
|
-
free(properties->status);
|
|
68
|
-
free(properties->hyperlink_base);
|
|
69
|
+
free((void *) properties->title);
|
|
70
|
+
free((void *) properties->subject);
|
|
71
|
+
free((void *) properties->author);
|
|
72
|
+
free((void *) properties->manager);
|
|
73
|
+
free((void *) properties->company);
|
|
74
|
+
free((void *) properties->category);
|
|
75
|
+
free((void *) properties->keywords);
|
|
76
|
+
free((void *) properties->comments);
|
|
77
|
+
free((void *) properties->status);
|
|
78
|
+
free((void *) properties->hyperlink_base);
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
free(properties);
|
|
@@ -97,6 +107,8 @@ lxw_workbook_free(lxw_workbook *workbook)
|
|
|
97
107
|
struct lxw_worksheet_name *next_worksheet_name;
|
|
98
108
|
struct lxw_chartsheet_name *chartsheet_name;
|
|
99
109
|
struct lxw_chartsheet_name *next_chartsheet_name;
|
|
110
|
+
struct lxw_image_md5 *image_md5;
|
|
111
|
+
struct lxw_image_md5 *next_image_md5;
|
|
100
112
|
lxw_chart *chart;
|
|
101
113
|
lxw_format *format;
|
|
102
114
|
lxw_defined_name *defined_name;
|
|
@@ -204,11 +216,55 @@ lxw_workbook_free(lxw_workbook *workbook)
|
|
|
204
216
|
free(workbook->chartsheet_names);
|
|
205
217
|
}
|
|
206
218
|
|
|
219
|
+
if (workbook->image_md5s) {
|
|
220
|
+
for (image_md5 = RB_MIN(lxw_image_md5s, workbook->image_md5s);
|
|
221
|
+
image_md5; image_md5 = next_image_md5) {
|
|
222
|
+
|
|
223
|
+
next_image_md5 =
|
|
224
|
+
RB_NEXT(lxw_image_md5s, workbook->image_md5, image_md5);
|
|
225
|
+
RB_REMOVE(lxw_image_md5s, workbook->image_md5s, image_md5);
|
|
226
|
+
free(image_md5->md5);
|
|
227
|
+
free(image_md5);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
free(workbook->image_md5s);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (workbook->header_image_md5s) {
|
|
234
|
+
for (image_md5 = RB_MIN(lxw_image_md5s, workbook->header_image_md5s);
|
|
235
|
+
image_md5; image_md5 = next_image_md5) {
|
|
236
|
+
|
|
237
|
+
next_image_md5 =
|
|
238
|
+
RB_NEXT(lxw_image_md5s, workbook->image_md5, image_md5);
|
|
239
|
+
RB_REMOVE(lxw_image_md5s, workbook->header_image_md5s, image_md5);
|
|
240
|
+
free(image_md5->md5);
|
|
241
|
+
free(image_md5);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
free(workbook->header_image_md5s);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (workbook->background_md5s) {
|
|
248
|
+
for (image_md5 = RB_MIN(lxw_image_md5s, workbook->background_md5s);
|
|
249
|
+
image_md5; image_md5 = next_image_md5) {
|
|
250
|
+
|
|
251
|
+
next_image_md5 =
|
|
252
|
+
RB_NEXT(lxw_image_md5s, workbook->image_md5, image_md5);
|
|
253
|
+
RB_REMOVE(lxw_image_md5s, workbook->background_md5s, image_md5);
|
|
254
|
+
free(image_md5->md5);
|
|
255
|
+
free(image_md5);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
free(workbook->background_md5s);
|
|
259
|
+
}
|
|
260
|
+
|
|
207
261
|
lxw_hash_free(workbook->used_xf_formats);
|
|
262
|
+
lxw_hash_free(workbook->used_dxf_formats);
|
|
208
263
|
lxw_sst_free(workbook->sst);
|
|
209
|
-
free(workbook->options.tmpdir);
|
|
264
|
+
free((void *) workbook->options.tmpdir);
|
|
210
265
|
free(workbook->ordered_charts);
|
|
211
266
|
free(workbook->vba_project);
|
|
267
|
+
free(workbook->vba_project_signature);
|
|
212
268
|
free(workbook->vba_codename);
|
|
213
269
|
free(workbook);
|
|
214
270
|
}
|
|
@@ -220,9 +276,15 @@ void
|
|
|
220
276
|
lxw_workbook_set_default_xf_indices(lxw_workbook *self)
|
|
221
277
|
{
|
|
222
278
|
lxw_format *format;
|
|
279
|
+
int32_t index = 0;
|
|
223
280
|
|
|
224
281
|
STAILQ_FOREACH(format, self->formats, list_pointers) {
|
|
225
|
-
|
|
282
|
+
|
|
283
|
+
/* Skip the hyperlink format. */
|
|
284
|
+
if (index != 1)
|
|
285
|
+
lxw_format_get_xf_index(format);
|
|
286
|
+
|
|
287
|
+
index++;
|
|
226
288
|
}
|
|
227
289
|
}
|
|
228
290
|
|
|
@@ -258,7 +320,7 @@ _prepare_fonts(lxw_workbook *self)
|
|
|
258
320
|
uint16_t *font_index = calloc(1, sizeof(uint16_t));
|
|
259
321
|
*font_index = index;
|
|
260
322
|
format->font_index = index;
|
|
261
|
-
format->has_font =
|
|
323
|
+
format->has_font = LXW_TRUE;
|
|
262
324
|
lxw_insert_hash_element(fonts, key, font_index,
|
|
263
325
|
sizeof(lxw_font));
|
|
264
326
|
index++;
|
|
@@ -268,6 +330,18 @@ _prepare_fonts(lxw_workbook *self)
|
|
|
268
330
|
|
|
269
331
|
lxw_hash_free(fonts);
|
|
270
332
|
|
|
333
|
+
/* For DXF formats we only need to check if the properties have changed. */
|
|
334
|
+
LXW_FOREACH_ORDERED(used_format_element, self->used_dxf_formats) {
|
|
335
|
+
lxw_format *format = (lxw_format *) used_format_element->value;
|
|
336
|
+
|
|
337
|
+
/* The only font properties that can change for a DXF format are:
|
|
338
|
+
* color, bold, italic, underline and strikethrough. */
|
|
339
|
+
if (format->font_color || format->bold || format->italic
|
|
340
|
+
|| format->underline || format->font_strikeout) {
|
|
341
|
+
format->has_dxf_font = LXW_TRUE;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
271
345
|
self->font_count = index;
|
|
272
346
|
}
|
|
273
347
|
|
|
@@ -312,6 +386,15 @@ _prepare_borders(lxw_workbook *self)
|
|
|
312
386
|
}
|
|
313
387
|
}
|
|
314
388
|
|
|
389
|
+
/* For DXF formats we only need to check if the properties have changed. */
|
|
390
|
+
LXW_FOREACH_ORDERED(used_format_element, self->used_dxf_formats) {
|
|
391
|
+
lxw_format *format = (lxw_format *) used_format_element->value;
|
|
392
|
+
|
|
393
|
+
if (format->left || format->right || format->top || format->bottom) {
|
|
394
|
+
format->has_dxf_border = LXW_TRUE;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
315
398
|
lxw_hash_free(borders);
|
|
316
399
|
|
|
317
400
|
self->border_count = index;
|
|
@@ -361,6 +444,17 @@ _prepare_fills(lxw_workbook *self)
|
|
|
361
444
|
lxw_insert_hash_element(fills, default_fill_2, fill_index2,
|
|
362
445
|
sizeof(lxw_fill));
|
|
363
446
|
|
|
447
|
+
/* For DXF formats we only need to check if the properties have changed. */
|
|
448
|
+
LXW_FOREACH_ORDERED(used_format_element, self->used_dxf_formats) {
|
|
449
|
+
lxw_format *format = (lxw_format *) used_format_element->value;
|
|
450
|
+
|
|
451
|
+
if (format->pattern || format->bg_color || format->fg_color) {
|
|
452
|
+
format->has_dxf_fill = LXW_TRUE;
|
|
453
|
+
format->dxf_bg_color = format->bg_color;
|
|
454
|
+
format->dxf_fg_color = format->fg_color;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
364
458
|
LXW_FOREACH_ORDERED(used_format_element, self->used_xf_formats) {
|
|
365
459
|
lxw_format *format = (lxw_format *) used_format_element->value;
|
|
366
460
|
lxw_fill *key = lxw_format_get_fill_key(format);
|
|
@@ -391,7 +485,6 @@ _prepare_fills(lxw_workbook *self)
|
|
|
391
485
|
if (format->pattern <= LXW_PATTERN_SOLID
|
|
392
486
|
&& format->bg_color == LXW_COLOR_UNSET
|
|
393
487
|
&& format->fg_color != LXW_COLOR_UNSET) {
|
|
394
|
-
format->bg_color = LXW_COLOR_UNSET;
|
|
395
488
|
format->pattern = LXW_PATTERN_SOLID;
|
|
396
489
|
}
|
|
397
490
|
|
|
@@ -482,6 +575,41 @@ _prepare_num_formats(lxw_workbook *self)
|
|
|
482
575
|
}
|
|
483
576
|
}
|
|
484
577
|
|
|
578
|
+
LXW_FOREACH_ORDERED(used_format_element, self->used_dxf_formats) {
|
|
579
|
+
lxw_format *format = (lxw_format *) used_format_element->value;
|
|
580
|
+
|
|
581
|
+
/* Format already has a number format index. */
|
|
582
|
+
if (format->num_format_index)
|
|
583
|
+
continue;
|
|
584
|
+
|
|
585
|
+
/* Check if there is a user defined number format string. */
|
|
586
|
+
if (*format->num_format) {
|
|
587
|
+
char num_format[LXW_FORMAT_FIELD_LEN] = { 0 };
|
|
588
|
+
lxw_snprintf(num_format, LXW_FORMAT_FIELD_LEN, "%s",
|
|
589
|
+
format->num_format);
|
|
590
|
+
|
|
591
|
+
/* Look up the num_format in the hash table. */
|
|
592
|
+
hash_element = lxw_hash_key_exists(num_formats, num_format,
|
|
593
|
+
LXW_FORMAT_FIELD_LEN);
|
|
594
|
+
|
|
595
|
+
if (hash_element) {
|
|
596
|
+
/* Num_Format has already been used. */
|
|
597
|
+
format->num_format_index = *(uint16_t *) hash_element->value;
|
|
598
|
+
}
|
|
599
|
+
else {
|
|
600
|
+
/* This is a new num_format. */
|
|
601
|
+
num_format_index = calloc(1, sizeof(uint16_t));
|
|
602
|
+
*num_format_index = index;
|
|
603
|
+
format->num_format_index = index;
|
|
604
|
+
lxw_insert_hash_element(num_formats, format->num_format,
|
|
605
|
+
num_format_index,
|
|
606
|
+
LXW_FORMAT_FIELD_LEN);
|
|
607
|
+
index++;
|
|
608
|
+
/* Don't update num_format_count for DXF formats. */
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
485
613
|
lxw_hash_free(num_formats);
|
|
486
614
|
|
|
487
615
|
self->num_format_count = num_format_count;
|
|
@@ -735,7 +863,7 @@ _populate_range_data_cache(lxw_workbook *self, lxw_series_range *range)
|
|
|
735
863
|
return;
|
|
736
864
|
}
|
|
737
865
|
|
|
738
|
-
cell_obj =
|
|
866
|
+
cell_obj = lxw_worksheet_find_cell_in_row(row_obj, col_num);
|
|
739
867
|
|
|
740
868
|
if (cell_obj) {
|
|
741
869
|
if (cell_obj->type == NUMBER_CELL) {
|
|
@@ -796,7 +924,7 @@ _populate_range_dimensions(lxw_workbook *self, lxw_series_range *range)
|
|
|
796
924
|
/* Create a copy of the formula to modify and parse into parts. */
|
|
797
925
|
lxw_snprintf(formula, LXW_MAX_FORMULA_RANGE_LENGTH, "%s", range->formula);
|
|
798
926
|
|
|
799
|
-
/* Check for valid formula.
|
|
927
|
+
/* Check for valid formula. Note, This needs stronger validation. */
|
|
800
928
|
tmp_str = strchr(formula, '!');
|
|
801
929
|
|
|
802
930
|
if (tmp_str == NULL) {
|
|
@@ -847,6 +975,9 @@ _populate_range_dimensions(lxw_workbook *self, lxw_series_range *range)
|
|
|
847
975
|
STATIC void
|
|
848
976
|
_populate_range(lxw_workbook *self, lxw_series_range *range)
|
|
849
977
|
{
|
|
978
|
+
if (!range)
|
|
979
|
+
return;
|
|
980
|
+
|
|
850
981
|
_populate_range_dimensions(self, range);
|
|
851
982
|
_populate_range_data_cache(self, range);
|
|
852
983
|
}
|
|
@@ -860,6 +991,7 @@ _add_chart_cache_data(lxw_workbook *self)
|
|
|
860
991
|
{
|
|
861
992
|
lxw_chart *chart;
|
|
862
993
|
lxw_chart_series *series;
|
|
994
|
+
uint16_t i;
|
|
863
995
|
|
|
864
996
|
STAILQ_FOREACH(chart, self->ordered_charts, ordered_list_pointers) {
|
|
865
997
|
|
|
@@ -874,10 +1006,34 @@ _add_chart_cache_data(lxw_workbook *self)
|
|
|
874
1006
|
_populate_range(self, series->categories);
|
|
875
1007
|
_populate_range(self, series->values);
|
|
876
1008
|
_populate_range(self, series->title.range);
|
|
1009
|
+
|
|
1010
|
+
for (i = 0; i < series->data_label_count; i++) {
|
|
1011
|
+
lxw_chart_custom_label *data_label = &series->data_labels[i];
|
|
1012
|
+
_populate_range(self, data_label->range);
|
|
1013
|
+
}
|
|
877
1014
|
}
|
|
878
1015
|
}
|
|
879
1016
|
}
|
|
880
1017
|
|
|
1018
|
+
/*
|
|
1019
|
+
* Store the image types used in the workbook to update the content types.
|
|
1020
|
+
*/
|
|
1021
|
+
STATIC void
|
|
1022
|
+
_store_image_type(lxw_workbook *self, uint8_t image_type)
|
|
1023
|
+
{
|
|
1024
|
+
if (image_type == LXW_IMAGE_PNG)
|
|
1025
|
+
self->has_png = LXW_TRUE;
|
|
1026
|
+
|
|
1027
|
+
if (image_type == LXW_IMAGE_JPEG)
|
|
1028
|
+
self->has_jpeg = LXW_TRUE;
|
|
1029
|
+
|
|
1030
|
+
if (image_type == LXW_IMAGE_BMP)
|
|
1031
|
+
self->has_bmp = LXW_TRUE;
|
|
1032
|
+
|
|
1033
|
+
if (image_type == LXW_IMAGE_GIF)
|
|
1034
|
+
self->has_gif = LXW_TRUE;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
881
1037
|
/*
|
|
882
1038
|
* Iterate through the worksheets and set up any chart or image drawings.
|
|
883
1039
|
*/
|
|
@@ -886,11 +1042,16 @@ _prepare_drawings(lxw_workbook *self)
|
|
|
886
1042
|
{
|
|
887
1043
|
lxw_sheet *sheet;
|
|
888
1044
|
lxw_worksheet *worksheet;
|
|
889
|
-
|
|
1045
|
+
lxw_object_properties *object_props;
|
|
890
1046
|
uint32_t chart_ref_id = 0;
|
|
891
1047
|
uint32_t image_ref_id = 0;
|
|
1048
|
+
uint32_t ref_id = 0;
|
|
892
1049
|
uint32_t drawing_id = 0;
|
|
893
1050
|
uint8_t is_chartsheet;
|
|
1051
|
+
lxw_image_md5 tmp_image_md5;
|
|
1052
|
+
lxw_image_md5 *new_image_md5 = NULL;
|
|
1053
|
+
lxw_image_md5 *found_duplicate_image = NULL;
|
|
1054
|
+
uint8_t i;
|
|
894
1055
|
|
|
895
1056
|
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
|
896
1057
|
if (sheet->is_chartsheet) {
|
|
@@ -902,42 +1063,205 @@ _prepare_drawings(lxw_workbook *self)
|
|
|
902
1063
|
is_chartsheet = LXW_FALSE;
|
|
903
1064
|
}
|
|
904
1065
|
|
|
905
|
-
if (STAILQ_EMPTY(worksheet->
|
|
906
|
-
&& STAILQ_EMPTY(worksheet->chart_data)
|
|
1066
|
+
if (STAILQ_EMPTY(worksheet->image_props)
|
|
1067
|
+
&& STAILQ_EMPTY(worksheet->chart_data)
|
|
1068
|
+
&& !worksheet->has_header_vml && !worksheet->has_background_image) {
|
|
907
1069
|
continue;
|
|
1070
|
+
}
|
|
908
1071
|
|
|
909
1072
|
drawing_id++;
|
|
910
1073
|
|
|
911
|
-
|
|
1074
|
+
/* Prepare background images. */
|
|
1075
|
+
if (worksheet->has_background_image) {
|
|
1076
|
+
|
|
1077
|
+
object_props = worksheet->background_image;
|
|
1078
|
+
|
|
1079
|
+
_store_image_type(self, object_props->image_type);
|
|
1080
|
+
|
|
1081
|
+
/* Check for duplicate images and only store the first instance. */
|
|
1082
|
+
if (object_props->md5) {
|
|
1083
|
+
tmp_image_md5.md5 = object_props->md5;
|
|
1084
|
+
found_duplicate_image = RB_FIND(lxw_image_md5s,
|
|
1085
|
+
self->background_md5s,
|
|
1086
|
+
&tmp_image_md5);
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
if (found_duplicate_image) {
|
|
1090
|
+
ref_id = found_duplicate_image->id;
|
|
1091
|
+
object_props->is_duplicate = LXW_TRUE;
|
|
1092
|
+
}
|
|
1093
|
+
else {
|
|
1094
|
+
image_ref_id++;
|
|
1095
|
+
ref_id = image_ref_id;
|
|
1096
|
+
|
|
1097
|
+
#ifndef USE_NO_MD5
|
|
1098
|
+
new_image_md5 = calloc(1, sizeof(lxw_image_md5));
|
|
1099
|
+
#endif
|
|
1100
|
+
if (new_image_md5 && object_props->md5) {
|
|
1101
|
+
new_image_md5->id = ref_id;
|
|
1102
|
+
new_image_md5->md5 = lxw_strdup(object_props->md5);
|
|
1103
|
+
|
|
1104
|
+
RB_INSERT(lxw_image_md5s, self->background_md5s,
|
|
1105
|
+
new_image_md5);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
lxw_worksheet_prepare_background(worksheet, ref_id, object_props);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/* Prepare worksheet images. */
|
|
1113
|
+
STAILQ_FOREACH(object_props, worksheet->image_props, list_pointers) {
|
|
1114
|
+
|
|
1115
|
+
/* Ignore background image added above. */
|
|
1116
|
+
if (object_props->is_background)
|
|
1117
|
+
continue;
|
|
1118
|
+
|
|
1119
|
+
_store_image_type(self, object_props->image_type);
|
|
1120
|
+
|
|
1121
|
+
/* Check for duplicate images and only store the first instance. */
|
|
1122
|
+
if (object_props->md5) {
|
|
1123
|
+
tmp_image_md5.md5 = object_props->md5;
|
|
1124
|
+
found_duplicate_image = RB_FIND(lxw_image_md5s,
|
|
1125
|
+
self->image_md5s,
|
|
1126
|
+
&tmp_image_md5);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
if (found_duplicate_image) {
|
|
1130
|
+
ref_id = found_duplicate_image->id;
|
|
1131
|
+
object_props->is_duplicate = LXW_TRUE;
|
|
1132
|
+
}
|
|
1133
|
+
else {
|
|
1134
|
+
image_ref_id++;
|
|
1135
|
+
ref_id = image_ref_id;
|
|
1136
|
+
|
|
1137
|
+
#ifndef USE_NO_MD5
|
|
1138
|
+
new_image_md5 = calloc(1, sizeof(lxw_image_md5));
|
|
1139
|
+
#endif
|
|
1140
|
+
if (new_image_md5 && object_props->md5) {
|
|
1141
|
+
new_image_md5->id = ref_id;
|
|
1142
|
+
new_image_md5->md5 = lxw_strdup(object_props->md5);
|
|
1143
|
+
|
|
1144
|
+
RB_INSERT(lxw_image_md5s, self->image_md5s,
|
|
1145
|
+
new_image_md5);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
lxw_worksheet_prepare_image(worksheet, ref_id, drawing_id,
|
|
1150
|
+
object_props);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/* Prepare worksheet charts. */
|
|
1154
|
+
STAILQ_FOREACH(object_props, worksheet->chart_data, list_pointers) {
|
|
912
1155
|
chart_ref_id++;
|
|
913
1156
|
lxw_worksheet_prepare_chart(worksheet, chart_ref_id, drawing_id,
|
|
914
|
-
|
|
915
|
-
if (
|
|
916
|
-
STAILQ_INSERT_TAIL(self->ordered_charts,
|
|
1157
|
+
object_props, is_chartsheet);
|
|
1158
|
+
if (object_props->chart)
|
|
1159
|
+
STAILQ_INSERT_TAIL(self->ordered_charts, object_props->chart,
|
|
917
1160
|
ordered_list_pointers);
|
|
918
1161
|
}
|
|
919
1162
|
|
|
920
|
-
|
|
1163
|
+
/* Prepare worksheet header/footer images. */
|
|
1164
|
+
for (i = 0; i < LXW_HEADER_FOOTER_OBJS_MAX; i++) {
|
|
1165
|
+
|
|
1166
|
+
object_props = *worksheet->header_footer_objs[i];
|
|
1167
|
+
if (!object_props)
|
|
1168
|
+
continue;
|
|
921
1169
|
|
|
922
|
-
|
|
923
|
-
self->has_png = LXW_TRUE;
|
|
1170
|
+
_store_image_type(self, object_props->image_type);
|
|
924
1171
|
|
|
925
|
-
|
|
926
|
-
|
|
1172
|
+
/* Check for duplicate images and only store the first instance. */
|
|
1173
|
+
if (object_props->md5) {
|
|
1174
|
+
tmp_image_md5.md5 = object_props->md5;
|
|
1175
|
+
found_duplicate_image = RB_FIND(lxw_image_md5s,
|
|
1176
|
+
self->header_image_md5s,
|
|
1177
|
+
&tmp_image_md5);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
if (found_duplicate_image) {
|
|
1181
|
+
ref_id = found_duplicate_image->id;
|
|
1182
|
+
object_props->is_duplicate = LXW_TRUE;
|
|
1183
|
+
}
|
|
1184
|
+
else {
|
|
1185
|
+
image_ref_id++;
|
|
1186
|
+
ref_id = image_ref_id;
|
|
927
1187
|
|
|
928
|
-
|
|
929
|
-
|
|
1188
|
+
#ifndef USE_NO_MD5
|
|
1189
|
+
new_image_md5 = calloc(1, sizeof(lxw_image_md5));
|
|
1190
|
+
#endif
|
|
1191
|
+
if (new_image_md5 && object_props->md5) {
|
|
1192
|
+
new_image_md5->id = ref_id;
|
|
1193
|
+
new_image_md5->md5 = lxw_strdup(object_props->md5);
|
|
930
1194
|
|
|
931
|
-
|
|
1195
|
+
RB_INSERT(lxw_image_md5s, self->header_image_md5s,
|
|
1196
|
+
new_image_md5);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
932
1199
|
|
|
933
|
-
|
|
934
|
-
|
|
1200
|
+
lxw_worksheet_prepare_header_image(worksheet, ref_id,
|
|
1201
|
+
object_props);
|
|
935
1202
|
}
|
|
1203
|
+
|
|
936
1204
|
}
|
|
937
1205
|
|
|
938
1206
|
self->drawing_count = drawing_id;
|
|
939
1207
|
}
|
|
940
1208
|
|
|
1209
|
+
/*
|
|
1210
|
+
* Iterate through the worksheets and set up the VML objects.
|
|
1211
|
+
*/
|
|
1212
|
+
STATIC void
|
|
1213
|
+
_prepare_vml(lxw_workbook *self)
|
|
1214
|
+
{
|
|
1215
|
+
lxw_worksheet *worksheet;
|
|
1216
|
+
lxw_sheet *sheet;
|
|
1217
|
+
uint32_t comment_id = 0;
|
|
1218
|
+
uint32_t vml_drawing_id = 0;
|
|
1219
|
+
uint32_t vml_data_id = 1;
|
|
1220
|
+
uint32_t vml_header_id = 0;
|
|
1221
|
+
uint32_t vml_shape_id = 1024;
|
|
1222
|
+
uint32_t comment_count = 0;
|
|
1223
|
+
|
|
1224
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
|
1225
|
+
if (sheet->is_chartsheet)
|
|
1226
|
+
continue;
|
|
1227
|
+
else
|
|
1228
|
+
worksheet = sheet->u.worksheet;
|
|
1229
|
+
|
|
1230
|
+
if (!worksheet->has_vml && !worksheet->has_header_vml)
|
|
1231
|
+
continue;
|
|
1232
|
+
|
|
1233
|
+
if (worksheet->has_vml) {
|
|
1234
|
+
self->has_vml = LXW_TRUE;
|
|
1235
|
+
if (worksheet->has_comments) {
|
|
1236
|
+
self->comment_count++;
|
|
1237
|
+
comment_id++;
|
|
1238
|
+
self->has_comments = LXW_TRUE;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
vml_drawing_id++;
|
|
1242
|
+
|
|
1243
|
+
comment_count = lxw_worksheet_prepare_vml_objects(worksheet,
|
|
1244
|
+
vml_data_id,
|
|
1245
|
+
vml_shape_id,
|
|
1246
|
+
vml_drawing_id,
|
|
1247
|
+
comment_id);
|
|
1248
|
+
|
|
1249
|
+
/* Each VML should start with a shape id incremented by 1024. */
|
|
1250
|
+
vml_data_id += 1 * ((1024 + comment_count) / 1024);
|
|
1251
|
+
vml_shape_id += 1024 * ((1024 + comment_count) / 1024);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
if (worksheet->has_header_vml) {
|
|
1255
|
+
self->has_vml = LXW_TRUE;
|
|
1256
|
+
vml_drawing_id++;
|
|
1257
|
+
vml_header_id++;
|
|
1258
|
+
lxw_worksheet_prepare_header_vml_objects(worksheet,
|
|
1259
|
+
vml_header_id,
|
|
1260
|
+
vml_drawing_id);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
941
1265
|
/*
|
|
942
1266
|
* Iterate through the worksheets and store any defined names used for print
|
|
943
1267
|
* ranges or repeat rows/columns.
|
|
@@ -1085,6 +1409,34 @@ _prepare_defined_names(lxw_workbook *self)
|
|
|
1085
1409
|
}
|
|
1086
1410
|
}
|
|
1087
1411
|
|
|
1412
|
+
/*
|
|
1413
|
+
* Iterate through the worksheets and set up the table objects.
|
|
1414
|
+
*/
|
|
1415
|
+
STATIC void
|
|
1416
|
+
_prepare_tables(lxw_workbook *self)
|
|
1417
|
+
{
|
|
1418
|
+
lxw_worksheet *worksheet;
|
|
1419
|
+
lxw_sheet *sheet;
|
|
1420
|
+
uint32_t table_id = 0;
|
|
1421
|
+
uint32_t table_count = 0;
|
|
1422
|
+
|
|
1423
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
|
1424
|
+
if (sheet->is_chartsheet)
|
|
1425
|
+
continue;
|
|
1426
|
+
else
|
|
1427
|
+
worksheet = sheet->u.worksheet;
|
|
1428
|
+
|
|
1429
|
+
table_count = worksheet->table_count;
|
|
1430
|
+
|
|
1431
|
+
if (table_count == 0)
|
|
1432
|
+
continue;
|
|
1433
|
+
|
|
1434
|
+
lxw_worksheet_prepare_tables(worksheet, table_id + 1);
|
|
1435
|
+
|
|
1436
|
+
table_id += table_count;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1088
1440
|
/*****************************************************************************
|
|
1089
1441
|
*
|
|
1090
1442
|
* XML functions.
|
|
@@ -1146,6 +1498,26 @@ _write_file_version(lxw_workbook *self)
|
|
|
1146
1498
|
LXW_FREE_ATTRIBUTES();
|
|
1147
1499
|
}
|
|
1148
1500
|
|
|
1501
|
+
/*
|
|
1502
|
+
* Write the <fileSharing> element.
|
|
1503
|
+
*/
|
|
1504
|
+
STATIC void
|
|
1505
|
+
_workbook_write_file_sharing(lxw_workbook *self)
|
|
1506
|
+
{
|
|
1507
|
+
struct xml_attribute_list attributes;
|
|
1508
|
+
struct xml_attribute *attribute;
|
|
1509
|
+
|
|
1510
|
+
if (self->read_only == 0)
|
|
1511
|
+
return;
|
|
1512
|
+
|
|
1513
|
+
LXW_INIT_ATTRIBUTES();
|
|
1514
|
+
LXW_PUSH_ATTRIBUTES_STR("readOnlyRecommended", "1");
|
|
1515
|
+
|
|
1516
|
+
lxw_xml_empty_tag(self->file, "fileSharing", &attributes);
|
|
1517
|
+
|
|
1518
|
+
LXW_FREE_ATTRIBUTES();
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1149
1521
|
/*
|
|
1150
1522
|
* Write the <workbookPr> element.
|
|
1151
1523
|
*/
|
|
@@ -1344,6 +1716,9 @@ lxw_workbook_assemble_xml_file(lxw_workbook *self)
|
|
|
1344
1716
|
/* Write the XLSX file version. */
|
|
1345
1717
|
_write_file_version(self);
|
|
1346
1718
|
|
|
1719
|
+
/* Write the fileSharing element. */
|
|
1720
|
+
_workbook_write_file_sharing(self);
|
|
1721
|
+
|
|
1347
1722
|
/* Write the workbook properties. */
|
|
1348
1723
|
_write_workbook_pr(self);
|
|
1349
1724
|
|
|
@@ -1432,6 +1807,21 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
|
|
1432
1807
|
GOTO_LABEL_ON_MEM_ERROR(workbook->chartsheet_names, mem_error);
|
|
1433
1808
|
RB_INIT(workbook->chartsheet_names);
|
|
1434
1809
|
|
|
1810
|
+
/* Add the image MD5 tree. */
|
|
1811
|
+
workbook->image_md5s = calloc(1, sizeof(struct lxw_image_md5s));
|
|
1812
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->image_md5s, mem_error);
|
|
1813
|
+
RB_INIT(workbook->image_md5s);
|
|
1814
|
+
|
|
1815
|
+
/* Add the header image MD5 tree. */
|
|
1816
|
+
workbook->header_image_md5s = calloc(1, sizeof(struct lxw_image_md5s));
|
|
1817
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->header_image_md5s, mem_error);
|
|
1818
|
+
RB_INIT(workbook->header_image_md5s);
|
|
1819
|
+
|
|
1820
|
+
/* Add the background image MD5 tree. */
|
|
1821
|
+
workbook->background_md5s = calloc(1, sizeof(struct lxw_image_md5s));
|
|
1822
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->background_md5s, mem_error);
|
|
1823
|
+
RB_INIT(workbook->background_md5s);
|
|
1824
|
+
|
|
1435
1825
|
/* Add the charts list. */
|
|
1436
1826
|
workbook->charts = calloc(1, sizeof(struct lxw_charts));
|
|
1437
1827
|
GOTO_LABEL_ON_MEM_ERROR(workbook->charts, mem_error);
|
|
@@ -1464,6 +1854,10 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
|
|
1464
1854
|
workbook->used_xf_formats = lxw_hash_new(128, 1, 0);
|
|
1465
1855
|
GOTO_LABEL_ON_MEM_ERROR(workbook->used_xf_formats, mem_error);
|
|
1466
1856
|
|
|
1857
|
+
/* Add a hash table to track format indices. */
|
|
1858
|
+
workbook->used_dxf_formats = lxw_hash_new(128, 1, 0);
|
|
1859
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->used_dxf_formats, mem_error);
|
|
1860
|
+
|
|
1467
1861
|
/* Add the worksheets list. */
|
|
1468
1862
|
workbook->custom_properties =
|
|
1469
1863
|
calloc(1, sizeof(struct lxw_custom_properties));
|
|
@@ -1477,12 +1871,22 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
|
|
1477
1871
|
/* Initialize its index. */
|
|
1478
1872
|
lxw_format_get_xf_index(format);
|
|
1479
1873
|
|
|
1874
|
+
/* Add the default hyperlink format. */
|
|
1875
|
+
format = workbook_add_format(workbook);
|
|
1876
|
+
GOTO_LABEL_ON_MEM_ERROR(format, mem_error);
|
|
1877
|
+
format_set_hyperlink(format);
|
|
1878
|
+
workbook->default_url_format = format;
|
|
1879
|
+
|
|
1480
1880
|
if (options) {
|
|
1481
1881
|
workbook->options.constant_memory = options->constant_memory;
|
|
1482
1882
|
workbook->options.tmpdir = lxw_strdup(options->tmpdir);
|
|
1483
1883
|
workbook->options.use_zip64 = options->use_zip64;
|
|
1884
|
+
workbook->options.output_buffer = options->output_buffer;
|
|
1885
|
+
workbook->options.output_buffer_size = options->output_buffer_size;
|
|
1484
1886
|
}
|
|
1485
1887
|
|
|
1888
|
+
workbook->max_url_length = 2079;
|
|
1889
|
+
|
|
1486
1890
|
return workbook;
|
|
1487
1891
|
|
|
1488
1892
|
mem_error:
|
|
@@ -1501,13 +1905,13 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
|
|
1501
1905
|
lxw_worksheet *worksheet = NULL;
|
|
1502
1906
|
lxw_worksheet_name *worksheet_name = NULL;
|
|
1503
1907
|
lxw_error error;
|
|
1504
|
-
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
1908
|
+
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
1505
1909
|
char *new_name = NULL;
|
|
1506
1910
|
|
|
1507
1911
|
if (sheetname) {
|
|
1508
1912
|
/* Use the user supplied name. */
|
|
1509
1913
|
init_data.name = lxw_strdup(sheetname);
|
|
1510
|
-
init_data.quoted_name = lxw_quote_sheetname(
|
|
1914
|
+
init_data.quoted_name = lxw_quote_sheetname(sheetname);
|
|
1511
1915
|
}
|
|
1512
1916
|
else {
|
|
1513
1917
|
/* Use the default SheetN name. */
|
|
@@ -1540,6 +1944,8 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
|
|
1540
1944
|
init_data.active_sheet = &self->active_sheet;
|
|
1541
1945
|
init_data.first_sheet = &self->first_sheet;
|
|
1542
1946
|
init_data.tmpdir = self->options.tmpdir;
|
|
1947
|
+
init_data.default_url_format = self->default_url_format;
|
|
1948
|
+
init_data.max_url_length = self->max_url_length;
|
|
1543
1949
|
|
|
1544
1950
|
/* Create a new worksheet object. */
|
|
1545
1951
|
worksheet = lxw_worksheet_new(&init_data);
|
|
@@ -1566,8 +1972,8 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
|
|
1566
1972
|
return worksheet;
|
|
1567
1973
|
|
|
1568
1974
|
mem_error:
|
|
1569
|
-
free(init_data.name);
|
|
1570
|
-
free(init_data.quoted_name);
|
|
1975
|
+
free((void *) init_data.name);
|
|
1976
|
+
free((void *) init_data.quoted_name);
|
|
1571
1977
|
free(worksheet_name);
|
|
1572
1978
|
free(worksheet);
|
|
1573
1979
|
return NULL;
|
|
@@ -1583,13 +1989,13 @@ workbook_add_chartsheet(lxw_workbook *self, const char *sheetname)
|
|
|
1583
1989
|
lxw_chartsheet *chartsheet = NULL;
|
|
1584
1990
|
lxw_chartsheet_name *chartsheet_name = NULL;
|
|
1585
1991
|
lxw_error error;
|
|
1586
|
-
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
1992
|
+
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
1587
1993
|
char *new_name = NULL;
|
|
1588
1994
|
|
|
1589
1995
|
if (sheetname) {
|
|
1590
1996
|
/* Use the user supplied name. */
|
|
1591
1997
|
init_data.name = lxw_strdup(sheetname);
|
|
1592
|
-
init_data.quoted_name = lxw_quote_sheetname(
|
|
1998
|
+
init_data.quoted_name = lxw_quote_sheetname(sheetname);
|
|
1593
1999
|
}
|
|
1594
2000
|
else {
|
|
1595
2001
|
/* Use the default SheetN name. */
|
|
@@ -1650,8 +2056,8 @@ workbook_add_chartsheet(lxw_workbook *self, const char *sheetname)
|
|
|
1650
2056
|
return chartsheet;
|
|
1651
2057
|
|
|
1652
2058
|
mem_error:
|
|
1653
|
-
free(init_data.name);
|
|
1654
|
-
free(init_data.quoted_name);
|
|
2059
|
+
free((void *) init_data.name);
|
|
2060
|
+
free((void *) init_data.quoted_name);
|
|
1655
2061
|
free(chartsheet_name);
|
|
1656
2062
|
free(chartsheet);
|
|
1657
2063
|
return NULL;
|
|
@@ -1694,6 +2100,7 @@ workbook_add_format(lxw_workbook *self)
|
|
|
1694
2100
|
}
|
|
1695
2101
|
|
|
1696
2102
|
format->xf_format_indices = self->used_xf_formats;
|
|
2103
|
+
format->dxf_format_indices = self->used_dxf_formats;
|
|
1697
2104
|
format->num_xf_formats = &self->num_xf_formats;
|
|
1698
2105
|
|
|
1699
2106
|
STAILQ_INSERT_TAIL(self->formats, format, list_pointers);
|
|
@@ -1721,6 +2128,7 @@ workbook_close(lxw_workbook *self)
|
|
|
1721
2128
|
lxw_worksheet *worksheet = NULL;
|
|
1722
2129
|
lxw_packager *packager = NULL;
|
|
1723
2130
|
lxw_error error = LXW_NO_ERROR;
|
|
2131
|
+
char codename[LXW_MAX_SHEETNAME_LENGTH] = { 0 };
|
|
1724
2132
|
|
|
1725
2133
|
/* Add a default worksheet if non have been added. */
|
|
1726
2134
|
if (!self->num_sheets)
|
|
@@ -1731,12 +2139,12 @@ workbook_close(lxw_workbook *self)
|
|
|
1731
2139
|
sheet = STAILQ_FIRST(self->sheets);
|
|
1732
2140
|
if (!sheet->is_chartsheet) {
|
|
1733
2141
|
worksheet = sheet->u.worksheet;
|
|
1734
|
-
worksheet->selected =
|
|
2142
|
+
worksheet->selected = LXW_TRUE;
|
|
1735
2143
|
worksheet->hidden = 0;
|
|
1736
2144
|
}
|
|
1737
2145
|
}
|
|
1738
2146
|
|
|
1739
|
-
/* Set the active sheet. */
|
|
2147
|
+
/* Set the active sheet and check if a metadata file is needed. */
|
|
1740
2148
|
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
|
1741
2149
|
if (sheet->is_chartsheet)
|
|
1742
2150
|
continue;
|
|
@@ -1744,7 +2152,10 @@ workbook_close(lxw_workbook *self)
|
|
|
1744
2152
|
worksheet = sheet->u.worksheet;
|
|
1745
2153
|
|
|
1746
2154
|
if (worksheet->index == self->active_sheet)
|
|
1747
|
-
worksheet->active =
|
|
2155
|
+
worksheet->active = LXW_TRUE;
|
|
2156
|
+
|
|
2157
|
+
if (worksheet->has_dynamic_arrays)
|
|
2158
|
+
self->has_metadata = LXW_TRUE;
|
|
1748
2159
|
}
|
|
1749
2160
|
|
|
1750
2161
|
/* Set workbook and worksheet VBA codenames if a macro has been added. */
|
|
@@ -1758,11 +2169,18 @@ workbook_close(lxw_workbook *self)
|
|
|
1758
2169
|
else
|
|
1759
2170
|
worksheet = sheet->u.worksheet;
|
|
1760
2171
|
|
|
1761
|
-
if (!worksheet->vba_codename)
|
|
1762
|
-
|
|
2172
|
+
if (!worksheet->vba_codename) {
|
|
2173
|
+
lxw_snprintf(codename, LXW_MAX_SHEETNAME_LENGTH, "Sheet%d",
|
|
2174
|
+
worksheet->index + 1);
|
|
2175
|
+
|
|
2176
|
+
worksheet_set_vba_name(worksheet, codename);
|
|
2177
|
+
}
|
|
1763
2178
|
}
|
|
1764
2179
|
}
|
|
1765
2180
|
|
|
2181
|
+
/* Prepare the worksheet VML elements such as comments. */
|
|
2182
|
+
_prepare_vml(self);
|
|
2183
|
+
|
|
1766
2184
|
/* Set the defined names for the worksheets such as Print Titles. */
|
|
1767
2185
|
_prepare_defined_names(self);
|
|
1768
2186
|
|
|
@@ -1772,6 +2190,9 @@ workbook_close(lxw_workbook *self)
|
|
|
1772
2190
|
/* Add cached data to charts. */
|
|
1773
2191
|
_add_chart_cache_data(self);
|
|
1774
2192
|
|
|
2193
|
+
/* Set the table ids for the worksheet tables. */
|
|
2194
|
+
_prepare_tables(self);
|
|
2195
|
+
|
|
1775
2196
|
/* Create a packager object to assemble sub-elements into a zip file. */
|
|
1776
2197
|
packager = lxw_packager_new(self->filename,
|
|
1777
2198
|
self->options.tmpdir,
|
|
@@ -1779,9 +2200,9 @@ workbook_close(lxw_workbook *self)
|
|
|
1779
2200
|
|
|
1780
2201
|
/* If the packager fails it is generally due to a zip permission error. */
|
|
1781
2202
|
if (packager == NULL) {
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
2203
|
+
LXW_PRINTF(LXW_STDERR "[ERROR] workbook_close(): "
|
|
2204
|
+
"Error creating '%s'. "
|
|
2205
|
+
"System error = %s\n", self->filename, strerror(errno));
|
|
1785
2206
|
|
|
1786
2207
|
error = LXW_ERROR_CREATING_XLSX_FILE;
|
|
1787
2208
|
goto mem_error;
|
|
@@ -1793,51 +2214,57 @@ workbook_close(lxw_workbook *self)
|
|
|
1793
2214
|
/* Assemble all the sub-files in the xlsx package. */
|
|
1794
2215
|
error = lxw_create_package(packager);
|
|
1795
2216
|
|
|
2217
|
+
if (!self->filename) {
|
|
2218
|
+
*self->options.output_buffer = packager->output_buffer;
|
|
2219
|
+
*self->options.output_buffer_size = packager->output_buffer_size;
|
|
2220
|
+
}
|
|
2221
|
+
|
|
1796
2222
|
/* Error and non-error conditions fall through to the cleanup code. */
|
|
1797
2223
|
if (error == LXW_ERROR_CREATING_TMPFILE) {
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
2224
|
+
LXW_PRINTF(LXW_STDERR "[ERROR] workbook_close(): "
|
|
2225
|
+
"Error creating tmpfile(s) to assemble '%s'. "
|
|
2226
|
+
"System error = %s\n", self->filename, strerror(errno));
|
|
1801
2227
|
}
|
|
1802
2228
|
|
|
1803
2229
|
/* If LXW_ERROR_ZIP_FILE_OPERATION then errno is set by zip. */
|
|
1804
2230
|
if (error == LXW_ERROR_ZIP_FILE_OPERATION) {
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
2231
|
+
LXW_PRINTF(LXW_STDERR "[ERROR] workbook_close(): "
|
|
2232
|
+
"Zip ZIP_ERRNO error while creating xlsx file '%s'. "
|
|
2233
|
+
"System error = %s\n", self->filename, strerror(errno));
|
|
1808
2234
|
}
|
|
1809
2235
|
|
|
1810
2236
|
/* If LXW_ERROR_ZIP_PARAMETER_ERROR then errno is set by zip. */
|
|
1811
2237
|
if (error == LXW_ERROR_ZIP_PARAMETER_ERROR) {
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
2238
|
+
LXW_PRINTF(LXW_STDERR "[ERROR] workbook_close(): "
|
|
2239
|
+
"Zip ZIP_PARAMERROR error while creating xlsx file '%s'. "
|
|
2240
|
+
"System error = %s\n", self->filename, strerror(errno));
|
|
1815
2241
|
}
|
|
1816
2242
|
|
|
1817
2243
|
/* If LXW_ERROR_ZIP_BAD_ZIP_FILE then errno is set by zip. */
|
|
1818
2244
|
if (error == LXW_ERROR_ZIP_BAD_ZIP_FILE) {
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
2245
|
+
LXW_PRINTF(LXW_STDERR "[ERROR] workbook_close(): "
|
|
2246
|
+
"Zip ZIP_BADZIPFILE error while creating xlsx file '%s'. "
|
|
2247
|
+
"This may require the use_zip64 option for large files. "
|
|
2248
|
+
"System error = %s\n", self->filename, strerror(errno));
|
|
1823
2249
|
}
|
|
1824
2250
|
|
|
1825
2251
|
/* If LXW_ERROR_ZIP_INTERNAL_ERROR then errno is set by zip. */
|
|
1826
2252
|
if (error == LXW_ERROR_ZIP_INTERNAL_ERROR) {
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
2253
|
+
LXW_PRINTF(LXW_STDERR "[ERROR] workbook_close(): "
|
|
2254
|
+
"Zip ZIP_INTERNALERROR error while creating xlsx file '%s'. "
|
|
2255
|
+
"System error = %s\n", self->filename, strerror(errno));
|
|
1830
2256
|
}
|
|
1831
2257
|
|
|
1832
2258
|
/* The next 2 error conditions don't set errno. */
|
|
1833
2259
|
if (error == LXW_ERROR_ZIP_FILE_ADD) {
|
|
1834
|
-
|
|
1835
|
-
|
|
2260
|
+
LXW_PRINTF(LXW_STDERR "[ERROR] workbook_close(): "
|
|
2261
|
+
"Zip error adding file to xlsx file '%s'.\n",
|
|
2262
|
+
self->filename);
|
|
1836
2263
|
}
|
|
1837
2264
|
|
|
1838
2265
|
if (error == LXW_ERROR_ZIP_CLOSE) {
|
|
1839
|
-
|
|
1840
|
-
|
|
2266
|
+
LXW_PRINTF(LXW_STDERR "[ERROR] workbook_close(): "
|
|
2267
|
+
"Zip error closing xlsx file '%s'.\n", self->filename);
|
|
1841
2268
|
}
|
|
1842
2269
|
|
|
1843
2270
|
mem_error:
|
|
@@ -1922,6 +2349,8 @@ workbook_set_properties(lxw_workbook *self, lxw_doc_properties *user_props)
|
|
|
1922
2349
|
GOTO_LABEL_ON_MEM_ERROR(doc_props->hyperlink_base, mem_error);
|
|
1923
2350
|
}
|
|
1924
2351
|
|
|
2352
|
+
doc_props->created = user_props->created;
|
|
2353
|
+
|
|
1925
2354
|
self->properties = doc_props;
|
|
1926
2355
|
|
|
1927
2356
|
return LXW_NO_ERROR;
|
|
@@ -2169,6 +2598,27 @@ workbook_get_chartsheet_by_name(lxw_workbook *self, const char *name)
|
|
|
2169
2598
|
return NULL;
|
|
2170
2599
|
}
|
|
2171
2600
|
|
|
2601
|
+
/*
|
|
2602
|
+
* Get the default URL format.
|
|
2603
|
+
*/
|
|
2604
|
+
lxw_format *
|
|
2605
|
+
workbook_get_default_url_format(lxw_workbook *self)
|
|
2606
|
+
{
|
|
2607
|
+
return self->default_url_format;
|
|
2608
|
+
}
|
|
2609
|
+
|
|
2610
|
+
/*
|
|
2611
|
+
* Unset the default URL format.
|
|
2612
|
+
*/
|
|
2613
|
+
void
|
|
2614
|
+
workbook_unset_default_url_format(lxw_workbook *self)
|
|
2615
|
+
{
|
|
2616
|
+
self->default_url_format->hyperlink = LXW_FALSE;
|
|
2617
|
+
self->default_url_format->xf_id = 0;
|
|
2618
|
+
self->default_url_format->underline = LXW_UNDERLINE_NONE;
|
|
2619
|
+
self->default_url_format->theme = 0;
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2172
2622
|
/*
|
|
2173
2623
|
* Validate the worksheet name based on Excel's rules.
|
|
2174
2624
|
*/
|
|
@@ -2187,10 +2637,6 @@ workbook_validate_sheet_name(lxw_workbook *self, const char *sheetname)
|
|
|
2187
2637
|
if (sheetname[0] == '\'' || sheetname[strlen(sheetname) - 1] == '\'')
|
|
2188
2638
|
return LXW_ERROR_SHEETNAME_START_END_APOSTROPHE;
|
|
2189
2639
|
|
|
2190
|
-
/* Check that the worksheet name isn't the reserved work "History". */
|
|
2191
|
-
if (lxw_strcasecmp(sheetname, "history") == 0)
|
|
2192
|
-
return LXW_ERROR_SHEETNAME_RESERVED;
|
|
2193
|
-
|
|
2194
2640
|
/* Check if the worksheet name is already in use. */
|
|
2195
2641
|
if (workbook_get_worksheet_by_name(self, sheetname))
|
|
2196
2642
|
return LXW_ERROR_SHEETNAME_ALREADY_USED;
|
|
@@ -2212,15 +2658,15 @@ workbook_add_vba_project(lxw_workbook *self, const char *filename)
|
|
|
2212
2658
|
|
|
2213
2659
|
if (!filename) {
|
|
2214
2660
|
LXW_WARN("workbook_add_vba_project(): "
|
|
2215
|
-
"filename must be specified.");
|
|
2661
|
+
"project filename must be specified.");
|
|
2216
2662
|
return LXW_ERROR_NULL_PARAMETER_IGNORED;
|
|
2217
2663
|
}
|
|
2218
2664
|
|
|
2219
2665
|
/* Check that the vbaProject file exists and can be opened. */
|
|
2220
|
-
filehandle =
|
|
2666
|
+
filehandle = lxw_fopen(filename, "rb");
|
|
2221
2667
|
if (!filehandle) {
|
|
2222
2668
|
LXW_WARN_FORMAT1("workbook_add_vba_project(): "
|
|
2223
|
-
"file doesn't exist or can't be opened: %s.",
|
|
2669
|
+
"project file doesn't exist or can't be opened: %s.",
|
|
2224
2670
|
filename);
|
|
2225
2671
|
return LXW_ERROR_PARAMETER_VALIDATION;
|
|
2226
2672
|
}
|
|
@@ -2231,6 +2677,41 @@ workbook_add_vba_project(lxw_workbook *self, const char *filename)
|
|
|
2231
2677
|
return LXW_NO_ERROR;
|
|
2232
2678
|
}
|
|
2233
2679
|
|
|
2680
|
+
/*
|
|
2681
|
+
* Add a vbaProject binary and a vbaProjectSignature binary to the Excel workbook.
|
|
2682
|
+
*/
|
|
2683
|
+
lxw_error
|
|
2684
|
+
workbook_add_signed_vba_project(lxw_workbook *self,
|
|
2685
|
+
const char *vba_project,
|
|
2686
|
+
const char *signature)
|
|
2687
|
+
{
|
|
2688
|
+
FILE *filehandle;
|
|
2689
|
+
|
|
2690
|
+
lxw_error error = workbook_add_vba_project(self, vba_project);
|
|
2691
|
+
if (error != LXW_NO_ERROR)
|
|
2692
|
+
return error;
|
|
2693
|
+
|
|
2694
|
+
if (!signature) {
|
|
2695
|
+
LXW_WARN("workbook_add_signed_vba_project(): "
|
|
2696
|
+
"signature filename must be specified.");
|
|
2697
|
+
return LXW_ERROR_NULL_PARAMETER_IGNORED;
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
/* Check that the vbaProjectSignature file exists and can be opened. */
|
|
2701
|
+
filehandle = lxw_fopen(signature, "rb");
|
|
2702
|
+
if (!filehandle) {
|
|
2703
|
+
LXW_WARN_FORMAT1("workbook_add_signed_vba_project(): "
|
|
2704
|
+
"signature file doesn't exist or can't be opened: %s.",
|
|
2705
|
+
signature);
|
|
2706
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
|
2707
|
+
}
|
|
2708
|
+
fclose(filehandle);
|
|
2709
|
+
|
|
2710
|
+
self->vba_project_signature = lxw_strdup(signature);
|
|
2711
|
+
|
|
2712
|
+
return LXW_NO_ERROR;
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2234
2715
|
/*
|
|
2235
2716
|
* Set the VBA name for the workbook.
|
|
2236
2717
|
*/
|
|
@@ -2246,3 +2727,12 @@ workbook_set_vba_name(lxw_workbook *self, const char *name)
|
|
|
2246
2727
|
|
|
2247
2728
|
return LXW_NO_ERROR;
|
|
2248
2729
|
}
|
|
2730
|
+
|
|
2731
|
+
/*
|
|
2732
|
+
* Set the Excel "Read-only recommended" save option.
|
|
2733
|
+
*/
|
|
2734
|
+
void
|
|
2735
|
+
workbook_read_only_recommended(lxw_workbook *self)
|
|
2736
|
+
{
|
|
2737
|
+
self->read_only = 2;
|
|
2738
|
+
}
|