xlsxwriter 0.0.3 → 0.0.4.pre.2
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/{LICENSE.txt → License.txt} +64 -3
- data/ext/xlsxwriter/libxlsxwriter/Makefile +42 -7
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/app.h +2 -2
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chart.h +2481 -97
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/common.h +41 -2
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/core.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/format.h +5 -5
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/packager.h +8 -3
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/styles.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/utility.h +1 -0
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/workbook.h +2 -2
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/worksheet.h +381 -1
- data/ext/xlsxwriter/libxlsxwriter/src/Makefile +25 -5
- data/ext/xlsxwriter/libxlsxwriter/src/app.c +17 -13
- data/ext/xlsxwriter/libxlsxwriter/src/chart.c +3903 -976
- data/ext/xlsxwriter/libxlsxwriter/src/content_types.c +18 -14
- data/ext/xlsxwriter/libxlsxwriter/src/core.c +9 -9
- data/ext/xlsxwriter/libxlsxwriter/src/format.c +2 -2
- data/ext/xlsxwriter/libxlsxwriter/src/packager.c +179 -95
- data/ext/xlsxwriter/libxlsxwriter/src/relationships.c +11 -8
- data/ext/xlsxwriter/libxlsxwriter/src/shared_strings.c +2 -0
- data/ext/xlsxwriter/libxlsxwriter/src/styles.c +10 -8
- data/ext/xlsxwriter/libxlsxwriter/src/utility.c +18 -1
- data/ext/xlsxwriter/libxlsxwriter/src/workbook.c +41 -25
- data/ext/xlsxwriter/libxlsxwriter/src/worksheet.c +672 -42
- data/ext/xlsxwriter/libxlsxwriter/third_party/minizip/Makefile +6 -1
- data/lib/xlsxwriter/version.rb +1 -1
- data/lib/xlsxwriter/worksheet.rb +11 -5
- metadata +6 -6
@@ -53,16 +53,19 @@ lxw_free_relationships(lxw_relationships *rels)
|
|
53
53
|
if (!rels)
|
54
54
|
return;
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
if (rels->relationships) {
|
57
|
+
while (!STAILQ_EMPTY(rels->relationships)) {
|
58
|
+
relationship = STAILQ_FIRST(rels->relationships);
|
59
|
+
STAILQ_REMOVE_HEAD(rels->relationships, list_pointers);
|
60
|
+
free(relationship->type);
|
61
|
+
free(relationship->target);
|
62
|
+
free(relationship->target_mode);
|
63
|
+
free(relationship);
|
64
|
+
}
|
65
|
+
|
66
|
+
free(rels->relationships);
|
63
67
|
}
|
64
68
|
|
65
|
-
free(rels->relationships);
|
66
69
|
free(rels);
|
67
70
|
}
|
68
71
|
|
@@ -19,8 +19,10 @@
|
|
19
19
|
STATIC int _element_cmp(struct sst_element *element1,
|
20
20
|
struct sst_element *element2);
|
21
21
|
|
22
|
+
#ifndef __clang_analyzer__
|
22
23
|
LXW_RB_GENERATE_ELEMENT(sst_rb_tree, sst_element, sst_tree_pointers,
|
23
24
|
_element_cmp);
|
25
|
+
#endif
|
24
26
|
|
25
27
|
/*****************************************************************************
|
26
28
|
*
|
@@ -54,13 +54,15 @@ lxw_styles_free(lxw_styles *styles)
|
|
54
54
|
return;
|
55
55
|
|
56
56
|
/* Free the formats in the styles. */
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
if (styles->xf_formats) {
|
58
|
+
while (!STAILQ_EMPTY(styles->xf_formats)) {
|
59
|
+
format = STAILQ_FIRST(styles->xf_formats);
|
60
|
+
STAILQ_REMOVE_HEAD(styles->xf_formats, list_pointers);
|
61
|
+
free(format);
|
62
|
+
}
|
63
|
+
free(styles->xf_formats);
|
61
64
|
}
|
62
65
|
|
63
|
-
free(styles->xf_formats);
|
64
66
|
free(styles);
|
65
67
|
}
|
66
68
|
|
@@ -151,13 +153,13 @@ _write_num_fmts(lxw_styles *self)
|
|
151
153
|
* Write the <sz> element.
|
152
154
|
*/
|
153
155
|
STATIC void
|
154
|
-
_write_font_size(lxw_styles *self,
|
156
|
+
_write_font_size(lxw_styles *self, double font_size)
|
155
157
|
{
|
156
158
|
struct xml_attribute_list attributes;
|
157
159
|
struct xml_attribute *attribute;
|
158
160
|
|
159
161
|
LXW_INIT_ATTRIBUTES();
|
160
|
-
|
162
|
+
LXW_PUSH_ATTRIBUTES_DBL("val", font_size);
|
161
163
|
|
162
164
|
lxw_xml_empty_tag(self->file, "sz", &attributes);
|
163
165
|
|
@@ -335,7 +337,7 @@ _write_font(lxw_styles *self, lxw_format *format)
|
|
335
337
|
if (format->font_script == LXW_FONT_SUBSCRIPT)
|
336
338
|
_write_vert_align(self, "subscript");
|
337
339
|
|
338
|
-
if (format->font_size)
|
340
|
+
if (format->font_size > 0.0)
|
339
341
|
_write_font_size(self, format->font_size);
|
340
342
|
|
341
343
|
if (format->theme)
|
@@ -28,6 +28,7 @@ char *error_strings[LXW_MAX_ERRNO + 1] = {
|
|
28
28
|
"Worksheet name exceeds Excel's limit of 31 characters.",
|
29
29
|
"Worksheet name contains invalid Excel character: '[]:*?/\\'",
|
30
30
|
"Worksheet name is already in use.",
|
31
|
+
"Parameter exceeds Excel's limit of 32 characters.",
|
31
32
|
"Parameter exceeds Excel's limit of 128 characters.",
|
32
33
|
"Parameter exceeds Excel's limit of 255 characters.",
|
33
34
|
"String exceeds Excel's limit of 32,767 characters.",
|
@@ -243,7 +244,10 @@ lxw_name_to_row(const char *row_str)
|
|
243
244
|
if (p)
|
244
245
|
row_num = atoi(p);
|
245
246
|
|
246
|
-
|
247
|
+
if (row_num)
|
248
|
+
return row_num - 1;
|
249
|
+
else
|
250
|
+
return 0;
|
247
251
|
}
|
248
252
|
|
249
253
|
/*
|
@@ -416,6 +420,19 @@ lxw_strdup(const char *str)
|
|
416
420
|
return copy;
|
417
421
|
}
|
418
422
|
|
423
|
+
/* Simple function to strdup() a formula string without the leading "=". */
|
424
|
+
char *
|
425
|
+
lxw_strdup_formula(const char *formula)
|
426
|
+
{
|
427
|
+
if (!formula)
|
428
|
+
return NULL;
|
429
|
+
|
430
|
+
if (formula[0] == '=')
|
431
|
+
return lxw_strdup(formula + 1);
|
432
|
+
else
|
433
|
+
return lxw_strdup(formula);
|
434
|
+
}
|
435
|
+
|
419
436
|
/* Simple strlen that counts UTF-8 characters. Assumes well formed UTF-8. */
|
420
437
|
size_t
|
421
438
|
lxw_utf8_strlen(const char *str)
|
@@ -14,8 +14,10 @@
|
|
14
14
|
#include "xlsxwriter/hash_table.h"
|
15
15
|
|
16
16
|
STATIC int _name_cmp(lxw_worksheet_name *name1, lxw_worksheet_name *name2);
|
17
|
+
#ifndef __clang_analyzer__
|
17
18
|
LXW_RB_GENERATE_NAMES(lxw_worksheet_names, lxw_worksheet_name, tree_pointers,
|
18
19
|
_name_cmp);
|
20
|
+
#endif
|
19
21
|
|
20
22
|
/*
|
21
23
|
* Forward declarations.
|
@@ -85,6 +87,7 @@ lxw_workbook_free(lxw_workbook *workbook)
|
|
85
87
|
lxw_chart *chart;
|
86
88
|
lxw_format *format;
|
87
89
|
lxw_defined_name *defined_name;
|
90
|
+
lxw_defined_name *defined_name_tmp;
|
88
91
|
lxw_custom_property *custom_property;
|
89
92
|
|
90
93
|
if (!workbook)
|
@@ -95,38 +98,56 @@ lxw_workbook_free(lxw_workbook *workbook)
|
|
95
98
|
free(workbook->filename);
|
96
99
|
|
97
100
|
/* Free the worksheets in the workbook. */
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
101
|
+
if (workbook->worksheets) {
|
102
|
+
while (!STAILQ_EMPTY(workbook->worksheets)) {
|
103
|
+
worksheet = STAILQ_FIRST(workbook->worksheets);
|
104
|
+
STAILQ_REMOVE_HEAD(workbook->worksheets, list_pointers);
|
105
|
+
lxw_worksheet_free(worksheet);
|
106
|
+
}
|
107
|
+
free(workbook->worksheets);
|
108
|
+
|
102
109
|
}
|
103
110
|
|
104
111
|
/* Free the charts in the workbook. */
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
112
|
+
if (workbook->charts) {
|
113
|
+
while (!STAILQ_EMPTY(workbook->charts)) {
|
114
|
+
chart = STAILQ_FIRST(workbook->charts);
|
115
|
+
STAILQ_REMOVE_HEAD(workbook->charts, list_pointers);
|
116
|
+
lxw_chart_free(chart);
|
117
|
+
}
|
118
|
+
free(workbook->charts);
|
109
119
|
}
|
110
120
|
|
111
121
|
/* Free the formats in the workbook. */
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
122
|
+
if (workbook->formats) {
|
123
|
+
while (!STAILQ_EMPTY(workbook->formats)) {
|
124
|
+
format = STAILQ_FIRST(workbook->formats);
|
125
|
+
STAILQ_REMOVE_HEAD(workbook->formats, list_pointers);
|
126
|
+
lxw_format_free(format);
|
127
|
+
}
|
128
|
+
free(workbook->formats);
|
116
129
|
}
|
117
130
|
|
118
131
|
/* Free the defined_names in the workbook. */
|
119
|
-
|
132
|
+
if (workbook->defined_names) {
|
120
133
|
defined_name = TAILQ_FIRST(workbook->defined_names);
|
121
|
-
|
122
|
-
|
134
|
+
while (defined_name) {
|
135
|
+
|
136
|
+
defined_name_tmp = TAILQ_NEXT(defined_name, list_pointers);
|
137
|
+
free(defined_name);
|
138
|
+
defined_name = defined_name_tmp;
|
139
|
+
}
|
140
|
+
free(workbook->defined_names);
|
123
141
|
}
|
124
142
|
|
125
143
|
/* Free the custom_properties in the workbook. */
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
144
|
+
if (workbook->custom_properties) {
|
145
|
+
while (!STAILQ_EMPTY(workbook->custom_properties)) {
|
146
|
+
custom_property = STAILQ_FIRST(workbook->custom_properties);
|
147
|
+
STAILQ_REMOVE_HEAD(workbook->custom_properties, list_pointers);
|
148
|
+
_free_custom_doc_property(custom_property);
|
149
|
+
}
|
150
|
+
free(workbook->custom_properties);
|
130
151
|
}
|
131
152
|
|
132
153
|
if (workbook->worksheet_names) {
|
@@ -147,12 +168,7 @@ lxw_workbook_free(lxw_workbook *workbook)
|
|
147
168
|
lxw_hash_free(workbook->used_xf_formats);
|
148
169
|
lxw_sst_free(workbook->sst);
|
149
170
|
free(workbook->options.tmpdir);
|
150
|
-
free(workbook->worksheets);
|
151
|
-
free(workbook->charts);
|
152
171
|
free(workbook->ordered_charts);
|
153
|
-
free(workbook->formats);
|
154
|
-
free(workbook->defined_names);
|
155
|
-
free(workbook->custom_properties);
|
156
172
|
free(workbook);
|
157
173
|
}
|
158
174
|
|
@@ -1493,7 +1509,7 @@ workbook_close(lxw_workbook *self)
|
|
1493
1509
|
{
|
1494
1510
|
lxw_worksheet *worksheet = NULL;
|
1495
1511
|
lxw_packager *packager = NULL;
|
1496
|
-
|
1512
|
+
lxw_error error = LXW_NO_ERROR;
|
1497
1513
|
|
1498
1514
|
/* Add a default worksheet if non have been added. */
|
1499
1515
|
if (!self->num_sheets)
|
@@ -15,11 +15,13 @@
|
|
15
15
|
#include "xlsxwriter/utility.h"
|
16
16
|
#include "xlsxwriter/relationships.h"
|
17
17
|
|
18
|
-
#define LXW_STR_MAX
|
19
|
-
#define LXW_BUFFER_SIZE
|
20
|
-
#define LXW_PORTRAIT
|
21
|
-
#define LXW_LANDSCAPE
|
22
|
-
#define LXW_PRINT_ACROSS
|
18
|
+
#define LXW_STR_MAX 32767
|
19
|
+
#define LXW_BUFFER_SIZE 4096
|
20
|
+
#define LXW_PORTRAIT 1
|
21
|
+
#define LXW_LANDSCAPE 0
|
22
|
+
#define LXW_PRINT_ACROSS 1
|
23
|
+
#define LXW_VALIDATION_MAX_TITLE_LENGTH 32
|
24
|
+
#define LXW_VALIDATION_MAX_STRING_LENGTH 255
|
23
25
|
|
24
26
|
/*
|
25
27
|
* Forward declarations.
|
@@ -28,8 +30,10 @@ STATIC void _worksheet_write_rows(lxw_worksheet *self);
|
|
28
30
|
STATIC int _row_cmp(lxw_row *row1, lxw_row *row2);
|
29
31
|
STATIC int _cell_cmp(lxw_cell *cell1, lxw_cell *cell2);
|
30
32
|
|
33
|
+
#ifndef __clang_analyzer__
|
31
34
|
LXW_RB_GENERATE_ROW(lxw_table_rows, lxw_row, tree_pointers, _row_cmp);
|
32
35
|
LXW_RB_GENERATE_CELL(lxw_table_cells, lxw_cell, tree_pointers, _cell_cmp);
|
36
|
+
#endif
|
33
37
|
|
34
38
|
/*****************************************************************************
|
35
39
|
*
|
@@ -121,6 +125,11 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
|
121
125
|
GOTO_LABEL_ON_MEM_ERROR(worksheet->selections, mem_error);
|
122
126
|
STAILQ_INIT(worksheet->selections);
|
123
127
|
|
128
|
+
worksheet->data_validations =
|
129
|
+
calloc(1, sizeof(struct lxw_data_validations));
|
130
|
+
GOTO_LABEL_ON_MEM_ERROR(worksheet->data_validations, mem_error);
|
131
|
+
STAILQ_INIT(worksheet->data_validations);
|
132
|
+
|
124
133
|
worksheet->external_hyperlinks = calloc(1, sizeof(struct lxw_rel_tuples));
|
125
134
|
GOTO_LABEL_ON_MEM_ERROR(worksheet->external_hyperlinks, mem_error);
|
126
135
|
STAILQ_INIT(worksheet->external_hyperlinks);
|
@@ -137,11 +146,7 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
|
137
146
|
if (init_data && init_data->optimize) {
|
138
147
|
FILE *tmpfile;
|
139
148
|
|
140
|
-
|
141
|
-
tmpfile = lxw_tmpfile(init_data->tmpdir);
|
142
|
-
else
|
143
|
-
tmpfile = lxw_tmpfile(NULL);
|
144
|
-
|
149
|
+
tmpfile = lxw_tmpfile(init_data->tmpdir);
|
145
150
|
if (!tmpfile) {
|
146
151
|
LXW_ERROR("Error creating tmpfile() for worksheet in "
|
147
152
|
"'constant_memory' mode.");
|
@@ -270,6 +275,26 @@ _free_image_options(lxw_image_options *image)
|
|
270
275
|
free(image);
|
271
276
|
}
|
272
277
|
|
278
|
+
/*
|
279
|
+
* Free a worksheet data_validation.
|
280
|
+
*/
|
281
|
+
STATIC void
|
282
|
+
_free_data_validation(lxw_data_validation *data_validation)
|
283
|
+
{
|
284
|
+
if (!data_validation)
|
285
|
+
return;
|
286
|
+
|
287
|
+
free(data_validation->value_formula);
|
288
|
+
free(data_validation->maximum_formula);
|
289
|
+
free(data_validation->input_title);
|
290
|
+
free(data_validation->input_message);
|
291
|
+
free(data_validation->error_title);
|
292
|
+
free(data_validation->error_message);
|
293
|
+
free(data_validation->minimum_formula);
|
294
|
+
|
295
|
+
free(data_validation);
|
296
|
+
}
|
297
|
+
|
273
298
|
/*
|
274
299
|
* Free a worksheet object.
|
275
300
|
*/
|
@@ -282,6 +307,7 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
282
307
|
lxw_merged_range *merged_range;
|
283
308
|
lxw_image_options *image_options;
|
284
309
|
lxw_selection *selection;
|
310
|
+
lxw_data_validation *data_validation;
|
285
311
|
lxw_rel_tuple *relationship;
|
286
312
|
|
287
313
|
if (!worksheet)
|
@@ -311,7 +337,6 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
311
337
|
}
|
312
338
|
|
313
339
|
if (worksheet->hyperlinks) {
|
314
|
-
|
315
340
|
for (row = RB_MIN(lxw_table_rows, worksheet->hyperlinks); row;
|
316
341
|
row = next_row) {
|
317
342
|
|
@@ -363,6 +388,16 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
363
388
|
free(worksheet->selections);
|
364
389
|
}
|
365
390
|
|
391
|
+
if (worksheet->data_validations) {
|
392
|
+
while (!STAILQ_EMPTY(worksheet->data_validations)) {
|
393
|
+
data_validation = STAILQ_FIRST(worksheet->data_validations);
|
394
|
+
STAILQ_REMOVE_HEAD(worksheet->data_validations, list_pointers);
|
395
|
+
_free_data_validation(data_validation);
|
396
|
+
}
|
397
|
+
|
398
|
+
free(worksheet->data_validations);
|
399
|
+
}
|
400
|
+
|
366
401
|
/* TODO. Add function for freeing the relationship lists. */
|
367
402
|
while (!STAILQ_EMPTY(worksheet->external_hyperlinks)) {
|
368
403
|
relationship = STAILQ_FIRST(worksheet->external_hyperlinks);
|
@@ -862,6 +897,61 @@ lxw_basename(const char *path)
|
|
862
897
|
return back_slash + 1;
|
863
898
|
}
|
864
899
|
|
900
|
+
/* Function to count the total concatenated length of the strings in a
|
901
|
+
* validation list array, including commas. */
|
902
|
+
size_t
|
903
|
+
_validation_list_length(char **list)
|
904
|
+
{
|
905
|
+
uint8_t i = 0;
|
906
|
+
size_t length = 0;
|
907
|
+
|
908
|
+
if (!list || !list[0])
|
909
|
+
return 0;
|
910
|
+
|
911
|
+
while (list[i] && length <= LXW_VALIDATION_MAX_STRING_LENGTH) {
|
912
|
+
/* Include commas in the length. */
|
913
|
+
length += 1 + lxw_utf8_strlen(list[i]);
|
914
|
+
i++;
|
915
|
+
}
|
916
|
+
|
917
|
+
/* Adjust the count for extraneous comma at end. */
|
918
|
+
length--;
|
919
|
+
|
920
|
+
return length;
|
921
|
+
}
|
922
|
+
|
923
|
+
/* Function to convert an array of strings into a CSV string for data
|
924
|
+
* validation lists. */
|
925
|
+
char *
|
926
|
+
_validation_list_to_csv(char **list)
|
927
|
+
{
|
928
|
+
uint8_t i = 0;
|
929
|
+
char *str;
|
930
|
+
|
931
|
+
/* Create a buffer for the concatenated, and quoted, string. */
|
932
|
+
/* Add +3 for quotes and EOL. */
|
933
|
+
str = calloc(1, LXW_VALIDATION_MAX_STRING_LENGTH + 3);
|
934
|
+
if (!str)
|
935
|
+
return NULL;
|
936
|
+
|
937
|
+
/* Add the start quote and first element. */
|
938
|
+
strcat(str, "\"");
|
939
|
+
strcat(str, list[0]);
|
940
|
+
|
941
|
+
/* Add the other elements preceded by a comma. */
|
942
|
+
i = 1;
|
943
|
+
while (list[i]) {
|
944
|
+
strcat(str, ",");
|
945
|
+
strcat(str, list[i]);
|
946
|
+
i++;
|
947
|
+
}
|
948
|
+
|
949
|
+
/* Add the end quote. */
|
950
|
+
strcat(str, "\"");
|
951
|
+
|
952
|
+
return str;
|
953
|
+
}
|
954
|
+
|
865
955
|
/*****************************************************************************
|
866
956
|
*
|
867
957
|
* XML functions.
|
@@ -2067,11 +2157,14 @@ _process_png(lxw_image_options *image_options)
|
|
2067
2157
|
uint32_t height = 0;
|
2068
2158
|
double x_dpi = 96;
|
2069
2159
|
double y_dpi = 96;
|
2160
|
+
int fseek_err;
|
2070
2161
|
|
2071
2162
|
FILE *stream = image_options->stream;
|
2072
2163
|
|
2073
2164
|
/* Skip another 4 bytes to the end of the PNG header. */
|
2074
|
-
fseek(stream, 4, SEEK_CUR);
|
2165
|
+
fseek_err = fseek(stream, 4, SEEK_CUR);
|
2166
|
+
if (fseek_err)
|
2167
|
+
goto file_error;
|
2075
2168
|
|
2076
2169
|
while (!feof(stream)) {
|
2077
2170
|
|
@@ -2131,17 +2224,16 @@ _process_png(lxw_image_options *image_options)
|
|
2131
2224
|
if (memcmp(type, "IEND", 4) == 0)
|
2132
2225
|
break;
|
2133
2226
|
|
2134
|
-
if (!feof(stream))
|
2135
|
-
fseek(stream, offset, SEEK_CUR);
|
2227
|
+
if (!feof(stream)) {
|
2228
|
+
fseek_err = fseek(stream, offset, SEEK_CUR);
|
2229
|
+
if (fseek_err)
|
2230
|
+
goto file_error;
|
2231
|
+
}
|
2136
2232
|
}
|
2137
2233
|
|
2138
2234
|
/* Ensure that we read some valid data from the file. */
|
2139
|
-
if (width == 0)
|
2140
|
-
|
2141
|
-
"no size data found in file: %s.",
|
2142
|
-
image_options->filename);
|
2143
|
-
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2144
|
-
}
|
2235
|
+
if (width == 0)
|
2236
|
+
goto file_error;
|
2145
2237
|
|
2146
2238
|
/* Set the image metadata. */
|
2147
2239
|
image_options->image_type = LXW_IMAGE_PNG;
|
@@ -2152,6 +2244,13 @@ _process_png(lxw_image_options *image_options)
|
|
2152
2244
|
image_options->extension = lxw_strdup("png");
|
2153
2245
|
|
2154
2246
|
return LXW_NO_ERROR;
|
2247
|
+
|
2248
|
+
file_error:
|
2249
|
+
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
2250
|
+
"no size data found in file: %s.",
|
2251
|
+
image_options->filename);
|
2252
|
+
|
2253
|
+
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2155
2254
|
}
|
2156
2255
|
|
2157
2256
|
/*
|
@@ -2167,11 +2266,14 @@ _process_jpeg(lxw_image_options *image_options)
|
|
2167
2266
|
uint16_t height = 0;
|
2168
2267
|
double x_dpi = 96;
|
2169
2268
|
double y_dpi = 96;
|
2269
|
+
int fseek_err;
|
2170
2270
|
|
2171
2271
|
FILE *stream = image_options->stream;
|
2172
2272
|
|
2173
2273
|
/* Read back 2 bytes to the end of the initial 0xFFD8 marker. */
|
2174
|
-
fseek(stream, -2, SEEK_CUR);
|
2274
|
+
fseek_err = fseek(stream, -2, SEEK_CUR);
|
2275
|
+
if (fseek_err)
|
2276
|
+
goto file_error;
|
2175
2277
|
|
2176
2278
|
/* Search through the image data to read the height and width in the */
|
2177
2279
|
/* 0xFFC0/C2 element. Also read the DPI in the 0xFFE0 element. */
|
@@ -2193,7 +2295,9 @@ _process_jpeg(lxw_image_options *image_options)
|
|
2193
2295
|
|
2194
2296
|
if (marker == 0xFFC0 || marker == 0xFFC2) {
|
2195
2297
|
/* Skip 1 byte to height and width. */
|
2196
|
-
fseek(stream, 1, SEEK_CUR);
|
2298
|
+
fseek_err = fseek(stream, 1, SEEK_CUR);
|
2299
|
+
if (fseek_err)
|
2300
|
+
goto file_error;
|
2197
2301
|
|
2198
2302
|
if (fread(&height, sizeof(height), 1, stream) < 1)
|
2199
2303
|
break;
|
@@ -2212,7 +2316,9 @@ _process_jpeg(lxw_image_options *image_options)
|
|
2212
2316
|
uint16_t y_density = 0;
|
2213
2317
|
uint8_t units = 1;
|
2214
2318
|
|
2215
|
-
fseek(stream, 7, SEEK_CUR);
|
2319
|
+
fseek_err = fseek(stream, 7, SEEK_CUR);
|
2320
|
+
if (fseek_err)
|
2321
|
+
goto file_error;
|
2216
2322
|
|
2217
2323
|
if (fread(&units, sizeof(units), 1, stream) < 1)
|
2218
2324
|
break;
|
@@ -2242,17 +2348,16 @@ _process_jpeg(lxw_image_options *image_options)
|
|
2242
2348
|
if (marker == 0xFFDA)
|
2243
2349
|
break;
|
2244
2350
|
|
2245
|
-
if (!feof(stream))
|
2246
|
-
fseek(stream, offset, SEEK_CUR);
|
2351
|
+
if (!feof(stream)) {
|
2352
|
+
fseek_err = fseek(stream, offset, SEEK_CUR);
|
2353
|
+
if (fseek_err)
|
2354
|
+
goto file_error;
|
2355
|
+
}
|
2247
2356
|
}
|
2248
2357
|
|
2249
2358
|
/* Ensure that we read some valid data from the file. */
|
2250
|
-
if (width == 0)
|
2251
|
-
|
2252
|
-
"no size data found in file: %s.",
|
2253
|
-
image_options->filename);
|
2254
|
-
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2255
|
-
}
|
2359
|
+
if (width == 0)
|
2360
|
+
goto file_error;
|
2256
2361
|
|
2257
2362
|
/* Set the image metadata. */
|
2258
2363
|
image_options->image_type = LXW_IMAGE_JPEG;
|
@@ -2263,6 +2368,13 @@ _process_jpeg(lxw_image_options *image_options)
|
|
2263
2368
|
image_options->extension = lxw_strdup("jpeg");
|
2264
2369
|
|
2265
2370
|
return LXW_NO_ERROR;
|
2371
|
+
|
2372
|
+
file_error:
|
2373
|
+
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
2374
|
+
"no size data found in file: %s.",
|
2375
|
+
image_options->filename);
|
2376
|
+
|
2377
|
+
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2266
2378
|
}
|
2267
2379
|
|
2268
2380
|
/*
|
@@ -2275,11 +2387,14 @@ _process_bmp(lxw_image_options *image_options)
|
|
2275
2387
|
uint32_t height = 0;
|
2276
2388
|
double x_dpi = 96;
|
2277
2389
|
double y_dpi = 96;
|
2390
|
+
int fseek_err;
|
2278
2391
|
|
2279
2392
|
FILE *stream = image_options->stream;
|
2280
2393
|
|
2281
2394
|
/* Skip another 14 bytes to the start of the BMP height/width. */
|
2282
|
-
fseek(stream, 14, SEEK_CUR);
|
2395
|
+
fseek_err = fseek(stream, 14, SEEK_CUR);
|
2396
|
+
if (fseek_err)
|
2397
|
+
goto file_error;
|
2283
2398
|
|
2284
2399
|
if (fread(&width, sizeof(width), 1, stream) < 1)
|
2285
2400
|
width = 0;
|
@@ -2288,12 +2403,8 @@ _process_bmp(lxw_image_options *image_options)
|
|
2288
2403
|
height = 0;
|
2289
2404
|
|
2290
2405
|
/* Ensure that we read some valid data from the file. */
|
2291
|
-
if (width == 0)
|
2292
|
-
|
2293
|
-
"no size data found in file: %s.",
|
2294
|
-
image_options->filename);
|
2295
|
-
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2296
|
-
}
|
2406
|
+
if (width == 0)
|
2407
|
+
goto file_error;
|
2297
2408
|
|
2298
2409
|
/* Set the image metadata. */
|
2299
2410
|
image_options->image_type = LXW_IMAGE_BMP;
|
@@ -2304,6 +2415,13 @@ _process_bmp(lxw_image_options *image_options)
|
|
2304
2415
|
image_options->extension = lxw_strdup("bmp");
|
2305
2416
|
|
2306
2417
|
return LXW_NO_ERROR;
|
2418
|
+
|
2419
|
+
file_error:
|
2420
|
+
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
2421
|
+
"no size data found in file: %s.",
|
2422
|
+
image_options->filename);
|
2423
|
+
|
2424
|
+
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2307
2425
|
}
|
2308
2426
|
|
2309
2427
|
/*
|
@@ -3286,6 +3404,224 @@ _write_drawings(lxw_worksheet *self)
|
|
3286
3404
|
_write_drawing(self, self->rel_count);
|
3287
3405
|
}
|
3288
3406
|
|
3407
|
+
/*
|
3408
|
+
* Write the <formula1> element for numbers.
|
3409
|
+
*/
|
3410
|
+
STATIC void
|
3411
|
+
_worksheet_write_formula1_num(lxw_worksheet *self, double number)
|
3412
|
+
{
|
3413
|
+
char data[LXW_ATTR_32];
|
3414
|
+
|
3415
|
+
lxw_snprintf(data, LXW_ATTR_32, "%.16g", number);
|
3416
|
+
|
3417
|
+
lxw_xml_data_element(self->file, "formula1", data, NULL);
|
3418
|
+
}
|
3419
|
+
|
3420
|
+
/*
|
3421
|
+
* Write the <formula1> element for strings/formulas.
|
3422
|
+
*/
|
3423
|
+
STATIC void
|
3424
|
+
_worksheet_write_formula1_str(lxw_worksheet *self, char *str)
|
3425
|
+
{
|
3426
|
+
lxw_xml_data_element(self->file, "formula1", str, NULL);
|
3427
|
+
}
|
3428
|
+
|
3429
|
+
/*
|
3430
|
+
* Write the <formula2> element for numbers.
|
3431
|
+
*/
|
3432
|
+
STATIC void
|
3433
|
+
_worksheet_write_formula2_num(lxw_worksheet *self, double number)
|
3434
|
+
{
|
3435
|
+
char data[LXW_ATTR_32];
|
3436
|
+
|
3437
|
+
lxw_snprintf(data, LXW_ATTR_32, "%.16g", number);
|
3438
|
+
|
3439
|
+
lxw_xml_data_element(self->file, "formula2", data, NULL);
|
3440
|
+
}
|
3441
|
+
|
3442
|
+
/*
|
3443
|
+
* Write the <formula2> element for strings/formulas.
|
3444
|
+
*/
|
3445
|
+
STATIC void
|
3446
|
+
_worksheet_write_formula2_str(lxw_worksheet *self, char *str)
|
3447
|
+
{
|
3448
|
+
lxw_xml_data_element(self->file, "formula2", str, NULL);
|
3449
|
+
}
|
3450
|
+
|
3451
|
+
/*
|
3452
|
+
* Write the <dataValidation> element.
|
3453
|
+
*/
|
3454
|
+
STATIC void
|
3455
|
+
_worksheet_write_data_validation(lxw_worksheet *self,
|
3456
|
+
lxw_data_validation *validation)
|
3457
|
+
{
|
3458
|
+
struct xml_attribute_list attributes;
|
3459
|
+
struct xml_attribute *attribute;
|
3460
|
+
uint8_t is_between = 0;
|
3461
|
+
|
3462
|
+
LXW_INIT_ATTRIBUTES();
|
3463
|
+
|
3464
|
+
switch (validation->validate) {
|
3465
|
+
case LXW_VALIDATION_TYPE_INTEGER:
|
3466
|
+
case LXW_VALIDATION_TYPE_INTEGER_FORMULA:
|
3467
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "whole");
|
3468
|
+
break;
|
3469
|
+
case LXW_VALIDATION_TYPE_DECIMAL:
|
3470
|
+
case LXW_VALIDATION_TYPE_DECIMAL_FORMULA:
|
3471
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "decimal");
|
3472
|
+
break;
|
3473
|
+
case LXW_VALIDATION_TYPE_LIST:
|
3474
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
3475
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "list");
|
3476
|
+
break;
|
3477
|
+
case LXW_VALIDATION_TYPE_DATE:
|
3478
|
+
case LXW_VALIDATION_TYPE_DATE_FORMULA:
|
3479
|
+
case LXW_VALIDATION_TYPE_DATE_NUMBER:
|
3480
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "date");
|
3481
|
+
break;
|
3482
|
+
case LXW_VALIDATION_TYPE_TIME:
|
3483
|
+
case LXW_VALIDATION_TYPE_TIME_FORMULA:
|
3484
|
+
case LXW_VALIDATION_TYPE_TIME_NUMBER:
|
3485
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "time");
|
3486
|
+
break;
|
3487
|
+
case LXW_VALIDATION_TYPE_LENGTH:
|
3488
|
+
case LXW_VALIDATION_TYPE_LENGTH_FORMULA:
|
3489
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "textLength");
|
3490
|
+
break;
|
3491
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
3492
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "custom");
|
3493
|
+
break;
|
3494
|
+
}
|
3495
|
+
|
3496
|
+
switch (validation->criteria) {
|
3497
|
+
case LXW_VALIDATION_CRITERIA_EQUAL_TO:
|
3498
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "equal");
|
3499
|
+
break;
|
3500
|
+
case LXW_VALIDATION_CRITERIA_NOT_EQUAL_TO:
|
3501
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "notEqual");
|
3502
|
+
break;
|
3503
|
+
case LXW_VALIDATION_CRITERIA_LESS_THAN:
|
3504
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "lessThan");
|
3505
|
+
break;
|
3506
|
+
case LXW_VALIDATION_CRITERIA_LESS_THAN_OR_EQUAL_TO:
|
3507
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "lessThanOrEqual");
|
3508
|
+
break;
|
3509
|
+
case LXW_VALIDATION_CRITERIA_GREATER_THAN:
|
3510
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "greaterThan");
|
3511
|
+
break;
|
3512
|
+
case LXW_VALIDATION_CRITERIA_GREATER_THAN_OR_EQUAL_TO:
|
3513
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "greaterThanOrEqual");
|
3514
|
+
break;
|
3515
|
+
case LXW_VALIDATION_CRITERIA_BETWEEN:
|
3516
|
+
/* Between is the default for 2 formulas and isn't added. */
|
3517
|
+
is_between = 1;
|
3518
|
+
break;
|
3519
|
+
case LXW_VALIDATION_CRITERIA_NOT_BETWEEN:
|
3520
|
+
is_between = 1;
|
3521
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "notBetween");
|
3522
|
+
break;
|
3523
|
+
}
|
3524
|
+
|
3525
|
+
if (validation->error_type == LXW_VALIDATION_ERROR_TYPE_WARNING)
|
3526
|
+
LXW_PUSH_ATTRIBUTES_STR("errorStyle", "warning");
|
3527
|
+
|
3528
|
+
if (validation->error_type == LXW_VALIDATION_ERROR_TYPE_INFORMATION)
|
3529
|
+
LXW_PUSH_ATTRIBUTES_STR("errorStyle", "information");
|
3530
|
+
|
3531
|
+
if (validation->ignore_blank)
|
3532
|
+
LXW_PUSH_ATTRIBUTES_INT("allowBlank", 1);
|
3533
|
+
|
3534
|
+
if (validation->dropdown == LXW_VALIDATION_OFF)
|
3535
|
+
LXW_PUSH_ATTRIBUTES_INT("showDropDown", 1);
|
3536
|
+
|
3537
|
+
if (validation->show_input)
|
3538
|
+
LXW_PUSH_ATTRIBUTES_INT("showInputMessage", 1);
|
3539
|
+
|
3540
|
+
if (validation->show_error)
|
3541
|
+
LXW_PUSH_ATTRIBUTES_INT("showErrorMessage", 1);
|
3542
|
+
|
3543
|
+
if (validation->error_title)
|
3544
|
+
LXW_PUSH_ATTRIBUTES_STR("errorTitle", validation->error_title);
|
3545
|
+
|
3546
|
+
if (validation->error_message)
|
3547
|
+
LXW_PUSH_ATTRIBUTES_STR("error", validation->error_message);
|
3548
|
+
|
3549
|
+
if (validation->input_title)
|
3550
|
+
LXW_PUSH_ATTRIBUTES_STR("promptTitle", validation->input_title);
|
3551
|
+
|
3552
|
+
if (validation->input_message)
|
3553
|
+
LXW_PUSH_ATTRIBUTES_STR("prompt", validation->input_message);
|
3554
|
+
|
3555
|
+
LXW_PUSH_ATTRIBUTES_STR("sqref", validation->sqref);
|
3556
|
+
|
3557
|
+
if (validation->validate == LXW_VALIDATION_TYPE_ANY)
|
3558
|
+
lxw_xml_empty_tag(self->file, "dataValidation", &attributes);
|
3559
|
+
else
|
3560
|
+
lxw_xml_start_tag(self->file, "dataValidation", &attributes);
|
3561
|
+
|
3562
|
+
/* Write the formula1 and formula2 elements. */
|
3563
|
+
switch (validation->validate) {
|
3564
|
+
case LXW_VALIDATION_TYPE_INTEGER:
|
3565
|
+
case LXW_VALIDATION_TYPE_DECIMAL:
|
3566
|
+
case LXW_VALIDATION_TYPE_LENGTH:
|
3567
|
+
case LXW_VALIDATION_TYPE_DATE:
|
3568
|
+
case LXW_VALIDATION_TYPE_TIME:
|
3569
|
+
case LXW_VALIDATION_TYPE_DATE_NUMBER:
|
3570
|
+
case LXW_VALIDATION_TYPE_TIME_NUMBER:
|
3571
|
+
_worksheet_write_formula1_num(self, validation->value_number);
|
3572
|
+
if (is_between)
|
3573
|
+
_worksheet_write_formula2_num(self,
|
3574
|
+
validation->maximum_number);
|
3575
|
+
break;
|
3576
|
+
case LXW_VALIDATION_TYPE_INTEGER_FORMULA:
|
3577
|
+
case LXW_VALIDATION_TYPE_DECIMAL_FORMULA:
|
3578
|
+
case LXW_VALIDATION_TYPE_LENGTH_FORMULA:
|
3579
|
+
case LXW_VALIDATION_TYPE_DATE_FORMULA:
|
3580
|
+
case LXW_VALIDATION_TYPE_TIME_FORMULA:
|
3581
|
+
case LXW_VALIDATION_TYPE_LIST:
|
3582
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
3583
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
3584
|
+
_worksheet_write_formula1_str(self, validation->value_formula);
|
3585
|
+
if (is_between)
|
3586
|
+
_worksheet_write_formula2_str(self,
|
3587
|
+
validation->maximum_formula);
|
3588
|
+
break;
|
3589
|
+
}
|
3590
|
+
|
3591
|
+
if (validation->validate != LXW_VALIDATION_TYPE_ANY)
|
3592
|
+
lxw_xml_end_tag(self->file, "dataValidation");
|
3593
|
+
|
3594
|
+
LXW_FREE_ATTRIBUTES();
|
3595
|
+
}
|
3596
|
+
|
3597
|
+
/*
|
3598
|
+
* Write the <dataValidations> element.
|
3599
|
+
*/
|
3600
|
+
STATIC void
|
3601
|
+
_worksheet_write_data_validations(lxw_worksheet *self)
|
3602
|
+
{
|
3603
|
+
struct xml_attribute_list attributes;
|
3604
|
+
struct xml_attribute *attribute;
|
3605
|
+
lxw_data_validation *data_validation;
|
3606
|
+
|
3607
|
+
if (self->num_validations == 0)
|
3608
|
+
return;
|
3609
|
+
|
3610
|
+
LXW_INIT_ATTRIBUTES();
|
3611
|
+
LXW_PUSH_ATTRIBUTES_INT("count", self->num_validations);
|
3612
|
+
|
3613
|
+
lxw_xml_start_tag(self->file, "dataValidations", &attributes);
|
3614
|
+
|
3615
|
+
STAILQ_FOREACH(data_validation, self->data_validations, list_pointers) {
|
3616
|
+
/* Write the dataValidation element. */
|
3617
|
+
_worksheet_write_data_validation(self, data_validation);
|
3618
|
+
}
|
3619
|
+
|
3620
|
+
lxw_xml_end_tag(self->file, "dataValidations");
|
3621
|
+
|
3622
|
+
LXW_FREE_ATTRIBUTES();
|
3623
|
+
}
|
3624
|
+
|
3289
3625
|
/*
|
3290
3626
|
* Assemble and write the XML file.
|
3291
3627
|
*/
|
@@ -3328,6 +3664,9 @@ lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
|
|
3328
3664
|
/* Write the mergeCells element. */
|
3329
3665
|
_worksheet_write_merge_cells(self);
|
3330
3666
|
|
3667
|
+
/* Write the dataValidations element. */
|
3668
|
+
_worksheet_write_data_validations(self);
|
3669
|
+
|
3331
3670
|
/* Write the hyperlink element. */
|
3332
3671
|
_worksheet_write_hyperlinks(self);
|
3333
3672
|
|
@@ -3405,7 +3744,7 @@ worksheet_write_string(lxw_worksheet *self,
|
|
3405
3744
|
if (format)
|
3406
3745
|
return worksheet_write_blank(self, row_num, col_num, format);
|
3407
3746
|
else
|
3408
|
-
return
|
3747
|
+
return LXW_NO_ERROR;
|
3409
3748
|
}
|
3410
3749
|
|
3411
3750
|
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
@@ -3533,7 +3872,7 @@ worksheet_write_array_formula_num(lxw_worksheet *self,
|
|
3533
3872
|
|
3534
3873
|
/* Define the array range. */
|
3535
3874
|
range = calloc(1, LXW_MAX_CELL_RANGE_LENGTH);
|
3536
|
-
RETURN_ON_MEM_ERROR(range,
|
3875
|
+
RETURN_ON_MEM_ERROR(range, LXW_ERROR_MEMORY_MALLOC_FAILED);
|
3537
3876
|
|
3538
3877
|
if (first_row == last_row && first_col == last_col)
|
3539
3878
|
lxw_rowcol_to_cell(range, first_row, last_col);
|
@@ -4119,7 +4458,7 @@ worksheet_merge_range(lxw_worksheet *self, lxw_row_t first_row,
|
|
4119
4458
|
|
4120
4459
|
/* Store the merge range. */
|
4121
4460
|
merged_range = calloc(1, sizeof(lxw_merged_range));
|
4122
|
-
RETURN_ON_MEM_ERROR(merged_range,
|
4461
|
+
RETURN_ON_MEM_ERROR(merged_range, LXW_ERROR_MEMORY_MALLOC_FAILED);
|
4123
4462
|
|
4124
4463
|
merged_range->first_row = first_row;
|
4125
4464
|
merged_range->first_col = first_col;
|
@@ -4861,12 +5200,16 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
4861
5200
|
if (!short_name) {
|
4862
5201
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
4863
5202
|
"couldn't get basename for file: %s.", filename);
|
5203
|
+
fclose(image_stream);
|
4864
5204
|
return LXW_ERROR_PARAMETER_VALIDATION;
|
4865
5205
|
}
|
4866
5206
|
|
4867
5207
|
/* Create a new object to hold the image options. */
|
4868
5208
|
options = calloc(1, sizeof(lxw_image_options));
|
4869
|
-
|
5209
|
+
if (!options) {
|
5210
|
+
fclose(image_stream);
|
5211
|
+
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
5212
|
+
}
|
4870
5213
|
|
4871
5214
|
if (user_options) {
|
4872
5215
|
memcpy(options, user_options, sizeof(lxw_image_options));
|
@@ -4889,10 +5232,12 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
4889
5232
|
|
4890
5233
|
if (_get_image_properties(options) == LXW_NO_ERROR) {
|
4891
5234
|
STAILQ_INSERT_TAIL(self->image_data, options, list_pointers);
|
5235
|
+
fclose(image_stream);
|
4892
5236
|
return LXW_NO_ERROR;
|
4893
5237
|
}
|
4894
5238
|
else {
|
4895
5239
|
free(options);
|
5240
|
+
fclose(image_stream);
|
4896
5241
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
4897
5242
|
}
|
4898
5243
|
}
|
@@ -4990,3 +5335,288 @@ worksheet_insert_chart(lxw_worksheet *self,
|
|
4990
5335
|
{
|
4991
5336
|
return worksheet_insert_chart_opt(self, row_num, col_num, chart, NULL);
|
4992
5337
|
}
|
5338
|
+
|
5339
|
+
/*
|
5340
|
+
* Add a data validation to a worksheet, for a range. Ironically this requires
|
5341
|
+
* a lot of validation of the user input.
|
5342
|
+
*/
|
5343
|
+
lxw_error
|
5344
|
+
worksheet_data_validation_range(lxw_worksheet *self, lxw_row_t first_row,
|
5345
|
+
lxw_col_t first_col,
|
5346
|
+
lxw_row_t last_row,
|
5347
|
+
lxw_col_t last_col,
|
5348
|
+
lxw_data_validation *validation)
|
5349
|
+
{
|
5350
|
+
lxw_data_validation *copy;
|
5351
|
+
uint8_t is_between = LXW_FALSE;
|
5352
|
+
uint8_t is_formula = LXW_FALSE;
|
5353
|
+
uint8_t has_criteria = LXW_TRUE;
|
5354
|
+
lxw_error err;
|
5355
|
+
lxw_row_t tmp_row;
|
5356
|
+
lxw_col_t tmp_col;
|
5357
|
+
size_t length;
|
5358
|
+
|
5359
|
+
/* No action is required for validation type 'any' unless there are
|
5360
|
+
* input messages to display.*/
|
5361
|
+
if (validation->validate == LXW_VALIDATION_TYPE_ANY
|
5362
|
+
&& !(validation->input_title || validation->input_message)) {
|
5363
|
+
|
5364
|
+
return LXW_NO_ERROR;
|
5365
|
+
}
|
5366
|
+
|
5367
|
+
/* Check for formula types. */
|
5368
|
+
switch (validation->validate) {
|
5369
|
+
case LXW_VALIDATION_TYPE_INTEGER_FORMULA:
|
5370
|
+
case LXW_VALIDATION_TYPE_DECIMAL_FORMULA:
|
5371
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
5372
|
+
case LXW_VALIDATION_TYPE_LENGTH_FORMULA:
|
5373
|
+
case LXW_VALIDATION_TYPE_DATE_FORMULA:
|
5374
|
+
case LXW_VALIDATION_TYPE_TIME_FORMULA:
|
5375
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
5376
|
+
is_formula = LXW_TRUE;
|
5377
|
+
break;
|
5378
|
+
}
|
5379
|
+
|
5380
|
+
/* Check for types without a criteria. */
|
5381
|
+
switch (validation->validate) {
|
5382
|
+
case LXW_VALIDATION_TYPE_LIST:
|
5383
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
5384
|
+
case LXW_VALIDATION_TYPE_ANY:
|
5385
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
5386
|
+
has_criteria = LXW_FALSE;
|
5387
|
+
break;
|
5388
|
+
}
|
5389
|
+
|
5390
|
+
/* Check that a validation parameter has been specified
|
5391
|
+
* except for 'list', 'any' and 'custom'. */
|
5392
|
+
if (has_criteria && validation->criteria == LXW_VALIDATION_CRITERIA_NONE) {
|
5393
|
+
|
5394
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5395
|
+
"criteria parameter must be specified.");
|
5396
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5397
|
+
}
|
5398
|
+
|
5399
|
+
/* Check for "between" criteria so we can do additional checks. */
|
5400
|
+
if (has_criteria
|
5401
|
+
&& (validation->criteria == LXW_VALIDATION_CRITERIA_BETWEEN
|
5402
|
+
|| validation->criteria == LXW_VALIDATION_CRITERIA_NOT_BETWEEN)) {
|
5403
|
+
|
5404
|
+
is_between = LXW_TRUE;
|
5405
|
+
}
|
5406
|
+
|
5407
|
+
/* Check that formula values are non NULL. */
|
5408
|
+
if (is_formula) {
|
5409
|
+
if (is_between) {
|
5410
|
+
if (!validation->minimum_formula) {
|
5411
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5412
|
+
"minimum_formula parameter cannot be NULL.");
|
5413
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5414
|
+
}
|
5415
|
+
if (!validation->maximum_formula) {
|
5416
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5417
|
+
"maximum_formula parameter cannot be NULL.");
|
5418
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5419
|
+
}
|
5420
|
+
}
|
5421
|
+
else {
|
5422
|
+
if (!validation->value_formula) {
|
5423
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5424
|
+
"formula parameter cannot be NULL.");
|
5425
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5426
|
+
}
|
5427
|
+
}
|
5428
|
+
}
|
5429
|
+
|
5430
|
+
/* Check Excel limitations on input strings. */
|
5431
|
+
if (validation->input_title) {
|
5432
|
+
length = lxw_utf8_strlen(validation->input_title);
|
5433
|
+
if (length > LXW_VALIDATION_MAX_TITLE_LENGTH) {
|
5434
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5435
|
+
"input_title length > Excel limit of %d.",
|
5436
|
+
LXW_VALIDATION_MAX_TITLE_LENGTH);
|
5437
|
+
return LXW_ERROR_32_STRING_LENGTH_EXCEEDED;
|
5438
|
+
}
|
5439
|
+
}
|
5440
|
+
|
5441
|
+
if (validation->error_title) {
|
5442
|
+
length = lxw_utf8_strlen(validation->error_title);
|
5443
|
+
if (length > LXW_VALIDATION_MAX_TITLE_LENGTH) {
|
5444
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5445
|
+
"error_title length > Excel limit of %d.",
|
5446
|
+
LXW_VALIDATION_MAX_TITLE_LENGTH);
|
5447
|
+
return LXW_ERROR_32_STRING_LENGTH_EXCEEDED;
|
5448
|
+
}
|
5449
|
+
}
|
5450
|
+
|
5451
|
+
if (validation->input_message) {
|
5452
|
+
length = lxw_utf8_strlen(validation->input_message);
|
5453
|
+
if (length > LXW_VALIDATION_MAX_STRING_LENGTH) {
|
5454
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5455
|
+
"input_message length > Excel limit of %d.",
|
5456
|
+
LXW_VALIDATION_MAX_STRING_LENGTH);
|
5457
|
+
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
|
5458
|
+
}
|
5459
|
+
}
|
5460
|
+
|
5461
|
+
if (validation->error_message) {
|
5462
|
+
length = lxw_utf8_strlen(validation->error_message);
|
5463
|
+
if (length > LXW_VALIDATION_MAX_STRING_LENGTH) {
|
5464
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5465
|
+
"error_message length > Excel limit of %d.",
|
5466
|
+
LXW_VALIDATION_MAX_STRING_LENGTH);
|
5467
|
+
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
|
5468
|
+
}
|
5469
|
+
}
|
5470
|
+
|
5471
|
+
if (validation->validate == LXW_VALIDATION_TYPE_LIST) {
|
5472
|
+
length = _validation_list_length(validation->value_list);
|
5473
|
+
|
5474
|
+
if (length == 0) {
|
5475
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5476
|
+
"list parameters cannot be zero.");
|
5477
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5478
|
+
}
|
5479
|
+
|
5480
|
+
if (length > LXW_VALIDATION_MAX_STRING_LENGTH) {
|
5481
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5482
|
+
"list length with commas > Excel limit of %d.",
|
5483
|
+
LXW_VALIDATION_MAX_STRING_LENGTH);
|
5484
|
+
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
|
5485
|
+
}
|
5486
|
+
}
|
5487
|
+
|
5488
|
+
/* Swap last row/col with first row/col as necessary */
|
5489
|
+
if (first_row > last_row) {
|
5490
|
+
tmp_row = last_row;
|
5491
|
+
last_row = first_row;
|
5492
|
+
first_row = tmp_row;
|
5493
|
+
}
|
5494
|
+
if (first_col > last_col) {
|
5495
|
+
tmp_col = last_col;
|
5496
|
+
last_col = first_col;
|
5497
|
+
first_col = tmp_col;
|
5498
|
+
}
|
5499
|
+
|
5500
|
+
/* Check that dimensions are valid but don't store them. */
|
5501
|
+
err = _check_dimensions(self, last_row, last_col, LXW_TRUE, LXW_TRUE);
|
5502
|
+
if (err)
|
5503
|
+
return err;
|
5504
|
+
|
5505
|
+
/* Create a copy of the parameters from the user data validation. */
|
5506
|
+
copy = calloc(1, sizeof(lxw_data_validation));
|
5507
|
+
GOTO_LABEL_ON_MEM_ERROR(copy, mem_error);
|
5508
|
+
|
5509
|
+
/* Create the data validation range. */
|
5510
|
+
if (first_row == last_row && first_col == last_col)
|
5511
|
+
lxw_rowcol_to_cell(copy->sqref, first_row, last_col);
|
5512
|
+
else
|
5513
|
+
lxw_rowcol_to_range(copy->sqref, first_row, first_col, last_row,
|
5514
|
+
last_col);
|
5515
|
+
|
5516
|
+
/* Copy the parameters from the user data validation. */
|
5517
|
+
copy->validate = validation->validate;
|
5518
|
+
copy->value_number = validation->value_number;
|
5519
|
+
copy->error_type = validation->error_type;
|
5520
|
+
copy->dropdown = validation->dropdown;
|
5521
|
+
copy->is_between = is_between;
|
5522
|
+
|
5523
|
+
if (has_criteria)
|
5524
|
+
copy->criteria = validation->criteria;
|
5525
|
+
|
5526
|
+
if (is_between) {
|
5527
|
+
copy->value_number = validation->minimum_number;
|
5528
|
+
copy->maximum_number = validation->maximum_number;
|
5529
|
+
}
|
5530
|
+
|
5531
|
+
/* Copy the input/error titles and messages. */
|
5532
|
+
if (validation->input_title) {
|
5533
|
+
copy->input_title = lxw_strdup_formula(validation->input_title);
|
5534
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->input_title, mem_error);
|
5535
|
+
}
|
5536
|
+
|
5537
|
+
if (validation->input_message) {
|
5538
|
+
copy->input_message = lxw_strdup_formula(validation->input_message);
|
5539
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->input_message, mem_error);
|
5540
|
+
}
|
5541
|
+
|
5542
|
+
if (validation->error_title) {
|
5543
|
+
copy->error_title = lxw_strdup_formula(validation->error_title);
|
5544
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->error_title, mem_error);
|
5545
|
+
}
|
5546
|
+
|
5547
|
+
if (validation->error_message) {
|
5548
|
+
copy->error_message = lxw_strdup_formula(validation->error_message);
|
5549
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->error_message, mem_error);
|
5550
|
+
}
|
5551
|
+
|
5552
|
+
/* Copy the formula strings. */
|
5553
|
+
if (is_formula) {
|
5554
|
+
if (is_between) {
|
5555
|
+
copy->value_formula =
|
5556
|
+
lxw_strdup_formula(validation->minimum_formula);
|
5557
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
5558
|
+
copy->maximum_formula =
|
5559
|
+
lxw_strdup_formula(validation->maximum_formula);
|
5560
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->maximum_formula, mem_error);
|
5561
|
+
}
|
5562
|
+
else {
|
5563
|
+
copy->value_formula =
|
5564
|
+
lxw_strdup_formula(validation->value_formula);
|
5565
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
5566
|
+
}
|
5567
|
+
}
|
5568
|
+
|
5569
|
+
/* Copy the validation list as a csv string. */
|
5570
|
+
if (validation->validate == LXW_VALIDATION_TYPE_LIST) {
|
5571
|
+
copy->value_formula = _validation_list_to_csv(validation->value_list);
|
5572
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
5573
|
+
}
|
5574
|
+
|
5575
|
+
if (validation->validate == LXW_VALIDATION_TYPE_LIST_FORMULA) {
|
5576
|
+
copy->value_formula = lxw_strdup_formula(validation->value_formula);
|
5577
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
5578
|
+
}
|
5579
|
+
|
5580
|
+
if (validation->validate == LXW_VALIDATION_TYPE_DATE
|
5581
|
+
|| validation->validate == LXW_VALIDATION_TYPE_TIME) {
|
5582
|
+
if (is_between) {
|
5583
|
+
copy->value_number =
|
5584
|
+
lxw_datetime_to_excel_date(&validation->minimum_datetime,
|
5585
|
+
LXW_EPOCH_1900);
|
5586
|
+
copy->maximum_number =
|
5587
|
+
lxw_datetime_to_excel_date(&validation->maximum_datetime,
|
5588
|
+
LXW_EPOCH_1900);
|
5589
|
+
}
|
5590
|
+
else {
|
5591
|
+
copy->value_number =
|
5592
|
+
lxw_datetime_to_excel_date(&validation->value_datetime,
|
5593
|
+
LXW_EPOCH_1900);
|
5594
|
+
}
|
5595
|
+
}
|
5596
|
+
|
5597
|
+
/* These options are on by default so we can't take plain booleans. */
|
5598
|
+
copy->ignore_blank = validation->ignore_blank ^ 1;
|
5599
|
+
copy->show_input = validation->show_input ^ 1;
|
5600
|
+
copy->show_error = validation->show_error ^ 1;
|
5601
|
+
|
5602
|
+
STAILQ_INSERT_TAIL(self->data_validations, copy, list_pointers);
|
5603
|
+
|
5604
|
+
self->num_validations++;
|
5605
|
+
|
5606
|
+
return LXW_NO_ERROR;
|
5607
|
+
|
5608
|
+
mem_error:
|
5609
|
+
_free_data_validation(copy);
|
5610
|
+
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
5611
|
+
}
|
5612
|
+
|
5613
|
+
/*
|
5614
|
+
* Add a data validation to a worksheet, for a cell.
|
5615
|
+
*/
|
5616
|
+
lxw_error
|
5617
|
+
worksheet_data_validation_cell(lxw_worksheet *self, lxw_row_t row,
|
5618
|
+
lxw_col_t col, lxw_data_validation *validation)
|
5619
|
+
{
|
5620
|
+
return worksheet_data_validation_range(self, row, col,
|
5621
|
+
row, col, validation);
|
5622
|
+
}
|