fast_excel 0.2.6 → 0.3.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/.dockerignore +2 -0
- data/.gitignore +3 -0
- data/.travis.yml +18 -6
- data/CHANGELOG.md +14 -1
- data/Dockerfile.test +16 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +21 -21
- data/Makefile +13 -2
- data/README.md +148 -38
- data/Rakefile +2 -0
- data/examples/example.rb +3 -3
- data/examples/example_filters.rb +36 -0
- data/examples/example_formula.rb +1 -3
- data/examples/example_hyperlink.rb +20 -0
- data/fast_excel.gemspec +1 -1
- data/lib/fast_excel.rb +36 -12
- data/lib/fast_excel/binding.rb +31 -21
- data/lib/fast_excel/binding/chart.rb +20 -1
- data/lib/fast_excel/binding/workbook.rb +10 -2
- data/lib/fast_excel/binding/worksheet.rb +44 -27
- data/libxlsxwriter/.gitignore +1 -0
- data/libxlsxwriter/.indent.pro +5 -0
- data/libxlsxwriter/CMakeLists.txt +1 -11
- data/libxlsxwriter/CONTRIBUTING.md +1 -1
- data/libxlsxwriter/Changes.txt +84 -0
- data/libxlsxwriter/LICENSE.txt +1 -1
- data/libxlsxwriter/Makefile +7 -5
- data/libxlsxwriter/Readme.md +1 -1
- data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +1 -0
- data/libxlsxwriter/include/xlsxwriter.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/app.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/chart.h +56 -6
- data/libxlsxwriter/include/xlsxwriter/chartsheet.h +544 -0
- data/libxlsxwriter/include/xlsxwriter/common.h +27 -6
- data/libxlsxwriter/include/xlsxwriter/content_types.h +5 -2
- data/libxlsxwriter/include/xlsxwriter/core.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/custom.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/drawing.h +3 -2
- data/libxlsxwriter/include/xlsxwriter/format.h +3 -3
- data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/packager.h +13 -8
- data/libxlsxwriter/include/xlsxwriter/relationships.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/shared_strings.h +5 -3
- data/libxlsxwriter/include/xlsxwriter/styles.h +9 -4
- data/libxlsxwriter/include/xlsxwriter/theme.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/utility.h +26 -2
- data/libxlsxwriter/include/xlsxwriter/workbook.h +232 -55
- data/libxlsxwriter/include/xlsxwriter/worksheet.h +264 -53
- data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +3 -1
- data/libxlsxwriter/libxlsxwriter.podspec +1 -1
- data/libxlsxwriter/src/Makefile +3 -3
- data/libxlsxwriter/src/app.c +2 -2
- data/libxlsxwriter/src/chart.c +41 -5
- data/libxlsxwriter/src/chartsheet.c +508 -0
- data/libxlsxwriter/src/content_types.c +12 -4
- data/libxlsxwriter/src/core.c +2 -2
- data/libxlsxwriter/src/custom.c +2 -2
- data/libxlsxwriter/src/drawing.c +114 -17
- data/libxlsxwriter/src/format.c +3 -3
- data/libxlsxwriter/src/hash_table.c +1 -1
- data/libxlsxwriter/src/packager.c +369 -65
- data/libxlsxwriter/src/relationships.c +2 -2
- data/libxlsxwriter/src/shared_strings.c +18 -4
- data/libxlsxwriter/src/styles.c +56 -9
- data/libxlsxwriter/src/theme.c +2 -2
- data/libxlsxwriter/src/utility.c +53 -6
- data/libxlsxwriter/src/workbook.c +372 -56
- data/libxlsxwriter/src/worksheet.c +425 -76
- data/libxlsxwriter/src/xmlwriter.c +17 -8
- data/libxlsxwriter/third_party/minizip/ioapi.c +10 -0
- data/libxlsxwriter/third_party/minizip/zip.c +2 -0
- data/libxlsxwriter/third_party/tmpfileplus/tmpfileplus.c +2 -2
- data/libxlsxwriter/version.txt +1 -1
- data/test/tmpfile_test.rb +1 -0
- data/test/validations_test.rb +26 -6
- data/test/worksheet_test.rb +43 -0
- metadata +9 -6
- data/libxlsxwriter/.drone.yml +0 -27
- data/libxlsxwriter/appveyor.yml +0 -65
- data/libxlsxwriter/cmake/FindZLIB.cmake +0 -123
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -26,7 +26,7 @@
|
|
26
26
|
* Create a new relationships object.
|
27
27
|
*/
|
28
28
|
lxw_relationships *
|
29
|
-
lxw_relationships_new()
|
29
|
+
lxw_relationships_new(void)
|
30
30
|
{
|
31
31
|
lxw_relationships *rels = calloc(1, sizeof(lxw_relationships));
|
32
32
|
GOTO_LABEL_ON_MEM_ERROR(rels, mem_error);
|
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -34,7 +34,7 @@ LXW_RB_GENERATE_ELEMENT(sst_rb_tree, sst_element, sst_tree_pointers,
|
|
34
34
|
* Create a new SST SharedString object.
|
35
35
|
*/
|
36
36
|
lxw_sst *
|
37
|
-
lxw_sst_new()
|
37
|
+
lxw_sst_new(void)
|
38
38
|
{
|
39
39
|
/* Create the new shared string table. */
|
40
40
|
lxw_sst *sst = calloc(1, sizeof(lxw_sst));
|
@@ -161,6 +161,15 @@ _write_si(lxw_sst *self, char *string)
|
|
161
161
|
free(string);
|
162
162
|
}
|
163
163
|
|
164
|
+
/*
|
165
|
+
* Write the <si> element for rich strings.
|
166
|
+
*/
|
167
|
+
STATIC void
|
168
|
+
_write_rich_si(lxw_sst *self, char *string)
|
169
|
+
{
|
170
|
+
lxw_xml_rich_si_element(self->file, string);
|
171
|
+
}
|
172
|
+
|
164
173
|
/*
|
165
174
|
* Write the <sst> element.
|
166
175
|
*/
|
@@ -198,7 +207,11 @@ _write_sst_strings(lxw_sst *self)
|
|
198
207
|
|
199
208
|
STAILQ_FOREACH(sst_element, self->order_list, sst_order_pointers) {
|
200
209
|
/* Write the si element. */
|
201
|
-
|
210
|
+
if (sst_element->is_rich_string)
|
211
|
+
_write_rich_si(self, sst_element->string);
|
212
|
+
else
|
213
|
+
_write_si(self, sst_element->string);
|
214
|
+
|
202
215
|
}
|
203
216
|
}
|
204
217
|
|
@@ -230,7 +243,7 @@ lxw_sst_assemble_xml_file(lxw_sst *self)
|
|
230
243
|
* Add to or find a string in the SST SharedString table and return it's index.
|
231
244
|
*/
|
232
245
|
struct sst_element *
|
233
|
-
lxw_get_sst_index(lxw_sst *sst, const char *string)
|
246
|
+
lxw_get_sst_index(lxw_sst *sst, const char *string, uint8_t is_rich_string)
|
234
247
|
{
|
235
248
|
struct sst_element *element;
|
236
249
|
struct sst_element *existing_element;
|
@@ -243,6 +256,7 @@ lxw_get_sst_index(lxw_sst *sst, const char *string)
|
|
243
256
|
/* Create potential new element with the string and its index. */
|
244
257
|
element->index = sst->unique_count;
|
245
258
|
element->string = lxw_strdup(string);
|
259
|
+
element->is_rich_string = is_rich_string;
|
246
260
|
|
247
261
|
/* Try to insert it and see whether we already have that string. */
|
248
262
|
existing_element = RB_INSERT(sst_rb_tree, sst->rb_tree, element);
|
data/libxlsxwriter/src/styles.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -14,6 +14,8 @@
|
|
14
14
|
/*
|
15
15
|
* Forward declarations.
|
16
16
|
*/
|
17
|
+
STATIC void _write_font(lxw_styles *self, lxw_format *format,
|
18
|
+
uint8_t is_rich_string);
|
17
19
|
|
18
20
|
/*****************************************************************************
|
19
21
|
*
|
@@ -25,7 +27,7 @@
|
|
25
27
|
* Create a new styles object.
|
26
28
|
*/
|
27
29
|
lxw_styles *
|
28
|
-
lxw_styles_new()
|
30
|
+
lxw_styles_new(void)
|
29
31
|
{
|
30
32
|
lxw_styles *styles = calloc(1, sizeof(lxw_styles));
|
31
33
|
GOTO_LABEL_ON_MEM_ERROR(styles, mem_error);
|
@@ -66,6 +68,34 @@ lxw_styles_free(lxw_styles *styles)
|
|
66
68
|
free(styles);
|
67
69
|
}
|
68
70
|
|
71
|
+
/*
|
72
|
+
* Write the <t> element for rich strings.
|
73
|
+
*/
|
74
|
+
void
|
75
|
+
lxw_styles_write_string_fragment(lxw_styles *self, char *string)
|
76
|
+
{
|
77
|
+
struct xml_attribute_list attributes;
|
78
|
+
struct xml_attribute *attribute;
|
79
|
+
|
80
|
+
LXW_INIT_ATTRIBUTES();
|
81
|
+
|
82
|
+
/* Add attribute to preserve leading or trailing whitespace. */
|
83
|
+
if (isspace((unsigned char) string[0])
|
84
|
+
|| isspace((unsigned char) string[strlen(string) - 1]))
|
85
|
+
LXW_PUSH_ATTRIBUTES_STR("xml:space", "preserve");
|
86
|
+
|
87
|
+
lxw_xml_data_element(self->file, "t", string, &attributes);
|
88
|
+
|
89
|
+
LXW_FREE_ATTRIBUTES();
|
90
|
+
}
|
91
|
+
|
92
|
+
void
|
93
|
+
lxw_styles_write_rich_font(lxw_styles *self, lxw_format *format)
|
94
|
+
{
|
95
|
+
|
96
|
+
_write_font(self, format, LXW_TRUE);
|
97
|
+
}
|
98
|
+
|
69
99
|
/*****************************************************************************
|
70
100
|
*
|
71
101
|
* XML functions.
|
@@ -125,6 +155,7 @@ _write_num_fmts(lxw_styles *self)
|
|
125
155
|
struct xml_attribute_list attributes;
|
126
156
|
struct xml_attribute *attribute;
|
127
157
|
lxw_format *format;
|
158
|
+
uint16_t last_format_index = 0;
|
128
159
|
|
129
160
|
if (!self->num_format_count)
|
130
161
|
return;
|
@@ -141,7 +172,13 @@ _write_num_fmts(lxw_styles *self)
|
|
141
172
|
if (format->num_format_index < 164)
|
142
173
|
continue;
|
143
174
|
|
175
|
+
/* Ignore duplicates which have an already used index. */
|
176
|
+
if (format->num_format_index <= last_format_index)
|
177
|
+
continue;
|
178
|
+
|
144
179
|
_write_num_fmt(self, format->num_format_index, format->num_format);
|
180
|
+
|
181
|
+
last_format_index = format->num_format_index;
|
145
182
|
}
|
146
183
|
|
147
184
|
lxw_xml_end_tag(self->file, "numFmts");
|
@@ -207,7 +244,8 @@ _write_font_color_rgb(lxw_styles *self, int32_t rgb)
|
|
207
244
|
* Write the <name> element.
|
208
245
|
*/
|
209
246
|
STATIC void
|
210
|
-
_write_font_name(lxw_styles *self, const char *font_name
|
247
|
+
_write_font_name(lxw_styles *self, const char *font_name,
|
248
|
+
uint8_t is_rich_string)
|
211
249
|
{
|
212
250
|
struct xml_attribute_list attributes;
|
213
251
|
struct xml_attribute *attribute;
|
@@ -219,7 +257,10 @@ _write_font_name(lxw_styles *self, const char *font_name)
|
|
219
257
|
else
|
220
258
|
LXW_PUSH_ATTRIBUTES_STR("val", LXW_DEFAULT_FONT_NAME);
|
221
259
|
|
222
|
-
|
260
|
+
if (is_rich_string)
|
261
|
+
lxw_xml_empty_tag(self->file, "rFont", &attributes);
|
262
|
+
else
|
263
|
+
lxw_xml_empty_tag(self->file, "name", &attributes);
|
223
264
|
|
224
265
|
LXW_FREE_ATTRIBUTES();
|
225
266
|
}
|
@@ -309,9 +350,12 @@ _write_vert_align(lxw_styles *self, const char *align)
|
|
309
350
|
* Write the <font> element.
|
310
351
|
*/
|
311
352
|
STATIC void
|
312
|
-
_write_font(lxw_styles *self, lxw_format *format)
|
353
|
+
_write_font(lxw_styles *self, lxw_format *format, uint8_t is_rich_string)
|
313
354
|
{
|
314
|
-
|
355
|
+
if (is_rich_string)
|
356
|
+
lxw_xml_start_tag(self->file, "rPr", NULL);
|
357
|
+
else
|
358
|
+
lxw_xml_start_tag(self->file, "font", NULL);
|
315
359
|
|
316
360
|
if (format->bold)
|
317
361
|
lxw_xml_empty_tag(self->file, "b", NULL);
|
@@ -347,7 +391,7 @@ _write_font(lxw_styles *self, lxw_format *format)
|
|
347
391
|
else
|
348
392
|
_write_font_color_theme(self, LXW_DEFAULT_FONT_THEME);
|
349
393
|
|
350
|
-
_write_font_name(self, format->font_name);
|
394
|
+
_write_font_name(self, format->font_name, is_rich_string);
|
351
395
|
_write_font_family(self, format->font_family);
|
352
396
|
|
353
397
|
/* Only write the scheme element for the default font type if it
|
@@ -358,7 +402,10 @@ _write_font(lxw_styles *self, lxw_format *format)
|
|
358
402
|
_write_font_scheme(self, format->font_scheme);
|
359
403
|
}
|
360
404
|
|
361
|
-
|
405
|
+
if (is_rich_string)
|
406
|
+
lxw_xml_end_tag(self->file, "rPr");
|
407
|
+
else
|
408
|
+
lxw_xml_end_tag(self->file, "font");
|
362
409
|
}
|
363
410
|
|
364
411
|
/*
|
@@ -378,7 +425,7 @@ _write_fonts(lxw_styles *self)
|
|
378
425
|
|
379
426
|
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
|
380
427
|
if (format->has_font)
|
381
|
-
_write_font(self, format);
|
428
|
+
_write_font(self, format, LXW_FALSE);
|
382
429
|
}
|
383
430
|
|
384
431
|
lxw_xml_end_tag(self->file, "fonts");
|
data/libxlsxwriter/src/theme.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -289,7 +289,7 @@ const char *theme_strs[] = {
|
|
289
289
|
* Create a new theme object.
|
290
290
|
*/
|
291
291
|
lxw_theme *
|
292
|
-
lxw_theme_new()
|
292
|
+
lxw_theme_new(void)
|
293
293
|
{
|
294
294
|
lxw_theme *theme = calloc(1, sizeof(lxw_theme));
|
295
295
|
GOTO_LABEL_ON_MEM_ERROR(theme, mem_error);
|
data/libxlsxwriter/src/utility.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -12,7 +12,7 @@
|
|
12
12
|
#include <string.h>
|
13
13
|
#include <stdint.h>
|
14
14
|
#include <stdlib.h>
|
15
|
-
#include "xlsxwriter
|
15
|
+
#include "xlsxwriter.h"
|
16
16
|
#include "xlsxwriter/third_party/tmpfileplus.h"
|
17
17
|
|
18
18
|
char *error_strings[LXW_MAX_ERRNO + 1] = {
|
@@ -20,14 +20,20 @@ char *error_strings[LXW_MAX_ERRNO + 1] = {
|
|
20
20
|
"Memory error, failed to malloc() required memory.",
|
21
21
|
"Error creating output xlsx file. Usually a permissions error.",
|
22
22
|
"Error encountered when creating a tmpfile during file assembly.",
|
23
|
-
"
|
24
|
-
"
|
25
|
-
"
|
23
|
+
"Error reading a tmpfile.",
|
24
|
+
"Zip generic error ZIP_ERRNO while creating the xlsx file.",
|
25
|
+
"Zip error ZIP_PARAMERROR while creating the xlsx file.",
|
26
|
+
"Zip error ZIP_BADZIPFILE (use_zip64 option may be required).",
|
27
|
+
"Zip error ZIP_INTERNALERROR while creating the xlsx file.",
|
28
|
+
"File error or unknown zip error when adding sub file to xlsx file.",
|
29
|
+
"Unknown zip error when closing xlsx file.",
|
26
30
|
"NULL function parameter ignored.",
|
27
31
|
"Function parameter validation error.",
|
28
32
|
"Worksheet name exceeds Excel's limit of 31 characters.",
|
29
|
-
"Worksheet name
|
33
|
+
"Worksheet name cannot contain invalid characters: '[ ] : * ? / \\'",
|
34
|
+
"Worksheet name cannot start or end with an apostrophe.",
|
30
35
|
"Worksheet name is already in use.",
|
36
|
+
"Worksheet name 'History' is reserved by Excel.",
|
31
37
|
"Parameter exceeds Excel's limit of 32 characters.",
|
32
38
|
"Parameter exceeds Excel's limit of 128 characters.",
|
33
39
|
"Parameter exceeds Excel's limit of 255 characters.",
|
@@ -553,3 +559,44 @@ lxw_sprintf_dbl(char *data, double number)
|
|
553
559
|
return 0;
|
554
560
|
}
|
555
561
|
#endif
|
562
|
+
|
563
|
+
/*
|
564
|
+
* Retrieve runtime library version
|
565
|
+
*/
|
566
|
+
const char *
|
567
|
+
lxw_version(void)
|
568
|
+
{
|
569
|
+
return LXW_VERSION;
|
570
|
+
}
|
571
|
+
|
572
|
+
/*
|
573
|
+
* Hash a worksheet password. Based on the algorithm provided by Daniel Rentz
|
574
|
+
* of OpenOffice.
|
575
|
+
*/
|
576
|
+
uint16_t
|
577
|
+
lxw_hash_password(const char *password)
|
578
|
+
{
|
579
|
+
size_t count;
|
580
|
+
uint8_t i;
|
581
|
+
uint16_t hash = 0x0000;
|
582
|
+
|
583
|
+
count = strlen(password);
|
584
|
+
|
585
|
+
for (i = 0; i < count; i++) {
|
586
|
+
uint32_t low_15;
|
587
|
+
uint32_t high_15;
|
588
|
+
uint32_t letter = password[i] << (i + 1);
|
589
|
+
|
590
|
+
low_15 = letter & 0x7fff;
|
591
|
+
high_15 = letter & (0x7fff << 15);
|
592
|
+
high_15 = high_15 >> 15;
|
593
|
+
letter = low_15 | high_15;
|
594
|
+
|
595
|
+
hash ^= letter;
|
596
|
+
}
|
597
|
+
|
598
|
+
hash ^= count;
|
599
|
+
hash ^= 0xCE4B;
|
600
|
+
|
601
|
+
return hash;
|
602
|
+
}
|
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -13,10 +13,15 @@
|
|
13
13
|
#include "xlsxwriter/packager.h"
|
14
14
|
#include "xlsxwriter/hash_table.h"
|
15
15
|
|
16
|
-
STATIC int
|
16
|
+
STATIC int _worksheet_name_cmp(lxw_worksheet_name *name1,
|
17
|
+
lxw_worksheet_name *name2);
|
18
|
+
STATIC int _chartsheet_name_cmp(lxw_chartsheet_name *name1,
|
19
|
+
lxw_chartsheet_name *name2);
|
17
20
|
#ifndef __clang_analyzer__
|
18
|
-
|
19
|
-
|
21
|
+
LXW_RB_GENERATE_WORKSHEET_NAMES(lxw_worksheet_names, lxw_worksheet_name,
|
22
|
+
tree_pointers, _worksheet_name_cmp);
|
23
|
+
LXW_RB_GENERATE_CHARTSHEET_NAMES(lxw_chartsheet_names, lxw_chartsheet_name,
|
24
|
+
tree_pointers, _chartsheet_name_cmp);
|
20
25
|
#endif
|
21
26
|
|
22
27
|
/*
|
@@ -30,12 +35,18 @@ LXW_RB_GENERATE_NAMES(lxw_worksheet_names, lxw_worksheet_name, tree_pointers,
|
|
30
35
|
****************************************************************************/
|
31
36
|
|
32
37
|
/*
|
33
|
-
*
|
38
|
+
* Comparators for the sheet names structure red/black tree.
|
34
39
|
*/
|
35
40
|
STATIC int
|
36
|
-
|
41
|
+
_worksheet_name_cmp(lxw_worksheet_name *name1, lxw_worksheet_name *name2)
|
37
42
|
{
|
38
|
-
return
|
43
|
+
return lxw_strcasecmp(name1->name, name2->name);
|
44
|
+
}
|
45
|
+
|
46
|
+
STATIC int
|
47
|
+
_chartsheet_name_cmp(lxw_chartsheet_name *name1, lxw_chartsheet_name *name2)
|
48
|
+
{
|
49
|
+
return lxw_strcasecmp(name1->name, name2->name);
|
39
50
|
}
|
40
51
|
|
41
52
|
/*
|
@@ -81,9 +92,11 @@ _free_custom_doc_property(lxw_custom_property *custom_property)
|
|
81
92
|
void
|
82
93
|
lxw_workbook_free(lxw_workbook *workbook)
|
83
94
|
{
|
84
|
-
|
95
|
+
lxw_sheet *sheet;
|
85
96
|
struct lxw_worksheet_name *worksheet_name;
|
86
|
-
struct lxw_worksheet_name *
|
97
|
+
struct lxw_worksheet_name *next_worksheet_name;
|
98
|
+
struct lxw_chartsheet_name *chartsheet_name;
|
99
|
+
struct lxw_chartsheet_name *next_chartsheet_name;
|
87
100
|
lxw_chart *chart;
|
88
101
|
lxw_format *format;
|
89
102
|
lxw_defined_name *defined_name;
|
@@ -97,17 +110,26 @@ lxw_workbook_free(lxw_workbook *workbook)
|
|
97
110
|
|
98
111
|
free(workbook->filename);
|
99
112
|
|
100
|
-
/* Free the
|
101
|
-
if (workbook->
|
102
|
-
while (!STAILQ_EMPTY(workbook->
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
113
|
+
/* Free the sheets in the workbook. */
|
114
|
+
if (workbook->sheets) {
|
115
|
+
while (!STAILQ_EMPTY(workbook->sheets)) {
|
116
|
+
sheet = STAILQ_FIRST(workbook->sheets);
|
117
|
+
|
118
|
+
if (sheet->is_chartsheet)
|
119
|
+
lxw_chartsheet_free(sheet->u.chartsheet);
|
120
|
+
else
|
121
|
+
lxw_worksheet_free(sheet->u.worksheet);
|
108
122
|
|
123
|
+
STAILQ_REMOVE_HEAD(workbook->sheets, list_pointers);
|
124
|
+
free(sheet);
|
125
|
+
}
|
126
|
+
free(workbook->sheets);
|
109
127
|
}
|
110
128
|
|
129
|
+
/* Free the sheet lists. The worksheet objects are freed above. */
|
130
|
+
free(workbook->worksheets);
|
131
|
+
free(workbook->chartsheets);
|
132
|
+
|
111
133
|
/* Free the charts in the workbook. */
|
112
134
|
if (workbook->charts) {
|
113
135
|
while (!STAILQ_EMPTY(workbook->charts)) {
|
@@ -153,22 +175,41 @@ lxw_workbook_free(lxw_workbook *workbook)
|
|
153
175
|
if (workbook->worksheet_names) {
|
154
176
|
for (worksheet_name =
|
155
177
|
RB_MIN(lxw_worksheet_names, workbook->worksheet_names);
|
156
|
-
worksheet_name; worksheet_name =
|
178
|
+
worksheet_name; worksheet_name = next_worksheet_name) {
|
157
179
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
180
|
+
next_worksheet_name = RB_NEXT(lxw_worksheet_names,
|
181
|
+
workbook->worksheet_name,
|
182
|
+
worksheet_name);
|
183
|
+
RB_REMOVE(lxw_worksheet_names, workbook->worksheet_names,
|
184
|
+
worksheet_name);
|
162
185
|
free(worksheet_name);
|
163
186
|
}
|
164
187
|
|
165
188
|
free(workbook->worksheet_names);
|
166
189
|
}
|
167
190
|
|
191
|
+
if (workbook->chartsheet_names) {
|
192
|
+
for (chartsheet_name =
|
193
|
+
RB_MIN(lxw_chartsheet_names, workbook->chartsheet_names);
|
194
|
+
chartsheet_name; chartsheet_name = next_chartsheet_name) {
|
195
|
+
|
196
|
+
next_chartsheet_name = RB_NEXT(lxw_chartsheet_names,
|
197
|
+
workbook->chartsheet_name,
|
198
|
+
chartsheet_name);
|
199
|
+
RB_REMOVE(lxw_chartsheet_names, workbook->chartsheet_names,
|
200
|
+
chartsheet_name);
|
201
|
+
free(chartsheet_name);
|
202
|
+
}
|
203
|
+
|
204
|
+
free(workbook->chartsheet_names);
|
205
|
+
}
|
206
|
+
|
168
207
|
lxw_hash_free(workbook->used_xf_formats);
|
169
208
|
lxw_sst_free(workbook->sst);
|
170
209
|
free(workbook->options.tmpdir);
|
171
210
|
free(workbook->ordered_charts);
|
211
|
+
free(workbook->vba_project);
|
212
|
+
free(workbook->vba_codename);
|
172
213
|
free(workbook);
|
173
214
|
}
|
174
215
|
|
@@ -432,7 +473,7 @@ _prepare_num_formats(lxw_workbook *self)
|
|
432
473
|
num_format_index = calloc(1, sizeof(uint16_t));
|
433
474
|
*num_format_index = index;
|
434
475
|
format->num_format_index = index;
|
435
|
-
lxw_insert_hash_element(num_formats, num_format,
|
476
|
+
lxw_insert_hash_element(num_formats, format->num_format,
|
436
477
|
num_format_index,
|
437
478
|
LXW_FORMAT_FIELD_LEN);
|
438
479
|
index++;
|
@@ -496,6 +537,7 @@ _store_defined_name(lxw_workbook *self, const char *name,
|
|
496
537
|
const char *app_name, const char *formula, int16_t index,
|
497
538
|
uint8_t hidden)
|
498
539
|
{
|
540
|
+
lxw_sheet *sheet;
|
499
541
|
lxw_worksheet *worksheet;
|
500
542
|
lxw_defined_name *defined_name;
|
501
543
|
lxw_defined_name *list_defined_name;
|
@@ -546,7 +588,12 @@ _store_defined_name(lxw_workbook *self, const char *name,
|
|
546
588
|
worksheet_name[strlen(worksheet_name) - 1] = '\0';
|
547
589
|
|
548
590
|
/* Search for worksheet name to get the equivalent worksheet index. */
|
549
|
-
STAILQ_FOREACH(
|
591
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
592
|
+
if (sheet->is_chartsheet)
|
593
|
+
continue;
|
594
|
+
else
|
595
|
+
worksheet = sheet->u.worksheet;
|
596
|
+
|
550
597
|
if (strcmp(worksheet_name, worksheet->name) == 0) {
|
551
598
|
defined_name->index = worksheet->index;
|
552
599
|
lxw_strcpy(defined_name->normalised_sheetname,
|
@@ -837,13 +884,23 @@ _add_chart_cache_data(lxw_workbook *self)
|
|
837
884
|
STATIC void
|
838
885
|
_prepare_drawings(lxw_workbook *self)
|
839
886
|
{
|
887
|
+
lxw_sheet *sheet;
|
840
888
|
lxw_worksheet *worksheet;
|
841
889
|
lxw_image_options *image_options;
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
890
|
+
uint32_t chart_ref_id = 0;
|
891
|
+
uint32_t image_ref_id = 0;
|
892
|
+
uint32_t drawing_id = 0;
|
893
|
+
uint8_t is_chartsheet;
|
894
|
+
|
895
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
896
|
+
if (sheet->is_chartsheet) {
|
897
|
+
worksheet = sheet->u.chartsheet->worksheet;
|
898
|
+
is_chartsheet = LXW_TRUE;
|
899
|
+
}
|
900
|
+
else {
|
901
|
+
worksheet = sheet->u.worksheet;
|
902
|
+
is_chartsheet = LXW_FALSE;
|
903
|
+
}
|
847
904
|
|
848
905
|
if (STAILQ_EMPTY(worksheet->image_data)
|
849
906
|
&& STAILQ_EMPTY(worksheet->chart_data))
|
@@ -854,7 +911,7 @@ _prepare_drawings(lxw_workbook *self)
|
|
854
911
|
STAILQ_FOREACH(image_options, worksheet->chart_data, list_pointers) {
|
855
912
|
chart_ref_id++;
|
856
913
|
lxw_worksheet_prepare_chart(worksheet, chart_ref_id, drawing_id,
|
857
|
-
image_options);
|
914
|
+
image_options, is_chartsheet);
|
858
915
|
if (image_options->chart)
|
859
916
|
STAILQ_INSERT_TAIL(self->ordered_charts, image_options->chart,
|
860
917
|
ordered_list_pointers);
|
@@ -889,14 +946,18 @@ STATIC void
|
|
889
946
|
_prepare_defined_names(lxw_workbook *self)
|
890
947
|
{
|
891
948
|
lxw_worksheet *worksheet;
|
949
|
+
lxw_sheet *sheet;
|
892
950
|
char app_name[LXW_DEFINED_NAME_LENGTH];
|
893
951
|
char range[LXW_DEFINED_NAME_LENGTH];
|
894
952
|
char area[LXW_MAX_CELL_RANGE_LENGTH];
|
895
953
|
char first_col[8];
|
896
954
|
char last_col[8];
|
897
955
|
|
898
|
-
STAILQ_FOREACH(
|
899
|
-
|
956
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
957
|
+
if (sheet->is_chartsheet)
|
958
|
+
continue;
|
959
|
+
else
|
960
|
+
worksheet = sheet->u.worksheet;
|
900
961
|
/*
|
901
962
|
* Check for autofilter settings and store them.
|
902
963
|
*/
|
@@ -1076,6 +1137,10 @@ _write_file_version(lxw_workbook *self)
|
|
1076
1137
|
LXW_PUSH_ATTRIBUTES_STR("lowestEdited", "4");
|
1077
1138
|
LXW_PUSH_ATTRIBUTES_STR("rupBuild", "4505");
|
1078
1139
|
|
1140
|
+
if (self->vba_project)
|
1141
|
+
LXW_PUSH_ATTRIBUTES_STR("codeName",
|
1142
|
+
"{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}");
|
1143
|
+
|
1079
1144
|
lxw_xml_empty_tag(self->file, "fileVersion", &attributes);
|
1080
1145
|
|
1081
1146
|
LXW_FREE_ATTRIBUTES();
|
@@ -1091,6 +1156,10 @@ _write_workbook_pr(lxw_workbook *self)
|
|
1091
1156
|
struct xml_attribute *attribute;
|
1092
1157
|
|
1093
1158
|
LXW_INIT_ATTRIBUTES();
|
1159
|
+
|
1160
|
+
if (self->vba_codename)
|
1161
|
+
LXW_PUSH_ATTRIBUTES_STR("codeName", self->vba_codename);
|
1162
|
+
|
1094
1163
|
LXW_PUSH_ATTRIBUTES_STR("defaultThemeVersion", "124226");
|
1095
1164
|
|
1096
1165
|
lxw_xml_empty_tag(self->file, "workbookPr", &attributes);
|
@@ -1170,13 +1239,23 @@ _write_sheet(lxw_workbook *self, const char *name, uint32_t sheet_id,
|
|
1170
1239
|
STATIC void
|
1171
1240
|
_write_sheets(lxw_workbook *self)
|
1172
1241
|
{
|
1242
|
+
lxw_sheet *sheet;
|
1173
1243
|
lxw_worksheet *worksheet;
|
1244
|
+
lxw_chartsheet *chartsheet;
|
1174
1245
|
|
1175
1246
|
lxw_xml_start_tag(self->file, "sheets", NULL);
|
1176
1247
|
|
1177
|
-
STAILQ_FOREACH(
|
1178
|
-
|
1179
|
-
|
1248
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
1249
|
+
if (sheet->is_chartsheet) {
|
1250
|
+
chartsheet = sheet->u.chartsheet;
|
1251
|
+
_write_sheet(self, chartsheet->name, chartsheet->index + 1,
|
1252
|
+
chartsheet->hidden);
|
1253
|
+
}
|
1254
|
+
else {
|
1255
|
+
worksheet = sheet->u.worksheet;
|
1256
|
+
_write_sheet(self, worksheet->name, worksheet->index + 1,
|
1257
|
+
worksheet->hidden);
|
1258
|
+
}
|
1180
1259
|
}
|
1181
1260
|
|
1182
1261
|
lxw_xml_end_tag(self->file, "sheets");
|
@@ -1224,9 +1303,6 @@ _write_defined_name(lxw_workbook *self, lxw_defined_name *defined_name)
|
|
1224
1303
|
LXW_FREE_ATTRIBUTES();
|
1225
1304
|
}
|
1226
1305
|
|
1227
|
-
/*
|
1228
|
-
* Write the <definedNames> element.
|
1229
|
-
*/
|
1230
1306
|
STATIC void
|
1231
1307
|
_write_defined_names(lxw_workbook *self)
|
1232
1308
|
{
|
@@ -1330,16 +1406,32 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
|
1330
1406
|
GOTO_LABEL_ON_MEM_ERROR(workbook, mem_error);
|
1331
1407
|
workbook->filename = lxw_strdup(filename);
|
1332
1408
|
|
1409
|
+
/* Add the sheets list. */
|
1410
|
+
workbook->sheets = calloc(1, sizeof(struct lxw_sheets));
|
1411
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->sheets, mem_error);
|
1412
|
+
STAILQ_INIT(workbook->sheets);
|
1413
|
+
|
1333
1414
|
/* Add the worksheets list. */
|
1334
1415
|
workbook->worksheets = calloc(1, sizeof(struct lxw_worksheets));
|
1335
1416
|
GOTO_LABEL_ON_MEM_ERROR(workbook->worksheets, mem_error);
|
1336
1417
|
STAILQ_INIT(workbook->worksheets);
|
1337
1418
|
|
1419
|
+
/* Add the chartsheets list. */
|
1420
|
+
workbook->chartsheets = calloc(1, sizeof(struct lxw_chartsheets));
|
1421
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->chartsheets, mem_error);
|
1422
|
+
STAILQ_INIT(workbook->chartsheets);
|
1423
|
+
|
1338
1424
|
/* Add the worksheet names tree. */
|
1339
1425
|
workbook->worksheet_names = calloc(1, sizeof(struct lxw_worksheet_names));
|
1340
1426
|
GOTO_LABEL_ON_MEM_ERROR(workbook->worksheet_names, mem_error);
|
1341
1427
|
RB_INIT(workbook->worksheet_names);
|
1342
1428
|
|
1429
|
+
/* Add the chartsheet names tree. */
|
1430
|
+
workbook->chartsheet_names = calloc(1,
|
1431
|
+
sizeof(struct lxw_chartsheet_names));
|
1432
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->chartsheet_names, mem_error);
|
1433
|
+
RB_INIT(workbook->chartsheet_names);
|
1434
|
+
|
1343
1435
|
/* Add the charts list. */
|
1344
1436
|
workbook->charts = calloc(1, sizeof(struct lxw_charts));
|
1345
1437
|
GOTO_LABEL_ON_MEM_ERROR(workbook->charts, mem_error);
|
@@ -1388,6 +1480,7 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
|
1388
1480
|
if (options) {
|
1389
1481
|
workbook->options.constant_memory = options->constant_memory;
|
1390
1482
|
workbook->options.tmpdir = lxw_strdup(options->tmpdir);
|
1483
|
+
workbook->options.use_zip64 = options->use_zip64;
|
1391
1484
|
}
|
1392
1485
|
|
1393
1486
|
return workbook;
|
@@ -1404,7 +1497,8 @@ mem_error:
|
|
1404
1497
|
lxw_worksheet *
|
1405
1498
|
workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
1406
1499
|
{
|
1407
|
-
|
1500
|
+
lxw_sheet *sheet = NULL;
|
1501
|
+
lxw_worksheet *worksheet = NULL;
|
1408
1502
|
lxw_worksheet_name *worksheet_name = NULL;
|
1409
1503
|
lxw_error error;
|
1410
1504
|
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
@@ -1421,13 +1515,13 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
|
1421
1515
|
GOTO_LABEL_ON_MEM_ERROR(new_name, mem_error);
|
1422
1516
|
|
1423
1517
|
lxw_snprintf(new_name, LXW_MAX_SHEETNAME_LENGTH, "Sheet%d",
|
1424
|
-
self->
|
1518
|
+
self->num_worksheets + 1);
|
1425
1519
|
init_data.name = new_name;
|
1426
1520
|
init_data.quoted_name = lxw_strdup(new_name);
|
1427
1521
|
}
|
1428
1522
|
|
1429
1523
|
/* Check that the worksheet name is valid. */
|
1430
|
-
error =
|
1524
|
+
error = workbook_validate_sheet_name(self, init_data.name);
|
1431
1525
|
if (error) {
|
1432
1526
|
LXW_WARN_FORMAT2("workbook_add_worksheet(): worksheet name '%s' has "
|
1433
1527
|
"error: %s", init_data.name, lxw_strerror(error));
|
@@ -1451,9 +1545,19 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
|
1451
1545
|
worksheet = lxw_worksheet_new(&init_data);
|
1452
1546
|
GOTO_LABEL_ON_MEM_ERROR(worksheet, mem_error);
|
1453
1547
|
|
1454
|
-
|
1548
|
+
/* Add it to the worksheet list. */
|
1549
|
+
self->num_worksheets++;
|
1455
1550
|
STAILQ_INSERT_TAIL(self->worksheets, worksheet, list_pointers);
|
1456
1551
|
|
1552
|
+
/* Create a new sheet object. */
|
1553
|
+
sheet = calloc(1, sizeof(lxw_sheet));
|
1554
|
+
GOTO_LABEL_ON_MEM_ERROR(sheet, mem_error);
|
1555
|
+
sheet->u.worksheet = worksheet;
|
1556
|
+
|
1557
|
+
/* Add it to the worksheet list. */
|
1558
|
+
self->num_sheets++;
|
1559
|
+
STAILQ_INSERT_TAIL(self->sheets, sheet, list_pointers);
|
1560
|
+
|
1457
1561
|
/* Store the worksheet so we can look it up by name. */
|
1458
1562
|
worksheet_name->name = init_data.name;
|
1459
1563
|
worksheet_name->worksheet = worksheet;
|
@@ -1465,6 +1569,91 @@ mem_error:
|
|
1465
1569
|
free(init_data.name);
|
1466
1570
|
free(init_data.quoted_name);
|
1467
1571
|
free(worksheet_name);
|
1572
|
+
free(worksheet);
|
1573
|
+
return NULL;
|
1574
|
+
}
|
1575
|
+
|
1576
|
+
/*
|
1577
|
+
* Add a new chartsheet to the Excel workbook.
|
1578
|
+
*/
|
1579
|
+
lxw_chartsheet *
|
1580
|
+
workbook_add_chartsheet(lxw_workbook *self, const char *sheetname)
|
1581
|
+
{
|
1582
|
+
lxw_sheet *sheet = NULL;
|
1583
|
+
lxw_chartsheet *chartsheet = NULL;
|
1584
|
+
lxw_chartsheet_name *chartsheet_name = NULL;
|
1585
|
+
lxw_error error;
|
1586
|
+
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
1587
|
+
char *new_name = NULL;
|
1588
|
+
|
1589
|
+
if (sheetname) {
|
1590
|
+
/* Use the user supplied name. */
|
1591
|
+
init_data.name = lxw_strdup(sheetname);
|
1592
|
+
init_data.quoted_name = lxw_quote_sheetname((char *) sheetname);
|
1593
|
+
}
|
1594
|
+
else {
|
1595
|
+
/* Use the default SheetN name. */
|
1596
|
+
new_name = malloc(LXW_MAX_SHEETNAME_LENGTH);
|
1597
|
+
GOTO_LABEL_ON_MEM_ERROR(new_name, mem_error);
|
1598
|
+
|
1599
|
+
lxw_snprintf(new_name, LXW_MAX_SHEETNAME_LENGTH, "Chart%d",
|
1600
|
+
self->num_chartsheets + 1);
|
1601
|
+
init_data.name = new_name;
|
1602
|
+
init_data.quoted_name = lxw_strdup(new_name);
|
1603
|
+
}
|
1604
|
+
|
1605
|
+
/* Check that the chartsheet name is valid. */
|
1606
|
+
error = workbook_validate_sheet_name(self, init_data.name);
|
1607
|
+
if (error) {
|
1608
|
+
LXW_WARN_FORMAT2
|
1609
|
+
("workbook_add_chartsheet(): chartsheet name '%s' has "
|
1610
|
+
"error: %s", init_data.name, lxw_strerror(error));
|
1611
|
+
goto mem_error;
|
1612
|
+
}
|
1613
|
+
|
1614
|
+
/* Create a struct to find/store the chartsheet name/pointer. */
|
1615
|
+
chartsheet_name = calloc(1, sizeof(struct lxw_chartsheet_name));
|
1616
|
+
GOTO_LABEL_ON_MEM_ERROR(chartsheet_name, mem_error);
|
1617
|
+
|
1618
|
+
/* Initialize the metadata to pass to the chartsheet. */
|
1619
|
+
init_data.hidden = 0;
|
1620
|
+
init_data.index = self->num_sheets;
|
1621
|
+
init_data.sst = self->sst;
|
1622
|
+
init_data.optimize = self->options.constant_memory;
|
1623
|
+
init_data.active_sheet = &self->active_sheet;
|
1624
|
+
init_data.first_sheet = &self->first_sheet;
|
1625
|
+
init_data.tmpdir = self->options.tmpdir;
|
1626
|
+
|
1627
|
+
/* Create a new chartsheet object. */
|
1628
|
+
chartsheet = lxw_chartsheet_new(&init_data);
|
1629
|
+
GOTO_LABEL_ON_MEM_ERROR(chartsheet, mem_error);
|
1630
|
+
|
1631
|
+
/* Add it to the chartsheet list. */
|
1632
|
+
self->num_chartsheets++;
|
1633
|
+
STAILQ_INSERT_TAIL(self->chartsheets, chartsheet, list_pointers);
|
1634
|
+
|
1635
|
+
/* Create a new sheet object. */
|
1636
|
+
sheet = calloc(1, sizeof(lxw_sheet));
|
1637
|
+
GOTO_LABEL_ON_MEM_ERROR(sheet, mem_error);
|
1638
|
+
sheet->is_chartsheet = LXW_TRUE;
|
1639
|
+
sheet->u.chartsheet = chartsheet;
|
1640
|
+
|
1641
|
+
/* Add it to the chartsheet list. */
|
1642
|
+
self->num_sheets++;
|
1643
|
+
STAILQ_INSERT_TAIL(self->sheets, sheet, list_pointers);
|
1644
|
+
|
1645
|
+
/* Store the chartsheet so we can look it up by name. */
|
1646
|
+
chartsheet_name->name = init_data.name;
|
1647
|
+
chartsheet_name->chartsheet = chartsheet;
|
1648
|
+
RB_INSERT(lxw_chartsheet_names, self->chartsheet_names, chartsheet_name);
|
1649
|
+
|
1650
|
+
return chartsheet;
|
1651
|
+
|
1652
|
+
mem_error:
|
1653
|
+
free(init_data.name);
|
1654
|
+
free(init_data.quoted_name);
|
1655
|
+
free(chartsheet_name);
|
1656
|
+
free(chartsheet);
|
1468
1657
|
return NULL;
|
1469
1658
|
}
|
1470
1659
|
|
@@ -1528,6 +1717,7 @@ workbook_default_format(lxw_workbook *self)
|
|
1528
1717
|
lxw_error
|
1529
1718
|
workbook_close(lxw_workbook *self)
|
1530
1719
|
{
|
1720
|
+
lxw_sheet *sheet = NULL;
|
1531
1721
|
lxw_worksheet *worksheet = NULL;
|
1532
1722
|
lxw_packager *packager = NULL;
|
1533
1723
|
lxw_error error = LXW_NO_ERROR;
|
@@ -1538,17 +1728,41 @@ workbook_close(lxw_workbook *self)
|
|
1538
1728
|
|
1539
1729
|
/* Ensure that at least one worksheet has been selected. */
|
1540
1730
|
if (self->active_sheet == 0) {
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1731
|
+
sheet = STAILQ_FIRST(self->sheets);
|
1732
|
+
if (!sheet->is_chartsheet) {
|
1733
|
+
worksheet = sheet->u.worksheet;
|
1734
|
+
worksheet->selected = 1;
|
1735
|
+
worksheet->hidden = 0;
|
1736
|
+
}
|
1544
1737
|
}
|
1545
1738
|
|
1546
1739
|
/* Set the active sheet. */
|
1547
|
-
STAILQ_FOREACH(
|
1740
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
1741
|
+
if (sheet->is_chartsheet)
|
1742
|
+
continue;
|
1743
|
+
else
|
1744
|
+
worksheet = sheet->u.worksheet;
|
1745
|
+
|
1548
1746
|
if (worksheet->index == self->active_sheet)
|
1549
1747
|
worksheet->active = 1;
|
1550
1748
|
}
|
1551
1749
|
|
1750
|
+
/* Set workbook and worksheet VBA codenames if a macro has been added. */
|
1751
|
+
if (self->vba_project) {
|
1752
|
+
if (!self->vba_codename)
|
1753
|
+
workbook_set_vba_name(self, "ThisWorkbook");
|
1754
|
+
|
1755
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
1756
|
+
if (sheet->is_chartsheet)
|
1757
|
+
continue;
|
1758
|
+
else
|
1759
|
+
worksheet = sheet->u.worksheet;
|
1760
|
+
|
1761
|
+
if (!worksheet->vba_codename)
|
1762
|
+
worksheet_set_vba_name(worksheet, worksheet->name);
|
1763
|
+
}
|
1764
|
+
}
|
1765
|
+
|
1552
1766
|
/* Set the defined names for the worksheets such as Print Titles. */
|
1553
1767
|
_prepare_defined_names(self);
|
1554
1768
|
|
@@ -1559,13 +1773,15 @@ workbook_close(lxw_workbook *self)
|
|
1559
1773
|
_add_chart_cache_data(self);
|
1560
1774
|
|
1561
1775
|
/* Create a packager object to assemble sub-elements into a zip file. */
|
1562
|
-
packager = lxw_packager_new(self->filename,
|
1776
|
+
packager = lxw_packager_new(self->filename,
|
1777
|
+
self->options.tmpdir,
|
1778
|
+
self->options.use_zip64);
|
1563
1779
|
|
1564
1780
|
/* If the packager fails it is generally due to a zip permission error. */
|
1565
1781
|
if (packager == NULL) {
|
1566
1782
|
fprintf(stderr, "[ERROR] workbook_close(): "
|
1567
1783
|
"Error creating '%s'. "
|
1568
|
-
"
|
1784
|
+
"System error = %s\n", self->filename, strerror(errno));
|
1569
1785
|
|
1570
1786
|
error = LXW_ERROR_CREATING_XLSX_FILE;
|
1571
1787
|
goto mem_error;
|
@@ -1581,26 +1797,47 @@ workbook_close(lxw_workbook *self)
|
|
1581
1797
|
if (error == LXW_ERROR_CREATING_TMPFILE) {
|
1582
1798
|
fprintf(stderr, "[ERROR] workbook_close(): "
|
1583
1799
|
"Error creating tmpfile(s) to assemble '%s'. "
|
1584
|
-
"
|
1800
|
+
"System error = %s\n", self->filename, strerror(errno));
|
1585
1801
|
}
|
1586
1802
|
|
1587
|
-
/* If LXW_ERROR_ZIP_FILE_OPERATION then errno is set by
|
1803
|
+
/* If LXW_ERROR_ZIP_FILE_OPERATION then errno is set by zip. */
|
1588
1804
|
if (error == LXW_ERROR_ZIP_FILE_OPERATION) {
|
1589
1805
|
fprintf(stderr, "[ERROR] workbook_close(): "
|
1590
|
-
"
|
1591
|
-
"
|
1806
|
+
"Zip ZIP_ERRNO error while creating xlsx file '%s'. "
|
1807
|
+
"System error = %s\n", self->filename, strerror(errno));
|
1808
|
+
}
|
1809
|
+
|
1810
|
+
/* If LXW_ERROR_ZIP_PARAMETER_ERROR then errno is set by zip. */
|
1811
|
+
if (error == LXW_ERROR_ZIP_PARAMETER_ERROR) {
|
1812
|
+
fprintf(stderr, "[ERROR] workbook_close(): "
|
1813
|
+
"Zip ZIP_PARAMERROR error while creating xlsx file '%s'. "
|
1814
|
+
"System error = %s\n", self->filename, strerror(errno));
|
1815
|
+
}
|
1816
|
+
|
1817
|
+
/* If LXW_ERROR_ZIP_BAD_ZIP_FILE then errno is set by zip. */
|
1818
|
+
if (error == LXW_ERROR_ZIP_BAD_ZIP_FILE) {
|
1819
|
+
fprintf(stderr, "[ERROR] workbook_close(): "
|
1820
|
+
"Zip ZIP_BADZIPFILE error while creating xlsx file '%s'. "
|
1821
|
+
"This may require the use_zip64 option for large files. "
|
1822
|
+
"System error = %s\n", self->filename, strerror(errno));
|
1823
|
+
}
|
1824
|
+
|
1825
|
+
/* If LXW_ERROR_ZIP_INTERNAL_ERROR then errno is set by zip. */
|
1826
|
+
if (error == LXW_ERROR_ZIP_INTERNAL_ERROR) {
|
1827
|
+
fprintf(stderr, "[ERROR] workbook_close(): "
|
1828
|
+
"Zip ZIP_INTERNALERROR error while creating xlsx file '%s'. "
|
1829
|
+
"System error = %s\n", self->filename, strerror(errno));
|
1592
1830
|
}
|
1593
1831
|
|
1594
1832
|
/* The next 2 error conditions don't set errno. */
|
1595
1833
|
if (error == LXW_ERROR_ZIP_FILE_ADD) {
|
1596
1834
|
fprintf(stderr, "[ERROR] workbook_close(): "
|
1597
|
-
"
|
1598
|
-
self->filename);
|
1835
|
+
"Zip error adding file to xlsx file '%s'.\n", self->filename);
|
1599
1836
|
}
|
1600
1837
|
|
1601
1838
|
if (error == LXW_ERROR_ZIP_CLOSE) {
|
1602
1839
|
fprintf(stderr, "[ERROR] workbook_close(): "
|
1603
|
-
"
|
1840
|
+
"Zip error closing xlsx file '%s'.\n", self->filename);
|
1604
1841
|
}
|
1605
1842
|
|
1606
1843
|
mem_error:
|
@@ -1910,11 +2147,33 @@ workbook_get_worksheet_by_name(lxw_workbook *self, const char *name)
|
|
1910
2147
|
return NULL;
|
1911
2148
|
}
|
1912
2149
|
|
2150
|
+
/*
|
2151
|
+
* Get a chartsheet object from its name.
|
2152
|
+
*/
|
2153
|
+
lxw_chartsheet *
|
2154
|
+
workbook_get_chartsheet_by_name(lxw_workbook *self, const char *name)
|
2155
|
+
{
|
2156
|
+
lxw_chartsheet_name chartsheet_name;
|
2157
|
+
lxw_chartsheet_name *found;
|
2158
|
+
|
2159
|
+
if (!name)
|
2160
|
+
return NULL;
|
2161
|
+
|
2162
|
+
chartsheet_name.name = name;
|
2163
|
+
found = RB_FIND(lxw_chartsheet_names,
|
2164
|
+
self->chartsheet_names, &chartsheet_name);
|
2165
|
+
|
2166
|
+
if (found)
|
2167
|
+
return found->chartsheet;
|
2168
|
+
else
|
2169
|
+
return NULL;
|
2170
|
+
}
|
2171
|
+
|
1913
2172
|
/*
|
1914
2173
|
* Validate the worksheet name based on Excel's rules.
|
1915
2174
|
*/
|
1916
2175
|
lxw_error
|
1917
|
-
|
2176
|
+
workbook_validate_sheet_name(lxw_workbook *self, const char *sheetname)
|
1918
2177
|
{
|
1919
2178
|
/* Check the UTF-8 length of the worksheet name. */
|
1920
2179
|
if (lxw_utf8_strlen(sheetname) > LXW_SHEETNAME_MAX)
|
@@ -1924,9 +2183,66 @@ workbook_validate_worksheet_name(lxw_workbook *self, const char *sheetname)
|
|
1924
2183
|
if (strpbrk(sheetname, "[]:*?/\\"))
|
1925
2184
|
return LXW_ERROR_INVALID_SHEETNAME_CHARACTER;
|
1926
2185
|
|
2186
|
+
/* Check that the worksheet doesn't start or end with an apostrophe. */
|
2187
|
+
if (sheetname[0] == '\'' || sheetname[strlen(sheetname) - 1] == '\'')
|
2188
|
+
return LXW_ERROR_SHEETNAME_START_END_APOSTROPHE;
|
2189
|
+
|
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
|
+
|
1927
2194
|
/* Check if the worksheet name is already in use. */
|
1928
2195
|
if (workbook_get_worksheet_by_name(self, sheetname))
|
1929
2196
|
return LXW_ERROR_SHEETNAME_ALREADY_USED;
|
1930
2197
|
|
2198
|
+
/* Check if the chartsheet name is already in use. */
|
2199
|
+
if (workbook_get_chartsheet_by_name(self, sheetname))
|
2200
|
+
return LXW_ERROR_SHEETNAME_ALREADY_USED;
|
2201
|
+
|
2202
|
+
return LXW_NO_ERROR;
|
2203
|
+
}
|
2204
|
+
|
2205
|
+
/*
|
2206
|
+
* Add a vbaProject binary to the Excel workbook.
|
2207
|
+
*/
|
2208
|
+
lxw_error
|
2209
|
+
workbook_add_vba_project(lxw_workbook *self, const char *filename)
|
2210
|
+
{
|
2211
|
+
FILE *filehandle;
|
2212
|
+
|
2213
|
+
if (!filename) {
|
2214
|
+
LXW_WARN("workbook_add_vba_project(): "
|
2215
|
+
"filename must be specified.");
|
2216
|
+
return LXW_ERROR_NULL_PARAMETER_IGNORED;
|
2217
|
+
}
|
2218
|
+
|
2219
|
+
/* Check that the vbaProject file exists and can be opened. */
|
2220
|
+
filehandle = fopen(filename, "rb");
|
2221
|
+
if (!filehandle) {
|
2222
|
+
LXW_WARN_FORMAT1("workbook_add_vba_project(): "
|
2223
|
+
"file doesn't exist or can't be opened: %s.",
|
2224
|
+
filename);
|
2225
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
2226
|
+
}
|
2227
|
+
fclose(filehandle);
|
2228
|
+
|
2229
|
+
self->vba_project = lxw_strdup(filename);
|
2230
|
+
|
2231
|
+
return LXW_NO_ERROR;
|
2232
|
+
}
|
2233
|
+
|
2234
|
+
/*
|
2235
|
+
* Set the VBA name for the workbook.
|
2236
|
+
*/
|
2237
|
+
lxw_error
|
2238
|
+
workbook_set_vba_name(lxw_workbook *self, const char *name)
|
2239
|
+
{
|
2240
|
+
if (!name) {
|
2241
|
+
LXW_WARN("workbook_set_vba_name(): " "name must be specified.");
|
2242
|
+
return LXW_ERROR_NULL_PARAMETER_IGNORED;
|
2243
|
+
}
|
2244
|
+
|
2245
|
+
self->vba_codename = lxw_strdup(name);
|
2246
|
+
|
1931
2247
|
return LXW_NO_ERROR;
|
1932
2248
|
}
|