fast_excel 0.2.3 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|