xlsxwriter 0.0.5 → 0.0.6
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/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chart.h +55 -5
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chartsheet.h +544 -0
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/common.h +6 -0
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/content_types.h +2 -0
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/drawing.h +1 -0
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/format.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/shared_strings.h +3 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/styles.h +7 -2
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/utility.h +16 -0
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/workbook.h +122 -24
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/worksheet.h +236 -48
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/xmlwriter.h +2 -0
- data/ext/xlsxwriter/libxlsxwriter/src/chart.c +40 -4
- data/ext/xlsxwriter/libxlsxwriter/src/chartsheet.c +508 -0
- data/ext/xlsxwriter/libxlsxwriter/src/content_types.c +10 -0
- data/ext/xlsxwriter/libxlsxwriter/src/drawing.c +100 -3
- data/ext/xlsxwriter/libxlsxwriter/src/packager.c +252 -30
- data/ext/xlsxwriter/libxlsxwriter/src/shared_strings.c +16 -2
- data/ext/xlsxwriter/libxlsxwriter/src/styles.c +54 -7
- data/ext/xlsxwriter/libxlsxwriter/src/utility.c +43 -1
- data/ext/xlsxwriter/libxlsxwriter/src/workbook.c +254 -41
- data/ext/xlsxwriter/libxlsxwriter/src/worksheet.c +381 -65
- data/ext/xlsxwriter/libxlsxwriter/src/xmlwriter.c +16 -7
- data/ext/xlsxwriter/libxlsxwriter/third_party/minizip/ioapi.c +10 -0
- data/ext/xlsxwriter/libxlsxwriter/third_party/minizip/zip.c +2 -0
- data/ext/xlsxwriter/libxlsxwriter/third_party/tmpfileplus/tmpfileplus.c +2 -2
- data/ext/xlsxwriter/workbook.c +9 -6
- data/lib/xlsxwriter/version.rb +1 -1
- metadata +5 -4
@@ -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);
|
@@ -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
|
*
|
@@ -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");
|
@@ -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,6 +20,7 @@ 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
|
+
"Error reading a tmpfile.",
|
23
24
|
"Zlib error with a file operation while creating xlsx file.",
|
24
25
|
"Zlib error when adding sub file to xlsx file.",
|
25
26
|
"Zlib error when closing xlsx file.",
|
@@ -553,3 +554,44 @@ lxw_sprintf_dbl(char *data, double number)
|
|
553
554
|
return 0;
|
554
555
|
}
|
555
556
|
#endif
|
557
|
+
|
558
|
+
/*
|
559
|
+
* Retrieve runtime library version
|
560
|
+
*/
|
561
|
+
const char *
|
562
|
+
lxw_version(void)
|
563
|
+
{
|
564
|
+
return LXW_VERSION;
|
565
|
+
}
|
566
|
+
|
567
|
+
/*
|
568
|
+
* Hash a worksheet password. Based on the algorithm provided by Daniel Rentz
|
569
|
+
* of OpenOffice.
|
570
|
+
*/
|
571
|
+
uint16_t
|
572
|
+
lxw_hash_password(const char *password)
|
573
|
+
{
|
574
|
+
size_t count;
|
575
|
+
uint8_t i;
|
576
|
+
uint16_t hash = 0x0000;
|
577
|
+
|
578
|
+
count = strlen(password);
|
579
|
+
|
580
|
+
for (i = 0; i < count; i++) {
|
581
|
+
uint32_t low_15;
|
582
|
+
uint32_t high_15;
|
583
|
+
uint32_t letter = password[i] << (i + 1);
|
584
|
+
|
585
|
+
low_15 = letter & 0x7fff;
|
586
|
+
high_15 = letter & (0x7fff << 15);
|
587
|
+
high_15 = high_15 >> 15;
|
588
|
+
letter = low_15 | high_15;
|
589
|
+
|
590
|
+
hash ^= letter;
|
591
|
+
}
|
592
|
+
|
593
|
+
hash ^= count;
|
594
|
+
hash ^= 0xCE4B;
|
595
|
+
|
596
|
+
return hash;
|
597
|
+
}
|
@@ -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,10 +35,16 @@ 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)
|
42
|
+
{
|
43
|
+
return strcmp(name1->name, name2->name);
|
44
|
+
}
|
45
|
+
|
46
|
+
STATIC int
|
47
|
+
_chartsheet_name_cmp(lxw_chartsheet_name *name1, lxw_chartsheet_name *name2)
|
37
48
|
{
|
38
49
|
return strcmp(name1->name, name2->name);
|
39
50
|
}
|
@@ -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
|
-
STAILQ_REMOVE_HEAD(workbook->worksheets, list_pointers);
|
105
|
-
lxw_worksheet_free(worksheet);
|
106
|
-
}
|
107
|
-
free(workbook->worksheets);
|
113
|
+
/* Free the sheets in the workbook. */
|
114
|
+
if (workbook->sheets) {
|
115
|
+
while (!STAILQ_EMPTY(workbook->sheets)) {
|
116
|
+
sheet = STAILQ_FIRST(workbook->sheets);
|
108
117
|
|
118
|
+
if (sheet->is_chartsheet)
|
119
|
+
lxw_chartsheet_free(sheet->u.chartsheet);
|
120
|
+
else
|
121
|
+
lxw_worksheet_free(sheet->u.worksheet);
|
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,18 +175,35 @@ 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);
|
@@ -432,7 +471,7 @@ _prepare_num_formats(lxw_workbook *self)
|
|
432
471
|
num_format_index = calloc(1, sizeof(uint16_t));
|
433
472
|
*num_format_index = index;
|
434
473
|
format->num_format_index = index;
|
435
|
-
lxw_insert_hash_element(num_formats, num_format,
|
474
|
+
lxw_insert_hash_element(num_formats, format->num_format,
|
436
475
|
num_format_index,
|
437
476
|
LXW_FORMAT_FIELD_LEN);
|
438
477
|
index++;
|
@@ -496,6 +535,7 @@ _store_defined_name(lxw_workbook *self, const char *name,
|
|
496
535
|
const char *app_name, const char *formula, int16_t index,
|
497
536
|
uint8_t hidden)
|
498
537
|
{
|
538
|
+
lxw_sheet *sheet;
|
499
539
|
lxw_worksheet *worksheet;
|
500
540
|
lxw_defined_name *defined_name;
|
501
541
|
lxw_defined_name *list_defined_name;
|
@@ -546,7 +586,12 @@ _store_defined_name(lxw_workbook *self, const char *name,
|
|
546
586
|
worksheet_name[strlen(worksheet_name) - 1] = '\0';
|
547
587
|
|
548
588
|
/* Search for worksheet name to get the equivalent worksheet index. */
|
549
|
-
STAILQ_FOREACH(
|
589
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
590
|
+
if (sheet->is_chartsheet)
|
591
|
+
continue;
|
592
|
+
else
|
593
|
+
worksheet = sheet->u.worksheet;
|
594
|
+
|
550
595
|
if (strcmp(worksheet_name, worksheet->name) == 0) {
|
551
596
|
defined_name->index = worksheet->index;
|
552
597
|
lxw_strcpy(defined_name->normalised_sheetname,
|
@@ -837,13 +882,23 @@ _add_chart_cache_data(lxw_workbook *self)
|
|
837
882
|
STATIC void
|
838
883
|
_prepare_drawings(lxw_workbook *self)
|
839
884
|
{
|
885
|
+
lxw_sheet *sheet;
|
840
886
|
lxw_worksheet *worksheet;
|
841
887
|
lxw_image_options *image_options;
|
842
888
|
uint16_t chart_ref_id = 0;
|
843
889
|
uint16_t image_ref_id = 0;
|
844
890
|
uint16_t drawing_id = 0;
|
891
|
+
uint8_t is_chartsheet;
|
845
892
|
|
846
|
-
STAILQ_FOREACH(
|
893
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
894
|
+
if (sheet->is_chartsheet) {
|
895
|
+
worksheet = sheet->u.chartsheet->worksheet;
|
896
|
+
is_chartsheet = LXW_TRUE;
|
897
|
+
}
|
898
|
+
else {
|
899
|
+
worksheet = sheet->u.worksheet;
|
900
|
+
is_chartsheet = LXW_FALSE;
|
901
|
+
}
|
847
902
|
|
848
903
|
if (STAILQ_EMPTY(worksheet->image_data)
|
849
904
|
&& STAILQ_EMPTY(worksheet->chart_data))
|
@@ -854,7 +909,7 @@ _prepare_drawings(lxw_workbook *self)
|
|
854
909
|
STAILQ_FOREACH(image_options, worksheet->chart_data, list_pointers) {
|
855
910
|
chart_ref_id++;
|
856
911
|
lxw_worksheet_prepare_chart(worksheet, chart_ref_id, drawing_id,
|
857
|
-
image_options);
|
912
|
+
image_options, is_chartsheet);
|
858
913
|
if (image_options->chart)
|
859
914
|
STAILQ_INSERT_TAIL(self->ordered_charts, image_options->chart,
|
860
915
|
ordered_list_pointers);
|
@@ -889,14 +944,18 @@ STATIC void
|
|
889
944
|
_prepare_defined_names(lxw_workbook *self)
|
890
945
|
{
|
891
946
|
lxw_worksheet *worksheet;
|
947
|
+
lxw_sheet *sheet;
|
892
948
|
char app_name[LXW_DEFINED_NAME_LENGTH];
|
893
949
|
char range[LXW_DEFINED_NAME_LENGTH];
|
894
950
|
char area[LXW_MAX_CELL_RANGE_LENGTH];
|
895
951
|
char first_col[8];
|
896
952
|
char last_col[8];
|
897
953
|
|
898
|
-
STAILQ_FOREACH(
|
899
|
-
|
954
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
955
|
+
if (sheet->is_chartsheet)
|
956
|
+
continue;
|
957
|
+
else
|
958
|
+
worksheet = sheet->u.worksheet;
|
900
959
|
/*
|
901
960
|
* Check for autofilter settings and store them.
|
902
961
|
*/
|
@@ -1170,13 +1229,23 @@ _write_sheet(lxw_workbook *self, const char *name, uint32_t sheet_id,
|
|
1170
1229
|
STATIC void
|
1171
1230
|
_write_sheets(lxw_workbook *self)
|
1172
1231
|
{
|
1232
|
+
lxw_sheet *sheet;
|
1173
1233
|
lxw_worksheet *worksheet;
|
1234
|
+
lxw_chartsheet *chartsheet;
|
1174
1235
|
|
1175
1236
|
lxw_xml_start_tag(self->file, "sheets", NULL);
|
1176
1237
|
|
1177
|
-
STAILQ_FOREACH(
|
1178
|
-
|
1179
|
-
|
1238
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
1239
|
+
if (sheet->is_chartsheet) {
|
1240
|
+
chartsheet = sheet->u.chartsheet;
|
1241
|
+
_write_sheet(self, chartsheet->name, chartsheet->index + 1,
|
1242
|
+
chartsheet->hidden);
|
1243
|
+
}
|
1244
|
+
else {
|
1245
|
+
worksheet = sheet->u.worksheet;
|
1246
|
+
_write_sheet(self, worksheet->name, worksheet->index + 1,
|
1247
|
+
worksheet->hidden);
|
1248
|
+
}
|
1180
1249
|
}
|
1181
1250
|
|
1182
1251
|
lxw_xml_end_tag(self->file, "sheets");
|
@@ -1224,9 +1293,6 @@ _write_defined_name(lxw_workbook *self, lxw_defined_name *defined_name)
|
|
1224
1293
|
LXW_FREE_ATTRIBUTES();
|
1225
1294
|
}
|
1226
1295
|
|
1227
|
-
/*
|
1228
|
-
* Write the <definedNames> element.
|
1229
|
-
*/
|
1230
1296
|
STATIC void
|
1231
1297
|
_write_defined_names(lxw_workbook *self)
|
1232
1298
|
{
|
@@ -1330,16 +1396,32 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
|
1330
1396
|
GOTO_LABEL_ON_MEM_ERROR(workbook, mem_error);
|
1331
1397
|
workbook->filename = lxw_strdup(filename);
|
1332
1398
|
|
1399
|
+
/* Add the sheets list. */
|
1400
|
+
workbook->sheets = calloc(1, sizeof(struct lxw_sheets));
|
1401
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->sheets, mem_error);
|
1402
|
+
STAILQ_INIT(workbook->sheets);
|
1403
|
+
|
1333
1404
|
/* Add the worksheets list. */
|
1334
1405
|
workbook->worksheets = calloc(1, sizeof(struct lxw_worksheets));
|
1335
1406
|
GOTO_LABEL_ON_MEM_ERROR(workbook->worksheets, mem_error);
|
1336
1407
|
STAILQ_INIT(workbook->worksheets);
|
1337
1408
|
|
1409
|
+
/* Add the chartsheets list. */
|
1410
|
+
workbook->chartsheets = calloc(1, sizeof(struct lxw_chartsheets));
|
1411
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->chartsheets, mem_error);
|
1412
|
+
STAILQ_INIT(workbook->chartsheets);
|
1413
|
+
|
1338
1414
|
/* Add the worksheet names tree. */
|
1339
1415
|
workbook->worksheet_names = calloc(1, sizeof(struct lxw_worksheet_names));
|
1340
1416
|
GOTO_LABEL_ON_MEM_ERROR(workbook->worksheet_names, mem_error);
|
1341
1417
|
RB_INIT(workbook->worksheet_names);
|
1342
1418
|
|
1419
|
+
/* Add the chartsheet names tree. */
|
1420
|
+
workbook->chartsheet_names = calloc(1,
|
1421
|
+
sizeof(struct lxw_chartsheet_names));
|
1422
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->chartsheet_names, mem_error);
|
1423
|
+
RB_INIT(workbook->chartsheet_names);
|
1424
|
+
|
1343
1425
|
/* Add the charts list. */
|
1344
1426
|
workbook->charts = calloc(1, sizeof(struct lxw_charts));
|
1345
1427
|
GOTO_LABEL_ON_MEM_ERROR(workbook->charts, mem_error);
|
@@ -1404,7 +1486,8 @@ mem_error:
|
|
1404
1486
|
lxw_worksheet *
|
1405
1487
|
workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
1406
1488
|
{
|
1407
|
-
|
1489
|
+
lxw_sheet *sheet = NULL;
|
1490
|
+
lxw_worksheet *worksheet = NULL;
|
1408
1491
|
lxw_worksheet_name *worksheet_name = NULL;
|
1409
1492
|
lxw_error error;
|
1410
1493
|
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
@@ -1421,13 +1504,13 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
|
1421
1504
|
GOTO_LABEL_ON_MEM_ERROR(new_name, mem_error);
|
1422
1505
|
|
1423
1506
|
lxw_snprintf(new_name, LXW_MAX_SHEETNAME_LENGTH, "Sheet%d",
|
1424
|
-
self->
|
1507
|
+
self->num_worksheets + 1);
|
1425
1508
|
init_data.name = new_name;
|
1426
1509
|
init_data.quoted_name = lxw_strdup(new_name);
|
1427
1510
|
}
|
1428
1511
|
|
1429
1512
|
/* Check that the worksheet name is valid. */
|
1430
|
-
error =
|
1513
|
+
error = workbook_validate_sheet_name(self, init_data.name);
|
1431
1514
|
if (error) {
|
1432
1515
|
LXW_WARN_FORMAT2("workbook_add_worksheet(): worksheet name '%s' has "
|
1433
1516
|
"error: %s", init_data.name, lxw_strerror(error));
|
@@ -1451,9 +1534,19 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
|
1451
1534
|
worksheet = lxw_worksheet_new(&init_data);
|
1452
1535
|
GOTO_LABEL_ON_MEM_ERROR(worksheet, mem_error);
|
1453
1536
|
|
1454
|
-
|
1537
|
+
/* Add it to the worksheet list. */
|
1538
|
+
self->num_worksheets++;
|
1455
1539
|
STAILQ_INSERT_TAIL(self->worksheets, worksheet, list_pointers);
|
1456
1540
|
|
1541
|
+
/* Create a new sheet object. */
|
1542
|
+
sheet = calloc(1, sizeof(lxw_sheet));
|
1543
|
+
GOTO_LABEL_ON_MEM_ERROR(sheet, mem_error);
|
1544
|
+
sheet->u.worksheet = worksheet;
|
1545
|
+
|
1546
|
+
/* Add it to the worksheet list. */
|
1547
|
+
self->num_sheets++;
|
1548
|
+
STAILQ_INSERT_TAIL(self->sheets, sheet, list_pointers);
|
1549
|
+
|
1457
1550
|
/* Store the worksheet so we can look it up by name. */
|
1458
1551
|
worksheet_name->name = init_data.name;
|
1459
1552
|
worksheet_name->worksheet = worksheet;
|
@@ -1465,6 +1558,91 @@ mem_error:
|
|
1465
1558
|
free(init_data.name);
|
1466
1559
|
free(init_data.quoted_name);
|
1467
1560
|
free(worksheet_name);
|
1561
|
+
free(worksheet);
|
1562
|
+
return NULL;
|
1563
|
+
}
|
1564
|
+
|
1565
|
+
/*
|
1566
|
+
* Add a new chartsheet to the Excel workbook.
|
1567
|
+
*/
|
1568
|
+
lxw_chartsheet *
|
1569
|
+
workbook_add_chartsheet(lxw_workbook *self, const char *sheetname)
|
1570
|
+
{
|
1571
|
+
lxw_sheet *sheet = NULL;
|
1572
|
+
lxw_chartsheet *chartsheet = NULL;
|
1573
|
+
lxw_chartsheet_name *chartsheet_name = NULL;
|
1574
|
+
lxw_error error;
|
1575
|
+
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
1576
|
+
char *new_name = NULL;
|
1577
|
+
|
1578
|
+
if (sheetname) {
|
1579
|
+
/* Use the user supplied name. */
|
1580
|
+
init_data.name = lxw_strdup(sheetname);
|
1581
|
+
init_data.quoted_name = lxw_quote_sheetname((char *) sheetname);
|
1582
|
+
}
|
1583
|
+
else {
|
1584
|
+
/* Use the default SheetN name. */
|
1585
|
+
new_name = malloc(LXW_MAX_SHEETNAME_LENGTH);
|
1586
|
+
GOTO_LABEL_ON_MEM_ERROR(new_name, mem_error);
|
1587
|
+
|
1588
|
+
lxw_snprintf(new_name, LXW_MAX_SHEETNAME_LENGTH, "Chart%d",
|
1589
|
+
self->num_chartsheets + 1);
|
1590
|
+
init_data.name = new_name;
|
1591
|
+
init_data.quoted_name = lxw_strdup(new_name);
|
1592
|
+
}
|
1593
|
+
|
1594
|
+
/* Check that the chartsheet name is valid. */
|
1595
|
+
error = workbook_validate_sheet_name(self, init_data.name);
|
1596
|
+
if (error) {
|
1597
|
+
LXW_WARN_FORMAT2
|
1598
|
+
("workbook_add_chartsheet(): chartsheet name '%s' has "
|
1599
|
+
"error: %s", init_data.name, lxw_strerror(error));
|
1600
|
+
goto mem_error;
|
1601
|
+
}
|
1602
|
+
|
1603
|
+
/* Create a struct to find/store the chartsheet name/pointer. */
|
1604
|
+
chartsheet_name = calloc(1, sizeof(struct lxw_chartsheet_name));
|
1605
|
+
GOTO_LABEL_ON_MEM_ERROR(chartsheet_name, mem_error);
|
1606
|
+
|
1607
|
+
/* Initialize the metadata to pass to the chartsheet. */
|
1608
|
+
init_data.hidden = 0;
|
1609
|
+
init_data.index = self->num_sheets;
|
1610
|
+
init_data.sst = self->sst;
|
1611
|
+
init_data.optimize = self->options.constant_memory;
|
1612
|
+
init_data.active_sheet = &self->active_sheet;
|
1613
|
+
init_data.first_sheet = &self->first_sheet;
|
1614
|
+
init_data.tmpdir = self->options.tmpdir;
|
1615
|
+
|
1616
|
+
/* Create a new chartsheet object. */
|
1617
|
+
chartsheet = lxw_chartsheet_new(&init_data);
|
1618
|
+
GOTO_LABEL_ON_MEM_ERROR(chartsheet, mem_error);
|
1619
|
+
|
1620
|
+
/* Add it to the chartsheet list. */
|
1621
|
+
self->num_chartsheets++;
|
1622
|
+
STAILQ_INSERT_TAIL(self->chartsheets, chartsheet, list_pointers);
|
1623
|
+
|
1624
|
+
/* Create a new sheet object. */
|
1625
|
+
sheet = calloc(1, sizeof(lxw_sheet));
|
1626
|
+
GOTO_LABEL_ON_MEM_ERROR(sheet, mem_error);
|
1627
|
+
sheet->is_chartsheet = LXW_TRUE;
|
1628
|
+
sheet->u.chartsheet = chartsheet;
|
1629
|
+
|
1630
|
+
/* Add it to the chartsheet list. */
|
1631
|
+
self->num_sheets++;
|
1632
|
+
STAILQ_INSERT_TAIL(self->sheets, sheet, list_pointers);
|
1633
|
+
|
1634
|
+
/* Store the chartsheet so we can look it up by name. */
|
1635
|
+
chartsheet_name->name = init_data.name;
|
1636
|
+
chartsheet_name->chartsheet = chartsheet;
|
1637
|
+
RB_INSERT(lxw_chartsheet_names, self->chartsheet_names, chartsheet_name);
|
1638
|
+
|
1639
|
+
return chartsheet;
|
1640
|
+
|
1641
|
+
mem_error:
|
1642
|
+
free(init_data.name);
|
1643
|
+
free(init_data.quoted_name);
|
1644
|
+
free(chartsheet_name);
|
1645
|
+
free(chartsheet);
|
1468
1646
|
return NULL;
|
1469
1647
|
}
|
1470
1648
|
|
@@ -1509,6 +1687,7 @@ workbook_add_format(lxw_workbook *self)
|
|
1509
1687
|
lxw_error
|
1510
1688
|
workbook_close(lxw_workbook *self)
|
1511
1689
|
{
|
1690
|
+
lxw_sheet *sheet = NULL;
|
1512
1691
|
lxw_worksheet *worksheet = NULL;
|
1513
1692
|
lxw_packager *packager = NULL;
|
1514
1693
|
lxw_error error = LXW_NO_ERROR;
|
@@ -1519,13 +1698,21 @@ workbook_close(lxw_workbook *self)
|
|
1519
1698
|
|
1520
1699
|
/* Ensure that at least one worksheet has been selected. */
|
1521
1700
|
if (self->active_sheet == 0) {
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1701
|
+
sheet = STAILQ_FIRST(self->sheets);
|
1702
|
+
if (!sheet->is_chartsheet) {
|
1703
|
+
worksheet = sheet->u.worksheet;
|
1704
|
+
worksheet->selected = 1;
|
1705
|
+
worksheet->hidden = 0;
|
1706
|
+
}
|
1525
1707
|
}
|
1526
1708
|
|
1527
1709
|
/* Set the active sheet. */
|
1528
|
-
STAILQ_FOREACH(
|
1710
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
1711
|
+
if (sheet->is_chartsheet)
|
1712
|
+
continue;
|
1713
|
+
else
|
1714
|
+
worksheet = sheet->u.worksheet;
|
1715
|
+
|
1529
1716
|
if (worksheet->index == self->active_sheet)
|
1530
1717
|
worksheet->active = 1;
|
1531
1718
|
}
|
@@ -1891,11 +2078,33 @@ workbook_get_worksheet_by_name(lxw_workbook *self, const char *name)
|
|
1891
2078
|
return NULL;
|
1892
2079
|
}
|
1893
2080
|
|
2081
|
+
/*
|
2082
|
+
* Get a chartsheet object from its name.
|
2083
|
+
*/
|
2084
|
+
lxw_chartsheet *
|
2085
|
+
workbook_get_chartsheet_by_name(lxw_workbook *self, const char *name)
|
2086
|
+
{
|
2087
|
+
lxw_chartsheet_name chartsheet_name;
|
2088
|
+
lxw_chartsheet_name *found;
|
2089
|
+
|
2090
|
+
if (!name)
|
2091
|
+
return NULL;
|
2092
|
+
|
2093
|
+
chartsheet_name.name = name;
|
2094
|
+
found = RB_FIND(lxw_chartsheet_names,
|
2095
|
+
self->chartsheet_names, &chartsheet_name);
|
2096
|
+
|
2097
|
+
if (found)
|
2098
|
+
return found->chartsheet;
|
2099
|
+
else
|
2100
|
+
return NULL;
|
2101
|
+
}
|
2102
|
+
|
1894
2103
|
/*
|
1895
2104
|
* Validate the worksheet name based on Excel's rules.
|
1896
2105
|
*/
|
1897
2106
|
lxw_error
|
1898
|
-
|
2107
|
+
workbook_validate_sheet_name(lxw_workbook *self, const char *sheetname)
|
1899
2108
|
{
|
1900
2109
|
/* Check the UTF-8 length of the worksheet name. */
|
1901
2110
|
if (lxw_utf8_strlen(sheetname) > LXW_SHEETNAME_MAX)
|
@@ -1909,5 +2118,9 @@ workbook_validate_worksheet_name(lxw_workbook *self, const char *sheetname)
|
|
1909
2118
|
if (workbook_get_worksheet_by_name(self, sheetname))
|
1910
2119
|
return LXW_ERROR_SHEETNAME_ALREADY_USED;
|
1911
2120
|
|
2121
|
+
/* Check if the chartsheet name is already in use. */
|
2122
|
+
if (workbook_get_chartsheet_by_name(self, sheetname))
|
2123
|
+
return LXW_ERROR_SHEETNAME_ALREADY_USED;
|
2124
|
+
|
1912
2125
|
return LXW_NO_ERROR;
|
1913
2126
|
}
|