xlsxwriter 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|