fast_excel 0.2.3 → 0.2.5
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/.gitignore +3 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +16 -16
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/fast_excel.gemspec +1 -1
- data/lib/fast_excel.rb +21 -5
- data/lib/fast_excel/binding/format.rb +3 -3
- data/libxlsxwriter/.drone.yml +27 -0
- data/libxlsxwriter/.indent.pro +3 -0
- data/libxlsxwriter/.travis.yml +12 -0
- data/libxlsxwriter/CMakeLists.txt +348 -0
- data/libxlsxwriter/Changes.txt +78 -0
- data/libxlsxwriter/LICENSE.txt +65 -4
- data/libxlsxwriter/Makefile +27 -7
- data/libxlsxwriter/Readme.md +2 -0
- data/libxlsxwriter/appveyor.yml +65 -0
- data/libxlsxwriter/cmake/FindMINIZIP.cmake +121 -0
- data/libxlsxwriter/cmake/FindPackage.cmake +183 -0
- data/libxlsxwriter/cmake/FindZLIB.cmake +123 -0
- data/libxlsxwriter/cmake/i686-toolchain.cmake +7 -0
- data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +1 -1
- data/libxlsxwriter/cocoapods/libxlsxwriter.modulemap +2 -2
- data/libxlsxwriter/include/xlsxwriter.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/app.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/chart.h +109 -8
- data/libxlsxwriter/include/xlsxwriter/common.h +10 -2
- data/libxlsxwriter/include/xlsxwriter/content_types.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/core.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/drawing.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/format.h +6 -6
- data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/packager.h +6 -1
- data/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/styles.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/utility.h +11 -5
- data/libxlsxwriter/include/xlsxwriter/workbook.h +3 -3
- data/libxlsxwriter/include/xlsxwriter/worksheet.h +517 -39
- data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +2 -2
- data/libxlsxwriter/libxlsxwriter.podspec +4 -2
- data/libxlsxwriter/src/Makefile +30 -5
- data/libxlsxwriter/src/app.c +1 -1
- data/libxlsxwriter/src/chart.c +76 -19
- data/libxlsxwriter/src/content_types.c +1 -1
- data/libxlsxwriter/src/core.c +10 -10
- data/libxlsxwriter/src/custom.c +2 -2
- data/libxlsxwriter/src/drawing.c +1 -1
- data/libxlsxwriter/src/format.c +3 -3
- data/libxlsxwriter/src/hash_table.c +1 -1
- data/libxlsxwriter/src/packager.c +20 -7
- data/libxlsxwriter/src/relationships.c +1 -1
- data/libxlsxwriter/src/shared_strings.c +1 -1
- data/libxlsxwriter/src/styles.c +4 -4
- data/libxlsxwriter/src/theme.c +1 -1
- data/libxlsxwriter/src/utility.c +41 -1
- data/libxlsxwriter/src/workbook.c +8 -6
- data/libxlsxwriter/src/worksheet.c +748 -31
- data/libxlsxwriter/src/xmlwriter.c +2 -2
- data/libxlsxwriter/third_party/minizip/Makefile +6 -1
- data/libxlsxwriter/version.txt +1 -1
- data/test/reopen_test.rb +22 -0
- data/test/test_helper.rb +8 -5
- data/test/validations_test.rb +27 -0
- metadata +11 -2
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2018, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -37,7 +37,12 @@ STATIC lxw_error _add_file_to_zip(lxw_packager *self, FILE * file,
|
|
37
37
|
#undef SLIST_ENTRY
|
38
38
|
|
39
39
|
#include <windows.h>
|
40
|
+
|
41
|
+
#ifdef USE_SYSTEM_MINIZIP
|
42
|
+
#include "minizip/iowin32.h"
|
43
|
+
#else
|
40
44
|
#include "../third_party/minizip/iowin32.h"
|
45
|
+
#endif
|
41
46
|
|
42
47
|
zipFile
|
43
48
|
_open_zipfile_win32(const char *filename)
|
@@ -57,7 +62,7 @@ _open_zipfile_win32(const char *filename)
|
|
57
62
|
}
|
58
63
|
|
59
64
|
/* Use the native Win32 file handling functions with minizip. */
|
60
|
-
|
65
|
+
fill_win32_filefunc64W(&filefunc);
|
61
66
|
|
62
67
|
return zipOpen2_64(wide_filename, 0, NULL, &filefunc);
|
63
68
|
}
|
@@ -196,6 +201,7 @@ _write_image_files(lxw_packager *self)
|
|
196
201
|
lxw_worksheet *worksheet;
|
197
202
|
lxw_image_options *image;
|
198
203
|
lxw_error err;
|
204
|
+
FILE *image_stream;
|
199
205
|
|
200
206
|
char filename[LXW_FILENAME_LENGTH] = { 0 };
|
201
207
|
uint16_t index = 1;
|
@@ -210,12 +216,19 @@ _write_image_files(lxw_packager *self)
|
|
210
216
|
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
|
211
217
|
"xl/media/image%d.%s", index++, image->extension);
|
212
218
|
|
213
|
-
|
219
|
+
/* Check that the image file exists and can be opened. */
|
220
|
+
image_stream = fopen(image->filename, "rb");
|
221
|
+
if (!image_stream) {
|
222
|
+
LXW_WARN_FORMAT1("Error adding image to xlsx file: file "
|
223
|
+
"doesn't exist or can't be opened: %s.",
|
224
|
+
image->filename);
|
225
|
+
return LXW_ERROR_CREATING_TMPFILE;
|
226
|
+
}
|
227
|
+
|
228
|
+
err = _add_file_to_zip(self, image_stream, filename);
|
229
|
+
fclose(image_stream);
|
214
230
|
|
215
|
-
err = _add_file_to_zip(self, image->stream, filename);
|
216
231
|
RETURN_ON_ERROR(err);
|
217
|
-
|
218
|
-
fclose(image->stream);
|
219
232
|
}
|
220
233
|
}
|
221
234
|
|
@@ -934,7 +947,7 @@ lxw_create_package(lxw_packager *self)
|
|
934
947
|
RETURN_ON_ERROR(error);
|
935
948
|
|
936
949
|
error = _write_image_files(self);
|
937
|
-
RETURN_ON_ERROR(error)
|
950
|
+
RETURN_ON_ERROR(error);
|
938
951
|
|
939
952
|
error = _write_root_rels_file(self);
|
940
953
|
RETURN_ON_ERROR(error);
|
data/libxlsxwriter/src/styles.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2018, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -153,13 +153,13 @@ _write_num_fmts(lxw_styles *self)
|
|
153
153
|
* Write the <sz> element.
|
154
154
|
*/
|
155
155
|
STATIC void
|
156
|
-
_write_font_size(lxw_styles *self,
|
156
|
+
_write_font_size(lxw_styles *self, double font_size)
|
157
157
|
{
|
158
158
|
struct xml_attribute_list attributes;
|
159
159
|
struct xml_attribute *attribute;
|
160
160
|
|
161
161
|
LXW_INIT_ATTRIBUTES();
|
162
|
-
|
162
|
+
LXW_PUSH_ATTRIBUTES_DBL("val", font_size);
|
163
163
|
|
164
164
|
lxw_xml_empty_tag(self->file, "sz", &attributes);
|
165
165
|
|
@@ -337,7 +337,7 @@ _write_font(lxw_styles *self, lxw_format *format)
|
|
337
337
|
if (format->font_script == LXW_FONT_SUBSCRIPT)
|
338
338
|
_write_vert_align(self, "subscript");
|
339
339
|
|
340
|
-
if (format->font_size)
|
340
|
+
if (format->font_size > 0.0)
|
341
341
|
_write_font_size(self, format->font_size);
|
342
342
|
|
343
343
|
if (format->theme)
|
data/libxlsxwriter/src/theme.c
CHANGED
data/libxlsxwriter/src/utility.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2018, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -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.",
|
@@ -419,6 +420,19 @@ lxw_strdup(const char *str)
|
|
419
420
|
return copy;
|
420
421
|
}
|
421
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
|
+
|
422
436
|
/* Simple strlen that counts UTF-8 characters. Assumes well formed UTF-8. */
|
423
437
|
size_t
|
424
438
|
lxw_utf8_strlen(const char *str)
|
@@ -513,3 +527,29 @@ lxw_tmpfile(char *tmpdir)
|
|
513
527
|
return tmpfile();
|
514
528
|
#endif
|
515
529
|
}
|
530
|
+
|
531
|
+
/*
|
532
|
+
* Sample function to handle sprintf of doubles for locale portable code. This
|
533
|
+
* is usually handled by a lxw_sprintf_dbl() macro but it can be replaced with
|
534
|
+
* a function of the same name.
|
535
|
+
*
|
536
|
+
* The code below is a simplified example that changes numbers like 123,45 to
|
537
|
+
* 123.45. End-users can replace this with something more rigorous if
|
538
|
+
* required.
|
539
|
+
*/
|
540
|
+
#ifdef USE_DOUBLE_FUNCTION
|
541
|
+
int
|
542
|
+
lxw_sprintf_dbl(char *data, double number)
|
543
|
+
{
|
544
|
+
char *tmp;
|
545
|
+
|
546
|
+
lxw_snprintf(data, LXW_ATTR_32, "%.16g", number);
|
547
|
+
|
548
|
+
/* Replace comma with decimal point. */
|
549
|
+
tmp = strchr(data, ',');
|
550
|
+
if (tmp)
|
551
|
+
*tmp = '.';
|
552
|
+
|
553
|
+
return 0;
|
554
|
+
}
|
555
|
+
#endif
|
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2018, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -404,7 +404,6 @@ _prepare_num_formats(lxw_workbook *self)
|
|
404
404
|
lxw_hash_element *used_format_element;
|
405
405
|
uint16_t index = 0xA4;
|
406
406
|
uint16_t num_format_count = 0;
|
407
|
-
char *num_format;
|
408
407
|
uint16_t *num_format_index;
|
409
408
|
|
410
409
|
LXW_FOREACH_ORDERED(used_format_element, self->used_xf_formats) {
|
@@ -415,12 +414,14 @@ _prepare_num_formats(lxw_workbook *self)
|
|
415
414
|
continue;
|
416
415
|
|
417
416
|
/* Check if there is a user defined number format string. */
|
418
|
-
|
417
|
+
if (*format->num_format) {
|
418
|
+
char num_format[LXW_FORMAT_FIELD_LEN] = { 0 };
|
419
|
+
lxw_snprintf(num_format, LXW_FORMAT_FIELD_LEN, "%s",
|
420
|
+
format->num_format);
|
419
421
|
|
420
|
-
if (*num_format) {
|
421
422
|
/* Look up the num_format in the hash table. */
|
422
423
|
hash_element = lxw_hash_key_exists(num_formats, num_format,
|
423
|
-
|
424
|
+
LXW_FORMAT_FIELD_LEN);
|
424
425
|
|
425
426
|
if (hash_element) {
|
426
427
|
/* Num_Format has already been used. */
|
@@ -432,7 +433,8 @@ _prepare_num_formats(lxw_workbook *self)
|
|
432
433
|
*num_format_index = index;
|
433
434
|
format->num_format_index = index;
|
434
435
|
lxw_insert_hash_element(num_formats, num_format,
|
435
|
-
num_format_index,
|
436
|
+
num_format_index,
|
437
|
+
LXW_FORMAT_FIELD_LEN);
|
436
438
|
index++;
|
437
439
|
num_format_count++;
|
438
440
|
}
|
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2018, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -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.
|
@@ -123,6 +125,11 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
|
123
125
|
GOTO_LABEL_ON_MEM_ERROR(worksheet->selections, mem_error);
|
124
126
|
STAILQ_INIT(worksheet->selections);
|
125
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
|
+
|
126
133
|
worksheet->external_hyperlinks = calloc(1, sizeof(struct lxw_rel_tuples));
|
127
134
|
GOTO_LABEL_ON_MEM_ERROR(worksheet->external_hyperlinks, mem_error);
|
128
135
|
STAILQ_INIT(worksheet->external_hyperlinks);
|
@@ -187,6 +194,9 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
|
187
194
|
worksheet->zoom_scale_normal = LXW_TRUE;
|
188
195
|
worksheet->show_zeros = LXW_TRUE;
|
189
196
|
worksheet->outline_on = LXW_TRUE;
|
197
|
+
worksheet->outline_style = LXW_TRUE;
|
198
|
+
worksheet->outline_below = LXW_TRUE;
|
199
|
+
worksheet->outline_right = LXW_FALSE;
|
190
200
|
worksheet->tab_color = LXW_COLOR_UNSET;
|
191
201
|
|
192
202
|
if (init_data) {
|
@@ -268,6 +278,26 @@ _free_image_options(lxw_image_options *image)
|
|
268
278
|
free(image);
|
269
279
|
}
|
270
280
|
|
281
|
+
/*
|
282
|
+
* Free a worksheet data_validation.
|
283
|
+
*/
|
284
|
+
STATIC void
|
285
|
+
_free_data_validation(lxw_data_validation *data_validation)
|
286
|
+
{
|
287
|
+
if (!data_validation)
|
288
|
+
return;
|
289
|
+
|
290
|
+
free(data_validation->value_formula);
|
291
|
+
free(data_validation->maximum_formula);
|
292
|
+
free(data_validation->input_title);
|
293
|
+
free(data_validation->input_message);
|
294
|
+
free(data_validation->error_title);
|
295
|
+
free(data_validation->error_message);
|
296
|
+
free(data_validation->minimum_formula);
|
297
|
+
|
298
|
+
free(data_validation);
|
299
|
+
}
|
300
|
+
|
271
301
|
/*
|
272
302
|
* Free a worksheet object.
|
273
303
|
*/
|
@@ -280,6 +310,7 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
280
310
|
lxw_merged_range *merged_range;
|
281
311
|
lxw_image_options *image_options;
|
282
312
|
lxw_selection *selection;
|
313
|
+
lxw_data_validation *data_validation;
|
283
314
|
lxw_rel_tuple *relationship;
|
284
315
|
|
285
316
|
if (!worksheet)
|
@@ -309,7 +340,6 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
309
340
|
}
|
310
341
|
|
311
342
|
if (worksheet->hyperlinks) {
|
312
|
-
|
313
343
|
for (row = RB_MIN(lxw_table_rows, worksheet->hyperlinks); row;
|
314
344
|
row = next_row) {
|
315
345
|
|
@@ -361,6 +391,16 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
361
391
|
free(worksheet->selections);
|
362
392
|
}
|
363
393
|
|
394
|
+
if (worksheet->data_validations) {
|
395
|
+
while (!STAILQ_EMPTY(worksheet->data_validations)) {
|
396
|
+
data_validation = STAILQ_FIRST(worksheet->data_validations);
|
397
|
+
STAILQ_REMOVE_HEAD(worksheet->data_validations, list_pointers);
|
398
|
+
_free_data_validation(data_validation);
|
399
|
+
}
|
400
|
+
|
401
|
+
free(worksheet->data_validations);
|
402
|
+
}
|
403
|
+
|
364
404
|
/* TODO. Add function for freeing the relationship lists. */
|
365
405
|
while (!STAILQ_EMPTY(worksheet->external_hyperlinks)) {
|
366
406
|
relationship = STAILQ_FIRST(worksheet->external_hyperlinks);
|
@@ -860,6 +900,61 @@ lxw_basename(const char *path)
|
|
860
900
|
return back_slash + 1;
|
861
901
|
}
|
862
902
|
|
903
|
+
/* Function to count the total concatenated length of the strings in a
|
904
|
+
* validation list array, including commas. */
|
905
|
+
size_t
|
906
|
+
_validation_list_length(char **list)
|
907
|
+
{
|
908
|
+
uint8_t i = 0;
|
909
|
+
size_t length = 0;
|
910
|
+
|
911
|
+
if (!list || !list[0])
|
912
|
+
return 0;
|
913
|
+
|
914
|
+
while (list[i] && length <= LXW_VALIDATION_MAX_STRING_LENGTH) {
|
915
|
+
/* Include commas in the length. */
|
916
|
+
length += 1 + lxw_utf8_strlen(list[i]);
|
917
|
+
i++;
|
918
|
+
}
|
919
|
+
|
920
|
+
/* Adjust the count for extraneous comma at end. */
|
921
|
+
length--;
|
922
|
+
|
923
|
+
return length;
|
924
|
+
}
|
925
|
+
|
926
|
+
/* Function to convert an array of strings into a CSV string for data
|
927
|
+
* validation lists. */
|
928
|
+
char *
|
929
|
+
_validation_list_to_csv(char **list)
|
930
|
+
{
|
931
|
+
uint8_t i = 0;
|
932
|
+
char *str;
|
933
|
+
|
934
|
+
/* Create a buffer for the concatenated, and quoted, string. */
|
935
|
+
/* Add +3 for quotes and EOL. */
|
936
|
+
str = calloc(1, LXW_VALIDATION_MAX_STRING_LENGTH + 3);
|
937
|
+
if (!str)
|
938
|
+
return NULL;
|
939
|
+
|
940
|
+
/* Add the start quote and first element. */
|
941
|
+
strcat(str, "\"");
|
942
|
+
strcat(str, list[0]);
|
943
|
+
|
944
|
+
/* Add the other elements preceded by a comma. */
|
945
|
+
i = 1;
|
946
|
+
while (list[i]) {
|
947
|
+
strcat(str, ",");
|
948
|
+
strcat(str, list[i]);
|
949
|
+
i++;
|
950
|
+
}
|
951
|
+
|
952
|
+
/* Add the end quote. */
|
953
|
+
strcat(str, "\"");
|
954
|
+
|
955
|
+
return str;
|
956
|
+
}
|
957
|
+
|
863
958
|
/*****************************************************************************
|
864
959
|
*
|
865
960
|
* XML functions.
|
@@ -1372,6 +1467,12 @@ _worksheet_write_sheet_format_pr(lxw_worksheet *self)
|
|
1372
1467
|
if (self->default_row_zeroed)
|
1373
1468
|
LXW_PUSH_ATTRIBUTES_STR("zeroHeight", "1");
|
1374
1469
|
|
1470
|
+
if (self->outline_row_level)
|
1471
|
+
LXW_PUSH_ATTRIBUTES_INT("outlineLevelRow", self->outline_row_level);
|
1472
|
+
|
1473
|
+
if (self->outline_col_level)
|
1474
|
+
LXW_PUSH_ATTRIBUTES_INT("outlineLevelCol", self->outline_col_level);
|
1475
|
+
|
1375
1476
|
lxw_xml_empty_tag(self->file, "sheetFormatPr", &attributes);
|
1376
1477
|
|
1377
1478
|
LXW_FREE_ATTRIBUTES();
|
@@ -1608,6 +1709,9 @@ _write_row(lxw_worksheet *self, lxw_row *row, char *spans)
|
|
1608
1709
|
if (height != LXW_DEF_ROW_HEIGHT)
|
1609
1710
|
LXW_PUSH_ATTRIBUTES_STR("customHeight", "1");
|
1610
1711
|
|
1712
|
+
if (row->level)
|
1713
|
+
LXW_PUSH_ATTRIBUTES_INT("outlineLevel", row->level);
|
1714
|
+
|
1611
1715
|
if (row->collapsed)
|
1612
1716
|
LXW_PUSH_ATTRIBUTES_STR("collapsed", "1");
|
1613
1717
|
|
@@ -2183,8 +2287,7 @@ _process_jpeg(lxw_image_options *image_options)
|
|
2183
2287
|
if (fseek_err)
|
2184
2288
|
goto file_error;
|
2185
2289
|
|
2186
|
-
/* Search through the image data
|
2187
|
-
/* 0xFFC0/C2 element. Also read the DPI in the 0xFFE0 element. */
|
2290
|
+
/* Search through the image data and read the JPEG markers. */
|
2188
2291
|
while (!feof(stream)) {
|
2189
2292
|
|
2190
2293
|
/* Read the JPEG marker and length fields for the sub-section. */
|
@@ -2201,7 +2304,10 @@ _process_jpeg(lxw_image_options *image_options)
|
|
2201
2304
|
/* The offset for next fseek() is the field length + type length. */
|
2202
2305
|
offset = length - 2;
|
2203
2306
|
|
2204
|
-
|
2307
|
+
/* Read the height and width in the 0xFFCn elements (except C4, C8 */
|
2308
|
+
/* and CC which aren't SOF markers). */
|
2309
|
+
if ((marker & 0xFFF0) == 0xFFC0 && marker != 0xFFC4
|
2310
|
+
&& marker != 0xFFC8 && marker != 0xFFCC) {
|
2205
2311
|
/* Skip 1 byte to height and width. */
|
2206
2312
|
fseek_err = fseek(stream, 1, SEEK_CUR);
|
2207
2313
|
if (fseek_err)
|
@@ -2219,6 +2325,7 @@ _process_jpeg(lxw_image_options *image_options)
|
|
2219
2325
|
offset -= 9;
|
2220
2326
|
}
|
2221
2327
|
|
2328
|
+
/* Read the DPI in the 0xFFE0 element. */
|
2222
2329
|
if (marker == 0xFFE0) {
|
2223
2330
|
uint16_t x_density = 0;
|
2224
2331
|
uint16_t y_density = 0;
|
@@ -2314,6 +2421,9 @@ _process_bmp(lxw_image_options *image_options)
|
|
2314
2421
|
if (width == 0)
|
2315
2422
|
goto file_error;
|
2316
2423
|
|
2424
|
+
height = LXW_UINT32_HOST(height);
|
2425
|
+
width = LXW_UINT32_HOST(width);
|
2426
|
+
|
2317
2427
|
/* Set the image metadata. */
|
2318
2428
|
image_options->image_type = LXW_IMAGE_BMP;
|
2319
2429
|
image_options->width = width;
|
@@ -2385,6 +2495,18 @@ STATIC void
|
|
2385
2495
|
_write_number_cell(lxw_worksheet *self, char *range,
|
2386
2496
|
int32_t style_index, lxw_cell *cell)
|
2387
2497
|
{
|
2498
|
+
#ifdef USE_DOUBLE_FUNCTION
|
2499
|
+
char data[LXW_ATTR_32];
|
2500
|
+
|
2501
|
+
lxw_sprintf_dbl(data, cell->u.number);
|
2502
|
+
|
2503
|
+
if (style_index)
|
2504
|
+
fprintf(self->file,
|
2505
|
+
"<c r=\"%s\" s=\"%d\"><v>%s</v></c>",
|
2506
|
+
range, style_index, data);
|
2507
|
+
else
|
2508
|
+
fprintf(self->file, "<c r=\"%s\"><v>%s</v></c>", range, data);
|
2509
|
+
#else
|
2388
2510
|
if (style_index)
|
2389
2511
|
fprintf(self->file,
|
2390
2512
|
"<c r=\"%s\" s=\"%d\"><v>%.16g</v></c>",
|
@@ -2392,6 +2514,8 @@ _write_number_cell(lxw_worksheet *self, char *range,
|
|
2392
2514
|
else
|
2393
2515
|
fprintf(self->file,
|
2394
2516
|
"<c r=\"%s\"><v>%.16g</v></c>", range, cell->u.number);
|
2517
|
+
|
2518
|
+
#endif
|
2395
2519
|
}
|
2396
2520
|
|
2397
2521
|
/*
|
@@ -2402,6 +2526,7 @@ STATIC void
|
|
2402
2526
|
_write_string_cell(lxw_worksheet *self, char *range,
|
2403
2527
|
int32_t style_index, lxw_cell *cell)
|
2404
2528
|
{
|
2529
|
+
|
2405
2530
|
if (style_index)
|
2406
2531
|
fprintf(self->file,
|
2407
2532
|
"<c r=\"%s\" s=\"%d\" t=\"s\"><v>%d</v></c>",
|
@@ -2459,8 +2584,7 @@ _write_formula_num_cell(lxw_worksheet *self, lxw_cell *cell)
|
|
2459
2584
|
{
|
2460
2585
|
char data[LXW_ATTR_32];
|
2461
2586
|
|
2462
|
-
|
2463
|
-
|
2587
|
+
lxw_sprintf_dbl(data, cell->formula_result);
|
2464
2588
|
lxw_xml_data_element(self->file, "f", cell->u.string, NULL);
|
2465
2589
|
lxw_xml_data_element(self->file, "v", data, NULL);
|
2466
2590
|
}
|
@@ -2479,7 +2603,7 @@ _write_array_formula_num_cell(lxw_worksheet *self, lxw_cell *cell)
|
|
2479
2603
|
LXW_PUSH_ATTRIBUTES_STR("t", "array");
|
2480
2604
|
LXW_PUSH_ATTRIBUTES_STR("ref", cell->user_data1);
|
2481
2605
|
|
2482
|
-
|
2606
|
+
lxw_sprintf_dbl(data, cell->formula_result);
|
2483
2607
|
|
2484
2608
|
lxw_xml_data_element(self->file, "f", cell->u.string, &attributes);
|
2485
2609
|
lxw_xml_data_element(self->file, "v", data, NULL);
|
@@ -2515,8 +2639,10 @@ _write_boolean_cell(lxw_worksheet *self, lxw_cell *cell)
|
|
2515
2639
|
STATIC void
|
2516
2640
|
_calculate_spans(struct lxw_row *row, char *span, int32_t *block_num)
|
2517
2641
|
{
|
2518
|
-
|
2519
|
-
|
2642
|
+
lxw_cell *cell_min = RB_MIN(lxw_table_cells, row->cells);
|
2643
|
+
lxw_cell *cell_max = RB_MAX(lxw_table_cells, row->cells);
|
2644
|
+
lxw_col_t span_col_min = cell_min->col_num;
|
2645
|
+
lxw_col_t span_col_max = cell_max->col_num;
|
2520
2646
|
lxw_col_t col_min;
|
2521
2647
|
lxw_col_t col_max;
|
2522
2648
|
*block_num = row->row_num / 16;
|
@@ -2526,8 +2652,10 @@ _calculate_spans(struct lxw_row *row, char *span, int32_t *block_num)
|
|
2526
2652
|
while (row && (int32_t) (row->row_num / 16) == *block_num) {
|
2527
2653
|
|
2528
2654
|
if (!RB_EMPTY(row->cells)) {
|
2529
|
-
|
2530
|
-
|
2655
|
+
cell_min = RB_MIN(lxw_table_cells, row->cells);
|
2656
|
+
cell_max = RB_MAX(lxw_table_cells, row->cells);
|
2657
|
+
col_min = cell_min->col_num;
|
2658
|
+
col_max = cell_max->col_num;
|
2531
2659
|
|
2532
2660
|
if (col_min < span_col_min)
|
2533
2661
|
span_col_min = col_min;
|
@@ -2922,6 +3050,37 @@ _worksheet_write_tab_color(lxw_worksheet *self)
|
|
2922
3050
|
LXW_FREE_ATTRIBUTES();
|
2923
3051
|
}
|
2924
3052
|
|
3053
|
+
/*
|
3054
|
+
* Write the <outlinePr> element.
|
3055
|
+
*/
|
3056
|
+
STATIC void
|
3057
|
+
_worksheet_write_outline_pr(lxw_worksheet *self)
|
3058
|
+
{
|
3059
|
+
struct xml_attribute_list attributes;
|
3060
|
+
struct xml_attribute *attribute;
|
3061
|
+
|
3062
|
+
if (!self->outline_changed)
|
3063
|
+
return;
|
3064
|
+
|
3065
|
+
LXW_INIT_ATTRIBUTES();
|
3066
|
+
|
3067
|
+
if (self->outline_style)
|
3068
|
+
LXW_PUSH_ATTRIBUTES_STR("applyStyles", "1");
|
3069
|
+
|
3070
|
+
if (!self->outline_below)
|
3071
|
+
LXW_PUSH_ATTRIBUTES_STR("summaryBelow", "0");
|
3072
|
+
|
3073
|
+
if (!self->outline_right)
|
3074
|
+
LXW_PUSH_ATTRIBUTES_STR("summaryRight", "0");
|
3075
|
+
|
3076
|
+
if (!self->outline_on)
|
3077
|
+
LXW_PUSH_ATTRIBUTES_STR("showOutlineSymbols", "0");
|
3078
|
+
|
3079
|
+
lxw_xml_empty_tag(self->file, "outlinePr", &attributes);
|
3080
|
+
|
3081
|
+
LXW_FREE_ATTRIBUTES();
|
3082
|
+
}
|
3083
|
+
|
2925
3084
|
/*
|
2926
3085
|
* Write the <sheetPr> element for Sheet level properties.
|
2927
3086
|
*/
|
@@ -2950,7 +3109,7 @@ _worksheet_write_sheet_pr(lxw_worksheet *self)
|
|
2950
3109
|
|| self->outline_changed) {
|
2951
3110
|
lxw_xml_start_tag(self->file, "sheetPr", &attributes);
|
2952
3111
|
_worksheet_write_tab_color(self);
|
2953
|
-
|
3112
|
+
_worksheet_write_outline_pr(self);
|
2954
3113
|
_worksheet_write_page_set_up_pr(self);
|
2955
3114
|
lxw_xml_end_tag(self->file, "sheetPr");
|
2956
3115
|
}
|
@@ -3312,6 +3471,224 @@ _write_drawings(lxw_worksheet *self)
|
|
3312
3471
|
_write_drawing(self, self->rel_count);
|
3313
3472
|
}
|
3314
3473
|
|
3474
|
+
/*
|
3475
|
+
* Write the <formula1> element for numbers.
|
3476
|
+
*/
|
3477
|
+
STATIC void
|
3478
|
+
_worksheet_write_formula1_num(lxw_worksheet *self, double number)
|
3479
|
+
{
|
3480
|
+
char data[LXW_ATTR_32];
|
3481
|
+
|
3482
|
+
lxw_sprintf_dbl(data, number);
|
3483
|
+
|
3484
|
+
lxw_xml_data_element(self->file, "formula1", data, NULL);
|
3485
|
+
}
|
3486
|
+
|
3487
|
+
/*
|
3488
|
+
* Write the <formula1> element for strings/formulas.
|
3489
|
+
*/
|
3490
|
+
STATIC void
|
3491
|
+
_worksheet_write_formula1_str(lxw_worksheet *self, char *str)
|
3492
|
+
{
|
3493
|
+
lxw_xml_data_element(self->file, "formula1", str, NULL);
|
3494
|
+
}
|
3495
|
+
|
3496
|
+
/*
|
3497
|
+
* Write the <formula2> element for numbers.
|
3498
|
+
*/
|
3499
|
+
STATIC void
|
3500
|
+
_worksheet_write_formula2_num(lxw_worksheet *self, double number)
|
3501
|
+
{
|
3502
|
+
char data[LXW_ATTR_32];
|
3503
|
+
|
3504
|
+
lxw_sprintf_dbl(data, number);
|
3505
|
+
|
3506
|
+
lxw_xml_data_element(self->file, "formula2", data, NULL);
|
3507
|
+
}
|
3508
|
+
|
3509
|
+
/*
|
3510
|
+
* Write the <formula2> element for strings/formulas.
|
3511
|
+
*/
|
3512
|
+
STATIC void
|
3513
|
+
_worksheet_write_formula2_str(lxw_worksheet *self, char *str)
|
3514
|
+
{
|
3515
|
+
lxw_xml_data_element(self->file, "formula2", str, NULL);
|
3516
|
+
}
|
3517
|
+
|
3518
|
+
/*
|
3519
|
+
* Write the <dataValidation> element.
|
3520
|
+
*/
|
3521
|
+
STATIC void
|
3522
|
+
_worksheet_write_data_validation(lxw_worksheet *self,
|
3523
|
+
lxw_data_validation *validation)
|
3524
|
+
{
|
3525
|
+
struct xml_attribute_list attributes;
|
3526
|
+
struct xml_attribute *attribute;
|
3527
|
+
uint8_t is_between = 0;
|
3528
|
+
|
3529
|
+
LXW_INIT_ATTRIBUTES();
|
3530
|
+
|
3531
|
+
switch (validation->validate) {
|
3532
|
+
case LXW_VALIDATION_TYPE_INTEGER:
|
3533
|
+
case LXW_VALIDATION_TYPE_INTEGER_FORMULA:
|
3534
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "whole");
|
3535
|
+
break;
|
3536
|
+
case LXW_VALIDATION_TYPE_DECIMAL:
|
3537
|
+
case LXW_VALIDATION_TYPE_DECIMAL_FORMULA:
|
3538
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "decimal");
|
3539
|
+
break;
|
3540
|
+
case LXW_VALIDATION_TYPE_LIST:
|
3541
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
3542
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "list");
|
3543
|
+
break;
|
3544
|
+
case LXW_VALIDATION_TYPE_DATE:
|
3545
|
+
case LXW_VALIDATION_TYPE_DATE_FORMULA:
|
3546
|
+
case LXW_VALIDATION_TYPE_DATE_NUMBER:
|
3547
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "date");
|
3548
|
+
break;
|
3549
|
+
case LXW_VALIDATION_TYPE_TIME:
|
3550
|
+
case LXW_VALIDATION_TYPE_TIME_FORMULA:
|
3551
|
+
case LXW_VALIDATION_TYPE_TIME_NUMBER:
|
3552
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "time");
|
3553
|
+
break;
|
3554
|
+
case LXW_VALIDATION_TYPE_LENGTH:
|
3555
|
+
case LXW_VALIDATION_TYPE_LENGTH_FORMULA:
|
3556
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "textLength");
|
3557
|
+
break;
|
3558
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
3559
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "custom");
|
3560
|
+
break;
|
3561
|
+
}
|
3562
|
+
|
3563
|
+
switch (validation->criteria) {
|
3564
|
+
case LXW_VALIDATION_CRITERIA_EQUAL_TO:
|
3565
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "equal");
|
3566
|
+
break;
|
3567
|
+
case LXW_VALIDATION_CRITERIA_NOT_EQUAL_TO:
|
3568
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "notEqual");
|
3569
|
+
break;
|
3570
|
+
case LXW_VALIDATION_CRITERIA_LESS_THAN:
|
3571
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "lessThan");
|
3572
|
+
break;
|
3573
|
+
case LXW_VALIDATION_CRITERIA_LESS_THAN_OR_EQUAL_TO:
|
3574
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "lessThanOrEqual");
|
3575
|
+
break;
|
3576
|
+
case LXW_VALIDATION_CRITERIA_GREATER_THAN:
|
3577
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "greaterThan");
|
3578
|
+
break;
|
3579
|
+
case LXW_VALIDATION_CRITERIA_GREATER_THAN_OR_EQUAL_TO:
|
3580
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "greaterThanOrEqual");
|
3581
|
+
break;
|
3582
|
+
case LXW_VALIDATION_CRITERIA_BETWEEN:
|
3583
|
+
/* Between is the default for 2 formulas and isn't added. */
|
3584
|
+
is_between = 1;
|
3585
|
+
break;
|
3586
|
+
case LXW_VALIDATION_CRITERIA_NOT_BETWEEN:
|
3587
|
+
is_between = 1;
|
3588
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "notBetween");
|
3589
|
+
break;
|
3590
|
+
}
|
3591
|
+
|
3592
|
+
if (validation->error_type == LXW_VALIDATION_ERROR_TYPE_WARNING)
|
3593
|
+
LXW_PUSH_ATTRIBUTES_STR("errorStyle", "warning");
|
3594
|
+
|
3595
|
+
if (validation->error_type == LXW_VALIDATION_ERROR_TYPE_INFORMATION)
|
3596
|
+
LXW_PUSH_ATTRIBUTES_STR("errorStyle", "information");
|
3597
|
+
|
3598
|
+
if (validation->ignore_blank)
|
3599
|
+
LXW_PUSH_ATTRIBUTES_INT("allowBlank", 1);
|
3600
|
+
|
3601
|
+
if (validation->dropdown == LXW_VALIDATION_OFF)
|
3602
|
+
LXW_PUSH_ATTRIBUTES_INT("showDropDown", 1);
|
3603
|
+
|
3604
|
+
if (validation->show_input)
|
3605
|
+
LXW_PUSH_ATTRIBUTES_INT("showInputMessage", 1);
|
3606
|
+
|
3607
|
+
if (validation->show_error)
|
3608
|
+
LXW_PUSH_ATTRIBUTES_INT("showErrorMessage", 1);
|
3609
|
+
|
3610
|
+
if (validation->error_title)
|
3611
|
+
LXW_PUSH_ATTRIBUTES_STR("errorTitle", validation->error_title);
|
3612
|
+
|
3613
|
+
if (validation->error_message)
|
3614
|
+
LXW_PUSH_ATTRIBUTES_STR("error", validation->error_message);
|
3615
|
+
|
3616
|
+
if (validation->input_title)
|
3617
|
+
LXW_PUSH_ATTRIBUTES_STR("promptTitle", validation->input_title);
|
3618
|
+
|
3619
|
+
if (validation->input_message)
|
3620
|
+
LXW_PUSH_ATTRIBUTES_STR("prompt", validation->input_message);
|
3621
|
+
|
3622
|
+
LXW_PUSH_ATTRIBUTES_STR("sqref", validation->sqref);
|
3623
|
+
|
3624
|
+
if (validation->validate == LXW_VALIDATION_TYPE_ANY)
|
3625
|
+
lxw_xml_empty_tag(self->file, "dataValidation", &attributes);
|
3626
|
+
else
|
3627
|
+
lxw_xml_start_tag(self->file, "dataValidation", &attributes);
|
3628
|
+
|
3629
|
+
/* Write the formula1 and formula2 elements. */
|
3630
|
+
switch (validation->validate) {
|
3631
|
+
case LXW_VALIDATION_TYPE_INTEGER:
|
3632
|
+
case LXW_VALIDATION_TYPE_DECIMAL:
|
3633
|
+
case LXW_VALIDATION_TYPE_LENGTH:
|
3634
|
+
case LXW_VALIDATION_TYPE_DATE:
|
3635
|
+
case LXW_VALIDATION_TYPE_TIME:
|
3636
|
+
case LXW_VALIDATION_TYPE_DATE_NUMBER:
|
3637
|
+
case LXW_VALIDATION_TYPE_TIME_NUMBER:
|
3638
|
+
_worksheet_write_formula1_num(self, validation->value_number);
|
3639
|
+
if (is_between)
|
3640
|
+
_worksheet_write_formula2_num(self,
|
3641
|
+
validation->maximum_number);
|
3642
|
+
break;
|
3643
|
+
case LXW_VALIDATION_TYPE_INTEGER_FORMULA:
|
3644
|
+
case LXW_VALIDATION_TYPE_DECIMAL_FORMULA:
|
3645
|
+
case LXW_VALIDATION_TYPE_LENGTH_FORMULA:
|
3646
|
+
case LXW_VALIDATION_TYPE_DATE_FORMULA:
|
3647
|
+
case LXW_VALIDATION_TYPE_TIME_FORMULA:
|
3648
|
+
case LXW_VALIDATION_TYPE_LIST:
|
3649
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
3650
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
3651
|
+
_worksheet_write_formula1_str(self, validation->value_formula);
|
3652
|
+
if (is_between)
|
3653
|
+
_worksheet_write_formula2_str(self,
|
3654
|
+
validation->maximum_formula);
|
3655
|
+
break;
|
3656
|
+
}
|
3657
|
+
|
3658
|
+
if (validation->validate != LXW_VALIDATION_TYPE_ANY)
|
3659
|
+
lxw_xml_end_tag(self->file, "dataValidation");
|
3660
|
+
|
3661
|
+
LXW_FREE_ATTRIBUTES();
|
3662
|
+
}
|
3663
|
+
|
3664
|
+
/*
|
3665
|
+
* Write the <dataValidations> element.
|
3666
|
+
*/
|
3667
|
+
STATIC void
|
3668
|
+
_worksheet_write_data_validations(lxw_worksheet *self)
|
3669
|
+
{
|
3670
|
+
struct xml_attribute_list attributes;
|
3671
|
+
struct xml_attribute *attribute;
|
3672
|
+
lxw_data_validation *data_validation;
|
3673
|
+
|
3674
|
+
if (self->num_validations == 0)
|
3675
|
+
return;
|
3676
|
+
|
3677
|
+
LXW_INIT_ATTRIBUTES();
|
3678
|
+
LXW_PUSH_ATTRIBUTES_INT("count", self->num_validations);
|
3679
|
+
|
3680
|
+
lxw_xml_start_tag(self->file, "dataValidations", &attributes);
|
3681
|
+
|
3682
|
+
STAILQ_FOREACH(data_validation, self->data_validations, list_pointers) {
|
3683
|
+
/* Write the dataValidation element. */
|
3684
|
+
_worksheet_write_data_validation(self, data_validation);
|
3685
|
+
}
|
3686
|
+
|
3687
|
+
lxw_xml_end_tag(self->file, "dataValidations");
|
3688
|
+
|
3689
|
+
LXW_FREE_ATTRIBUTES();
|
3690
|
+
}
|
3691
|
+
|
3315
3692
|
/*
|
3316
3693
|
* Assemble and write the XML file.
|
3317
3694
|
*/
|
@@ -3354,6 +3731,9 @@ lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
|
|
3354
3731
|
/* Write the mergeCells element. */
|
3355
3732
|
_worksheet_write_merge_cells(self);
|
3356
3733
|
|
3734
|
+
/* Write the dataValidations element. */
|
3735
|
+
_worksheet_write_data_validations(self);
|
3736
|
+
|
3357
3737
|
/* Write the hyperlink element. */
|
3358
3738
|
_worksheet_write_hyperlinks(self);
|
3359
3739
|
|
@@ -3431,7 +3811,7 @@ worksheet_write_string(lxw_worksheet *self,
|
|
3431
3811
|
if (format)
|
3432
3812
|
return worksheet_write_blank(self, row_num, col_num, format);
|
3433
3813
|
else
|
3434
|
-
return
|
3814
|
+
return LXW_NO_ERROR;
|
3435
3815
|
}
|
3436
3816
|
|
3437
3817
|
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
@@ -4010,6 +4390,14 @@ worksheet_set_column_opt(lxw_worksheet *self,
|
|
4010
4390
|
copied_options = calloc(1, sizeof(lxw_col_options));
|
4011
4391
|
RETURN_ON_MEM_ERROR(copied_options, LXW_ERROR_MEMORY_MALLOC_FAILED);
|
4012
4392
|
|
4393
|
+
/* Ensure the level is <= 7). */
|
4394
|
+
if (level > 7)
|
4395
|
+
level = 7;
|
4396
|
+
|
4397
|
+
if (level > self->outline_col_level)
|
4398
|
+
self->outline_col_level = level;
|
4399
|
+
|
4400
|
+
/* Set the column properties. */
|
4013
4401
|
copied_options->firstcol = firstcol;
|
4014
4402
|
copied_options->lastcol = lastcol;
|
4015
4403
|
copied_options->width = width;
|
@@ -4082,6 +4470,14 @@ worksheet_set_row_opt(lxw_worksheet *self,
|
|
4082
4470
|
height = self->default_row_height;
|
4083
4471
|
}
|
4084
4472
|
|
4473
|
+
/* Ensure the level is <= 7). */
|
4474
|
+
if (level > 7)
|
4475
|
+
level = 7;
|
4476
|
+
|
4477
|
+
if (level > self->outline_row_level)
|
4478
|
+
self->outline_row_level = level;
|
4479
|
+
|
4480
|
+
/* Store the row properties. */
|
4085
4481
|
row = _get_row(self, row_num);
|
4086
4482
|
|
4087
4483
|
row->height = height;
|
@@ -4467,7 +4863,7 @@ worksheet_set_header_opt(lxw_worksheet *self, const char *string,
|
|
4467
4863
|
lxw_header_footer_options *options)
|
4468
4864
|
{
|
4469
4865
|
if (options) {
|
4470
|
-
if (options->margin
|
4866
|
+
if (options->margin >= 0.0)
|
4471
4867
|
self->margin_header = options->margin;
|
4472
4868
|
}
|
4473
4869
|
|
@@ -4491,7 +4887,7 @@ worksheet_set_footer_opt(lxw_worksheet *self, const char *string,
|
|
4491
4887
|
lxw_header_footer_options *options)
|
4492
4888
|
{
|
4493
4889
|
if (options) {
|
4494
|
-
if (options->margin
|
4890
|
+
if (options->margin >= 0.0)
|
4495
4891
|
self->margin_footer = options->margin;
|
4496
4892
|
}
|
4497
4893
|
|
@@ -4819,11 +5215,23 @@ worksheet_protect(lxw_worksheet *self, const char *password,
|
|
4819
5215
|
struct lxw_protection *protect = &self->protection;
|
4820
5216
|
|
4821
5217
|
/* Copy any user parameters to the internal structure. */
|
4822
|
-
if (options)
|
4823
|
-
|
4824
|
-
|
4825
|
-
|
4826
|
-
|
5218
|
+
if (options) {
|
5219
|
+
protect->no_select_locked_cells = options->no_select_locked_cells;
|
5220
|
+
protect->no_select_unlocked_cells = options->no_select_unlocked_cells;
|
5221
|
+
protect->format_cells = options->format_cells;
|
5222
|
+
protect->format_columns = options->format_columns;
|
5223
|
+
protect->format_rows = options->format_rows;
|
5224
|
+
protect->insert_columns = options->insert_columns;
|
5225
|
+
protect->insert_rows = options->insert_rows;
|
5226
|
+
protect->insert_hyperlinks = options->insert_hyperlinks;
|
5227
|
+
protect->delete_columns = options->delete_columns;
|
5228
|
+
protect->delete_rows = options->delete_rows;
|
5229
|
+
protect->sort = options->sort;
|
5230
|
+
protect->autofilter = options->autofilter;
|
5231
|
+
protect->pivot_tables = options->pivot_tables;
|
5232
|
+
protect->scenarios = options->scenarios;
|
5233
|
+
protect->objects = options->objects;
|
5234
|
+
}
|
4827
5235
|
|
4828
5236
|
if (password) {
|
4829
5237
|
uint16_t hash = _hash_password(password);
|
@@ -4833,6 +5241,23 @@ worksheet_protect(lxw_worksheet *self, const char *password,
|
|
4833
5241
|
protect->is_configured = LXW_TRUE;
|
4834
5242
|
}
|
4835
5243
|
|
5244
|
+
/*
|
5245
|
+
* Set the worksheet properties for outlines and grouping.
|
5246
|
+
*/
|
5247
|
+
void
|
5248
|
+
worksheet_outline_settings(lxw_worksheet *self,
|
5249
|
+
uint8_t visible,
|
5250
|
+
uint8_t symbols_below,
|
5251
|
+
uint8_t symbols_right, uint8_t auto_style)
|
5252
|
+
{
|
5253
|
+
self->outline_on = visible;
|
5254
|
+
self->outline_below = symbols_below;
|
5255
|
+
self->outline_right = symbols_right;
|
5256
|
+
self->outline_style = auto_style;
|
5257
|
+
|
5258
|
+
self->outline_changed = LXW_TRUE;
|
5259
|
+
}
|
5260
|
+
|
4836
5261
|
/*
|
4837
5262
|
* Set the default row properties
|
4838
5263
|
*/
|
@@ -4899,9 +5324,10 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
4899
5324
|
}
|
4900
5325
|
|
4901
5326
|
if (user_options) {
|
4902
|
-
|
4903
|
-
options->
|
4904
|
-
options->
|
5327
|
+
options->x_offset = user_options->x_offset;
|
5328
|
+
options->y_offset = user_options->y_offset;
|
5329
|
+
options->x_scale = user_options->x_scale;
|
5330
|
+
options->y_scale = user_options->y_scale;
|
4905
5331
|
}
|
4906
5332
|
|
4907
5333
|
/* Copy other options or set defaults. */
|
@@ -4919,10 +5345,12 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
4919
5345
|
|
4920
5346
|
if (_get_image_properties(options) == LXW_NO_ERROR) {
|
4921
5347
|
STAILQ_INSERT_TAIL(self->image_data, options, list_pointers);
|
5348
|
+
fclose(image_stream);
|
4922
5349
|
return LXW_NO_ERROR;
|
4923
5350
|
}
|
4924
5351
|
else {
|
4925
5352
|
free(options);
|
5353
|
+
fclose(image_stream);
|
4926
5354
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
4927
5355
|
}
|
4928
5356
|
}
|
@@ -4984,8 +5412,12 @@ worksheet_insert_chart_opt(lxw_worksheet *self,
|
|
4984
5412
|
options = calloc(1, sizeof(lxw_image_options));
|
4985
5413
|
RETURN_ON_MEM_ERROR(options, LXW_ERROR_MEMORY_MALLOC_FAILED);
|
4986
5414
|
|
4987
|
-
if (user_options)
|
4988
|
-
|
5415
|
+
if (user_options) {
|
5416
|
+
options->x_offset = user_options->x_offset;
|
5417
|
+
options->y_offset = user_options->y_offset;
|
5418
|
+
options->x_scale = user_options->x_scale;
|
5419
|
+
options->y_scale = user_options->y_scale;
|
5420
|
+
}
|
4989
5421
|
|
4990
5422
|
/* Copy other options or set defaults. */
|
4991
5423
|
options->row = row_num;
|
@@ -5020,3 +5452,288 @@ worksheet_insert_chart(lxw_worksheet *self,
|
|
5020
5452
|
{
|
5021
5453
|
return worksheet_insert_chart_opt(self, row_num, col_num, chart, NULL);
|
5022
5454
|
}
|
5455
|
+
|
5456
|
+
/*
|
5457
|
+
* Add a data validation to a worksheet, for a range. Ironically this requires
|
5458
|
+
* a lot of validation of the user input.
|
5459
|
+
*/
|
5460
|
+
lxw_error
|
5461
|
+
worksheet_data_validation_range(lxw_worksheet *self, lxw_row_t first_row,
|
5462
|
+
lxw_col_t first_col,
|
5463
|
+
lxw_row_t last_row,
|
5464
|
+
lxw_col_t last_col,
|
5465
|
+
lxw_data_validation *validation)
|
5466
|
+
{
|
5467
|
+
lxw_data_validation *copy;
|
5468
|
+
uint8_t is_between = LXW_FALSE;
|
5469
|
+
uint8_t is_formula = LXW_FALSE;
|
5470
|
+
uint8_t has_criteria = LXW_TRUE;
|
5471
|
+
lxw_error err;
|
5472
|
+
lxw_row_t tmp_row;
|
5473
|
+
lxw_col_t tmp_col;
|
5474
|
+
size_t length;
|
5475
|
+
|
5476
|
+
/* No action is required for validation type 'any' unless there are
|
5477
|
+
* input messages to display.*/
|
5478
|
+
if (validation->validate == LXW_VALIDATION_TYPE_ANY
|
5479
|
+
&& !(validation->input_title || validation->input_message)) {
|
5480
|
+
|
5481
|
+
return LXW_NO_ERROR;
|
5482
|
+
}
|
5483
|
+
|
5484
|
+
/* Check for formula types. */
|
5485
|
+
switch (validation->validate) {
|
5486
|
+
case LXW_VALIDATION_TYPE_INTEGER_FORMULA:
|
5487
|
+
case LXW_VALIDATION_TYPE_DECIMAL_FORMULA:
|
5488
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
5489
|
+
case LXW_VALIDATION_TYPE_LENGTH_FORMULA:
|
5490
|
+
case LXW_VALIDATION_TYPE_DATE_FORMULA:
|
5491
|
+
case LXW_VALIDATION_TYPE_TIME_FORMULA:
|
5492
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
5493
|
+
is_formula = LXW_TRUE;
|
5494
|
+
break;
|
5495
|
+
}
|
5496
|
+
|
5497
|
+
/* Check for types without a criteria. */
|
5498
|
+
switch (validation->validate) {
|
5499
|
+
case LXW_VALIDATION_TYPE_LIST:
|
5500
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
5501
|
+
case LXW_VALIDATION_TYPE_ANY:
|
5502
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
5503
|
+
has_criteria = LXW_FALSE;
|
5504
|
+
break;
|
5505
|
+
}
|
5506
|
+
|
5507
|
+
/* Check that a validation parameter has been specified
|
5508
|
+
* except for 'list', 'any' and 'custom'. */
|
5509
|
+
if (has_criteria && validation->criteria == LXW_VALIDATION_CRITERIA_NONE) {
|
5510
|
+
|
5511
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5512
|
+
"criteria parameter must be specified.");
|
5513
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5514
|
+
}
|
5515
|
+
|
5516
|
+
/* Check for "between" criteria so we can do additional checks. */
|
5517
|
+
if (has_criteria
|
5518
|
+
&& (validation->criteria == LXW_VALIDATION_CRITERIA_BETWEEN
|
5519
|
+
|| validation->criteria == LXW_VALIDATION_CRITERIA_NOT_BETWEEN)) {
|
5520
|
+
|
5521
|
+
is_between = LXW_TRUE;
|
5522
|
+
}
|
5523
|
+
|
5524
|
+
/* Check that formula values are non NULL. */
|
5525
|
+
if (is_formula) {
|
5526
|
+
if (is_between) {
|
5527
|
+
if (!validation->minimum_formula) {
|
5528
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5529
|
+
"minimum_formula parameter cannot be NULL.");
|
5530
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5531
|
+
}
|
5532
|
+
if (!validation->maximum_formula) {
|
5533
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5534
|
+
"maximum_formula parameter cannot be NULL.");
|
5535
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5536
|
+
}
|
5537
|
+
}
|
5538
|
+
else {
|
5539
|
+
if (!validation->value_formula) {
|
5540
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5541
|
+
"formula parameter cannot be NULL.");
|
5542
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5543
|
+
}
|
5544
|
+
}
|
5545
|
+
}
|
5546
|
+
|
5547
|
+
/* Check Excel limitations on input strings. */
|
5548
|
+
if (validation->input_title) {
|
5549
|
+
length = lxw_utf8_strlen(validation->input_title);
|
5550
|
+
if (length > LXW_VALIDATION_MAX_TITLE_LENGTH) {
|
5551
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5552
|
+
"input_title length > Excel limit of %d.",
|
5553
|
+
LXW_VALIDATION_MAX_TITLE_LENGTH);
|
5554
|
+
return LXW_ERROR_32_STRING_LENGTH_EXCEEDED;
|
5555
|
+
}
|
5556
|
+
}
|
5557
|
+
|
5558
|
+
if (validation->error_title) {
|
5559
|
+
length = lxw_utf8_strlen(validation->error_title);
|
5560
|
+
if (length > LXW_VALIDATION_MAX_TITLE_LENGTH) {
|
5561
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5562
|
+
"error_title length > Excel limit of %d.",
|
5563
|
+
LXW_VALIDATION_MAX_TITLE_LENGTH);
|
5564
|
+
return LXW_ERROR_32_STRING_LENGTH_EXCEEDED;
|
5565
|
+
}
|
5566
|
+
}
|
5567
|
+
|
5568
|
+
if (validation->input_message) {
|
5569
|
+
length = lxw_utf8_strlen(validation->input_message);
|
5570
|
+
if (length > LXW_VALIDATION_MAX_STRING_LENGTH) {
|
5571
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5572
|
+
"input_message length > Excel limit of %d.",
|
5573
|
+
LXW_VALIDATION_MAX_STRING_LENGTH);
|
5574
|
+
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
|
5575
|
+
}
|
5576
|
+
}
|
5577
|
+
|
5578
|
+
if (validation->error_message) {
|
5579
|
+
length = lxw_utf8_strlen(validation->error_message);
|
5580
|
+
if (length > LXW_VALIDATION_MAX_STRING_LENGTH) {
|
5581
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5582
|
+
"error_message length > Excel limit of %d.",
|
5583
|
+
LXW_VALIDATION_MAX_STRING_LENGTH);
|
5584
|
+
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
|
5585
|
+
}
|
5586
|
+
}
|
5587
|
+
|
5588
|
+
if (validation->validate == LXW_VALIDATION_TYPE_LIST) {
|
5589
|
+
length = _validation_list_length(validation->value_list);
|
5590
|
+
|
5591
|
+
if (length == 0) {
|
5592
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
5593
|
+
"list parameters cannot be zero.");
|
5594
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
5595
|
+
}
|
5596
|
+
|
5597
|
+
if (length > LXW_VALIDATION_MAX_STRING_LENGTH) {
|
5598
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
5599
|
+
"list length with commas > Excel limit of %d.",
|
5600
|
+
LXW_VALIDATION_MAX_STRING_LENGTH);
|
5601
|
+
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
|
5602
|
+
}
|
5603
|
+
}
|
5604
|
+
|
5605
|
+
/* Swap last row/col with first row/col as necessary */
|
5606
|
+
if (first_row > last_row) {
|
5607
|
+
tmp_row = last_row;
|
5608
|
+
last_row = first_row;
|
5609
|
+
first_row = tmp_row;
|
5610
|
+
}
|
5611
|
+
if (first_col > last_col) {
|
5612
|
+
tmp_col = last_col;
|
5613
|
+
last_col = first_col;
|
5614
|
+
first_col = tmp_col;
|
5615
|
+
}
|
5616
|
+
|
5617
|
+
/* Check that dimensions are valid but don't store them. */
|
5618
|
+
err = _check_dimensions(self, last_row, last_col, LXW_TRUE, LXW_TRUE);
|
5619
|
+
if (err)
|
5620
|
+
return err;
|
5621
|
+
|
5622
|
+
/* Create a copy of the parameters from the user data validation. */
|
5623
|
+
copy = calloc(1, sizeof(lxw_data_validation));
|
5624
|
+
GOTO_LABEL_ON_MEM_ERROR(copy, mem_error);
|
5625
|
+
|
5626
|
+
/* Create the data validation range. */
|
5627
|
+
if (first_row == last_row && first_col == last_col)
|
5628
|
+
lxw_rowcol_to_cell(copy->sqref, first_row, last_col);
|
5629
|
+
else
|
5630
|
+
lxw_rowcol_to_range(copy->sqref, first_row, first_col, last_row,
|
5631
|
+
last_col);
|
5632
|
+
|
5633
|
+
/* Copy the parameters from the user data validation. */
|
5634
|
+
copy->validate = validation->validate;
|
5635
|
+
copy->value_number = validation->value_number;
|
5636
|
+
copy->error_type = validation->error_type;
|
5637
|
+
copy->dropdown = validation->dropdown;
|
5638
|
+
copy->is_between = is_between;
|
5639
|
+
|
5640
|
+
if (has_criteria)
|
5641
|
+
copy->criteria = validation->criteria;
|
5642
|
+
|
5643
|
+
if (is_between) {
|
5644
|
+
copy->value_number = validation->minimum_number;
|
5645
|
+
copy->maximum_number = validation->maximum_number;
|
5646
|
+
}
|
5647
|
+
|
5648
|
+
/* Copy the input/error titles and messages. */
|
5649
|
+
if (validation->input_title) {
|
5650
|
+
copy->input_title = lxw_strdup_formula(validation->input_title);
|
5651
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->input_title, mem_error);
|
5652
|
+
}
|
5653
|
+
|
5654
|
+
if (validation->input_message) {
|
5655
|
+
copy->input_message = lxw_strdup_formula(validation->input_message);
|
5656
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->input_message, mem_error);
|
5657
|
+
}
|
5658
|
+
|
5659
|
+
if (validation->error_title) {
|
5660
|
+
copy->error_title = lxw_strdup_formula(validation->error_title);
|
5661
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->error_title, mem_error);
|
5662
|
+
}
|
5663
|
+
|
5664
|
+
if (validation->error_message) {
|
5665
|
+
copy->error_message = lxw_strdup_formula(validation->error_message);
|
5666
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->error_message, mem_error);
|
5667
|
+
}
|
5668
|
+
|
5669
|
+
/* Copy the formula strings. */
|
5670
|
+
if (is_formula) {
|
5671
|
+
if (is_between) {
|
5672
|
+
copy->value_formula =
|
5673
|
+
lxw_strdup_formula(validation->minimum_formula);
|
5674
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
5675
|
+
copy->maximum_formula =
|
5676
|
+
lxw_strdup_formula(validation->maximum_formula);
|
5677
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->maximum_formula, mem_error);
|
5678
|
+
}
|
5679
|
+
else {
|
5680
|
+
copy->value_formula =
|
5681
|
+
lxw_strdup_formula(validation->value_formula);
|
5682
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
5683
|
+
}
|
5684
|
+
}
|
5685
|
+
|
5686
|
+
/* Copy the validation list as a csv string. */
|
5687
|
+
if (validation->validate == LXW_VALIDATION_TYPE_LIST) {
|
5688
|
+
copy->value_formula = _validation_list_to_csv(validation->value_list);
|
5689
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
5690
|
+
}
|
5691
|
+
|
5692
|
+
if (validation->validate == LXW_VALIDATION_TYPE_LIST_FORMULA) {
|
5693
|
+
copy->value_formula = lxw_strdup_formula(validation->value_formula);
|
5694
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
5695
|
+
}
|
5696
|
+
|
5697
|
+
if (validation->validate == LXW_VALIDATION_TYPE_DATE
|
5698
|
+
|| validation->validate == LXW_VALIDATION_TYPE_TIME) {
|
5699
|
+
if (is_between) {
|
5700
|
+
copy->value_number =
|
5701
|
+
lxw_datetime_to_excel_date(&validation->minimum_datetime,
|
5702
|
+
LXW_EPOCH_1900);
|
5703
|
+
copy->maximum_number =
|
5704
|
+
lxw_datetime_to_excel_date(&validation->maximum_datetime,
|
5705
|
+
LXW_EPOCH_1900);
|
5706
|
+
}
|
5707
|
+
else {
|
5708
|
+
copy->value_number =
|
5709
|
+
lxw_datetime_to_excel_date(&validation->value_datetime,
|
5710
|
+
LXW_EPOCH_1900);
|
5711
|
+
}
|
5712
|
+
}
|
5713
|
+
|
5714
|
+
/* These options are on by default so we can't take plain booleans. */
|
5715
|
+
copy->ignore_blank = validation->ignore_blank ^ 1;
|
5716
|
+
copy->show_input = validation->show_input ^ 1;
|
5717
|
+
copy->show_error = validation->show_error ^ 1;
|
5718
|
+
|
5719
|
+
STAILQ_INSERT_TAIL(self->data_validations, copy, list_pointers);
|
5720
|
+
|
5721
|
+
self->num_validations++;
|
5722
|
+
|
5723
|
+
return LXW_NO_ERROR;
|
5724
|
+
|
5725
|
+
mem_error:
|
5726
|
+
_free_data_validation(copy);
|
5727
|
+
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
5728
|
+
}
|
5729
|
+
|
5730
|
+
/*
|
5731
|
+
* Add a data validation to a worksheet, for a cell.
|
5732
|
+
*/
|
5733
|
+
lxw_error
|
5734
|
+
worksheet_data_validation_cell(lxw_worksheet *self, lxw_row_t row,
|
5735
|
+
lxw_col_t col, lxw_data_validation *validation)
|
5736
|
+
{
|
5737
|
+
return worksheet_data_validation_range(self, row, col,
|
5738
|
+
row, col, validation);
|
5739
|
+
}
|