xlsxwriter 0.0.3 → 0.0.4.pre.2
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/{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
|
+
}
|