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.
- 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
|
+
}
|