fast_excel 0.2.2 → 0.4.0
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 +5 -5
- data/.dockerignore +2 -0
- data/.gitignore +7 -0
- data/.travis.yml +32 -9
- data/CHANGELOG.md +36 -1
- data/Dockerfile.test +17 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +33 -24
- data/LICENSE +21 -0
- data/Makefile +13 -0
- data/README.md +177 -40
- data/Rakefile +11 -1
- data/benchmarks/1k_rows.rb +17 -4
- data/benchmarks/20k_rows.rb +4 -0
- data/benchmarks/auto_width.rb +37 -0
- data/benchmarks/init.rb +14 -2
- data/benchmarks/memory.rb +8 -0
- data/benchmarks/profiler.rb +27 -0
- data/benchmarks/write_value.rb +62 -0
- data/examples/example.rb +3 -3
- data/examples/example_auto_width.rb +26 -0
- data/examples/example_filters.rb +36 -0
- data/examples/example_formula.rb +1 -3
- data/examples/example_hyperlink.rb +20 -0
- data/ext/fast_excel/extconf.rb +3 -0
- data/ext/fast_excel/text_width_ext.c +460 -0
- data/fast_excel.gemspec +3 -4
- data/letters.html +114 -0
- data/lib/fast_excel.rb +131 -25
- data/lib/fast_excel/binding.rb +33 -21
- data/lib/fast_excel/binding/chart.rb +20 -1
- data/lib/fast_excel/binding/format.rb +11 -4
- data/lib/fast_excel/binding/workbook.rb +10 -2
- data/lib/fast_excel/binding/worksheet.rb +44 -27
- data/libxlsxwriter/.gitignore +1 -0
- data/libxlsxwriter/.indent.pro +8 -0
- data/libxlsxwriter/.travis.yml +12 -0
- data/libxlsxwriter/CMakeLists.txt +338 -0
- data/libxlsxwriter/CONTRIBUTING.md +1 -1
- data/libxlsxwriter/Changes.txt +162 -0
- data/libxlsxwriter/LICENSE.txt +65 -4
- data/libxlsxwriter/Makefile +33 -11
- data/libxlsxwriter/Readme.md +3 -1
- data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +2 -1
- data/libxlsxwriter/cocoapods/libxlsxwriter.modulemap +2 -2
- data/libxlsxwriter/include/xlsxwriter.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/app.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/chart.h +164 -13
- data/libxlsxwriter/include/xlsxwriter/chartsheet.h +544 -0
- data/libxlsxwriter/include/xlsxwriter/common.h +35 -6
- data/libxlsxwriter/include/xlsxwriter/content_types.h +5 -2
- data/libxlsxwriter/include/xlsxwriter/core.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/custom.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/drawing.h +3 -2
- data/libxlsxwriter/include/xlsxwriter/format.h +8 -8
- data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/packager.h +18 -8
- data/libxlsxwriter/include/xlsxwriter/relationships.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/shared_strings.h +5 -3
- data/libxlsxwriter/include/xlsxwriter/styles.h +10 -5
- data/libxlsxwriter/include/xlsxwriter/theme.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/utility.h +35 -5
- data/libxlsxwriter/include/xlsxwriter/workbook.h +234 -57
- data/libxlsxwriter/include/xlsxwriter/worksheet.h +780 -91
- data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +4 -2
- data/libxlsxwriter/libxlsxwriter.podspec +4 -2
- data/libxlsxwriter/src/Makefile +31 -6
- data/libxlsxwriter/src/app.c +2 -2
- data/libxlsxwriter/src/chart.c +116 -23
- data/libxlsxwriter/src/chartsheet.c +508 -0
- data/libxlsxwriter/src/content_types.c +12 -4
- data/libxlsxwriter/src/core.c +11 -11
- data/libxlsxwriter/src/custom.c +3 -3
- data/libxlsxwriter/src/drawing.c +114 -17
- data/libxlsxwriter/src/format.c +5 -5
- data/libxlsxwriter/src/hash_table.c +1 -1
- data/libxlsxwriter/src/packager.c +378 -61
- data/libxlsxwriter/src/relationships.c +2 -2
- data/libxlsxwriter/src/shared_strings.c +18 -4
- data/libxlsxwriter/src/styles.c +59 -12
- data/libxlsxwriter/src/theme.c +2 -2
- data/libxlsxwriter/src/utility.c +93 -6
- data/libxlsxwriter/src/workbook.c +379 -61
- data/libxlsxwriter/src/worksheet.c +1240 -174
- data/libxlsxwriter/src/xmlwriter.c +18 -9
- data/libxlsxwriter/third_party/minizip/Makefile +6 -1
- data/libxlsxwriter/third_party/minizip/ioapi.c +10 -0
- data/libxlsxwriter/third_party/minizip/zip.c +2 -0
- data/libxlsxwriter/third_party/tmpfileplus/tmpfileplus.c +2 -2
- data/libxlsxwriter/version.txt +1 -1
- data/test/auto_width_test.rb +19 -0
- data/test/date_test.rb +34 -0
- data/test/format_test.rb +8 -0
- data/test/reopen_test.rb +22 -0
- data/test/test_helper.rb +8 -5
- data/test/text_width_test.rb +80 -0
- data/test/tmpfile_test.rb +1 -0
- data/test/validations_test.rb +47 -0
- data/test/worksheet_test.rb +44 -1
- metadata +33 -9
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
|
5
5
|
*
|
|
6
|
-
* Copyright 2014-
|
|
6
|
+
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -15,11 +15,11 @@
|
|
|
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
|
|
21
|
-
#define
|
|
22
|
-
#define
|
|
18
|
+
#define LXW_STR_MAX 32767
|
|
19
|
+
#define LXW_BUFFER_SIZE 4096
|
|
20
|
+
#define LXW_PRINT_ACROSS 1
|
|
21
|
+
#define LXW_VALIDATION_MAX_TITLE_LENGTH 32
|
|
22
|
+
#define LXW_VALIDATION_MAX_STRING_LENGTH 255
|
|
23
23
|
|
|
24
24
|
/*
|
|
25
25
|
* Forward declarations.
|
|
@@ -123,6 +123,11 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
|
|
123
123
|
GOTO_LABEL_ON_MEM_ERROR(worksheet->selections, mem_error);
|
|
124
124
|
STAILQ_INIT(worksheet->selections);
|
|
125
125
|
|
|
126
|
+
worksheet->data_validations =
|
|
127
|
+
calloc(1, sizeof(struct lxw_data_validations));
|
|
128
|
+
GOTO_LABEL_ON_MEM_ERROR(worksheet->data_validations, mem_error);
|
|
129
|
+
STAILQ_INIT(worksheet->data_validations);
|
|
130
|
+
|
|
126
131
|
worksheet->external_hyperlinks = calloc(1, sizeof(struct lxw_rel_tuples));
|
|
127
132
|
GOTO_LABEL_ON_MEM_ERROR(worksheet->external_hyperlinks, mem_error);
|
|
128
133
|
STAILQ_INIT(worksheet->external_hyperlinks);
|
|
@@ -187,6 +192,9 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
|
|
187
192
|
worksheet->zoom_scale_normal = LXW_TRUE;
|
|
188
193
|
worksheet->show_zeros = LXW_TRUE;
|
|
189
194
|
worksheet->outline_on = LXW_TRUE;
|
|
195
|
+
worksheet->outline_style = LXW_TRUE;
|
|
196
|
+
worksheet->outline_below = LXW_TRUE;
|
|
197
|
+
worksheet->outline_right = LXW_FALSE;
|
|
190
198
|
worksheet->tab_color = LXW_COLOR_UNSET;
|
|
191
199
|
|
|
192
200
|
if (init_data) {
|
|
@@ -261,13 +269,34 @@ _free_image_options(lxw_image_options *image)
|
|
|
261
269
|
return;
|
|
262
270
|
|
|
263
271
|
free(image->filename);
|
|
264
|
-
free(image->
|
|
272
|
+
free(image->description);
|
|
265
273
|
free(image->extension);
|
|
266
274
|
free(image->url);
|
|
267
275
|
free(image->tip);
|
|
276
|
+
free(image->image_buffer);
|
|
268
277
|
free(image);
|
|
269
278
|
}
|
|
270
279
|
|
|
280
|
+
/*
|
|
281
|
+
* Free a worksheet data_validation.
|
|
282
|
+
*/
|
|
283
|
+
STATIC void
|
|
284
|
+
_free_data_validation(lxw_data_validation *data_validation)
|
|
285
|
+
{
|
|
286
|
+
if (!data_validation)
|
|
287
|
+
return;
|
|
288
|
+
|
|
289
|
+
free(data_validation->value_formula);
|
|
290
|
+
free(data_validation->maximum_formula);
|
|
291
|
+
free(data_validation->input_title);
|
|
292
|
+
free(data_validation->input_message);
|
|
293
|
+
free(data_validation->error_title);
|
|
294
|
+
free(data_validation->error_message);
|
|
295
|
+
free(data_validation->minimum_formula);
|
|
296
|
+
|
|
297
|
+
free(data_validation);
|
|
298
|
+
}
|
|
299
|
+
|
|
271
300
|
/*
|
|
272
301
|
* Free a worksheet object.
|
|
273
302
|
*/
|
|
@@ -280,6 +309,7 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
|
280
309
|
lxw_merged_range *merged_range;
|
|
281
310
|
lxw_image_options *image_options;
|
|
282
311
|
lxw_selection *selection;
|
|
312
|
+
lxw_data_validation *data_validation;
|
|
283
313
|
lxw_rel_tuple *relationship;
|
|
284
314
|
|
|
285
315
|
if (!worksheet)
|
|
@@ -309,7 +339,6 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
|
309
339
|
}
|
|
310
340
|
|
|
311
341
|
if (worksheet->hyperlinks) {
|
|
312
|
-
|
|
313
342
|
for (row = RB_MIN(lxw_table_rows, worksheet->hyperlinks); row;
|
|
314
343
|
row = next_row) {
|
|
315
344
|
|
|
@@ -361,6 +390,16 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
|
361
390
|
free(worksheet->selections);
|
|
362
391
|
}
|
|
363
392
|
|
|
393
|
+
if (worksheet->data_validations) {
|
|
394
|
+
while (!STAILQ_EMPTY(worksheet->data_validations)) {
|
|
395
|
+
data_validation = STAILQ_FIRST(worksheet->data_validations);
|
|
396
|
+
STAILQ_REMOVE_HEAD(worksheet->data_validations, list_pointers);
|
|
397
|
+
_free_data_validation(data_validation);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
free(worksheet->data_validations);
|
|
401
|
+
}
|
|
402
|
+
|
|
364
403
|
/* TODO. Add function for freeing the relationship lists. */
|
|
365
404
|
while (!STAILQ_EMPTY(worksheet->external_hyperlinks)) {
|
|
366
405
|
relationship = STAILQ_FIRST(worksheet->external_hyperlinks);
|
|
@@ -409,6 +448,7 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
|
409
448
|
free(worksheet->vbreaks);
|
|
410
449
|
free(worksheet->name);
|
|
411
450
|
free(worksheet->quoted_name);
|
|
451
|
+
free(worksheet->vba_codename);
|
|
412
452
|
|
|
413
453
|
free(worksheet);
|
|
414
454
|
worksheet = NULL;
|
|
@@ -498,6 +538,26 @@ _new_inline_string_cell(lxw_row_t row_num,
|
|
|
498
538
|
return cell;
|
|
499
539
|
}
|
|
500
540
|
|
|
541
|
+
/*
|
|
542
|
+
* Create a new worksheet inline_string cell object for rich strings.
|
|
543
|
+
*/
|
|
544
|
+
STATIC lxw_cell *
|
|
545
|
+
_new_inline_rich_string_cell(lxw_row_t row_num,
|
|
546
|
+
lxw_col_t col_num, char *string,
|
|
547
|
+
lxw_format *format)
|
|
548
|
+
{
|
|
549
|
+
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
|
|
550
|
+
RETURN_ON_MEM_ERROR(cell, cell);
|
|
551
|
+
|
|
552
|
+
cell->row_num = row_num;
|
|
553
|
+
cell->col_num = col_num;
|
|
554
|
+
cell->type = INLINE_RICH_STRING_CELL;
|
|
555
|
+
cell->format = format;
|
|
556
|
+
cell->u.string = string;
|
|
557
|
+
|
|
558
|
+
return cell;
|
|
559
|
+
}
|
|
560
|
+
|
|
501
561
|
/*
|
|
502
562
|
* Create a new worksheet formula cell object.
|
|
503
563
|
*/
|
|
@@ -801,38 +861,6 @@ _cell_cmp(lxw_cell *cell1, lxw_cell *cell2)
|
|
|
801
861
|
return 0;
|
|
802
862
|
}
|
|
803
863
|
|
|
804
|
-
/*
|
|
805
|
-
* Hash a worksheet password. Based on the algorithm provided by Daniel Rentz
|
|
806
|
-
* of OpenOffice.
|
|
807
|
-
*/
|
|
808
|
-
STATIC uint16_t
|
|
809
|
-
_hash_password(const char *password)
|
|
810
|
-
{
|
|
811
|
-
size_t count;
|
|
812
|
-
uint8_t i;
|
|
813
|
-
uint16_t hash = 0x0000;
|
|
814
|
-
|
|
815
|
-
count = strlen(password);
|
|
816
|
-
|
|
817
|
-
for (i = 0; i < count; i++) {
|
|
818
|
-
uint32_t low_15;
|
|
819
|
-
uint32_t high_15;
|
|
820
|
-
uint32_t letter = password[i] << (i + 1);
|
|
821
|
-
|
|
822
|
-
low_15 = letter & 0x7fff;
|
|
823
|
-
high_15 = letter & (0x7fff << 15);
|
|
824
|
-
high_15 = high_15 >> 15;
|
|
825
|
-
letter = low_15 | high_15;
|
|
826
|
-
|
|
827
|
-
hash ^= letter;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
hash ^= count;
|
|
831
|
-
hash ^= 0xCE4B;
|
|
832
|
-
|
|
833
|
-
return hash;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
864
|
/*
|
|
837
865
|
* Simple replacement for libgen.h basename() for compatibility with MSVC. It
|
|
838
866
|
* handles forward and back slashes. It doesn't copy exactly the return
|
|
@@ -860,6 +888,61 @@ lxw_basename(const char *path)
|
|
|
860
888
|
return back_slash + 1;
|
|
861
889
|
}
|
|
862
890
|
|
|
891
|
+
/* Function to count the total concatenated length of the strings in a
|
|
892
|
+
* validation list array, including commas. */
|
|
893
|
+
size_t
|
|
894
|
+
_validation_list_length(char **list)
|
|
895
|
+
{
|
|
896
|
+
uint8_t i = 0;
|
|
897
|
+
size_t length = 0;
|
|
898
|
+
|
|
899
|
+
if (!list || !list[0])
|
|
900
|
+
return 0;
|
|
901
|
+
|
|
902
|
+
while (list[i] && length <= LXW_VALIDATION_MAX_STRING_LENGTH) {
|
|
903
|
+
/* Include commas in the length. */
|
|
904
|
+
length += 1 + lxw_utf8_strlen(list[i]);
|
|
905
|
+
i++;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
/* Adjust the count for extraneous comma at end. */
|
|
909
|
+
length--;
|
|
910
|
+
|
|
911
|
+
return length;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/* Function to convert an array of strings into a CSV string for data
|
|
915
|
+
* validation lists. */
|
|
916
|
+
char *
|
|
917
|
+
_validation_list_to_csv(char **list)
|
|
918
|
+
{
|
|
919
|
+
uint8_t i = 0;
|
|
920
|
+
char *str;
|
|
921
|
+
|
|
922
|
+
/* Create a buffer for the concatenated, and quoted, string. */
|
|
923
|
+
/* Add +3 for quotes and EOL. */
|
|
924
|
+
str = calloc(1, LXW_VALIDATION_MAX_STRING_LENGTH + 3);
|
|
925
|
+
if (!str)
|
|
926
|
+
return NULL;
|
|
927
|
+
|
|
928
|
+
/* Add the start quote and first element. */
|
|
929
|
+
strcat(str, "\"");
|
|
930
|
+
strcat(str, list[0]);
|
|
931
|
+
|
|
932
|
+
/* Add the other elements preceded by a comma. */
|
|
933
|
+
i = 1;
|
|
934
|
+
while (list[i]) {
|
|
935
|
+
strcat(str, ",");
|
|
936
|
+
strcat(str, list[i]);
|
|
937
|
+
i++;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/* Add the end quote. */
|
|
941
|
+
strcat(str, "\"");
|
|
942
|
+
|
|
943
|
+
return str;
|
|
944
|
+
}
|
|
945
|
+
|
|
863
946
|
/*****************************************************************************
|
|
864
947
|
*
|
|
865
948
|
* XML functions.
|
|
@@ -1372,6 +1455,12 @@ _worksheet_write_sheet_format_pr(lxw_worksheet *self)
|
|
|
1372
1455
|
if (self->default_row_zeroed)
|
|
1373
1456
|
LXW_PUSH_ATTRIBUTES_STR("zeroHeight", "1");
|
|
1374
1457
|
|
|
1458
|
+
if (self->outline_row_level)
|
|
1459
|
+
LXW_PUSH_ATTRIBUTES_INT("outlineLevelRow", self->outline_row_level);
|
|
1460
|
+
|
|
1461
|
+
if (self->outline_col_level)
|
|
1462
|
+
LXW_PUSH_ATTRIBUTES_INT("outlineLevelCol", self->outline_col_level);
|
|
1463
|
+
|
|
1375
1464
|
lxw_xml_empty_tag(self->file, "sheetFormatPr", &attributes);
|
|
1376
1465
|
|
|
1377
1466
|
LXW_FREE_ATTRIBUTES();
|
|
@@ -1608,6 +1697,9 @@ _write_row(lxw_worksheet *self, lxw_row *row, char *spans)
|
|
|
1608
1697
|
if (height != LXW_DEF_ROW_HEIGHT)
|
|
1609
1698
|
LXW_PUSH_ATTRIBUTES_STR("customHeight", "1");
|
|
1610
1699
|
|
|
1700
|
+
if (row->level)
|
|
1701
|
+
LXW_PUSH_ATTRIBUTES_INT("outlineLevel", row->level);
|
|
1702
|
+
|
|
1611
1703
|
if (row->collapsed)
|
|
1612
1704
|
LXW_PUSH_ATTRIBUTES_STR("collapsed", "1");
|
|
1613
1705
|
|
|
@@ -1649,6 +1741,9 @@ _worksheet_size_col(lxw_worksheet *self, lxw_col_t col_num)
|
|
|
1649
1741
|
}
|
|
1650
1742
|
|
|
1651
1743
|
if (col_opt) {
|
|
1744
|
+
if (col_opt->hidden)
|
|
1745
|
+
return 0;
|
|
1746
|
+
|
|
1652
1747
|
width = col_opt->width;
|
|
1653
1748
|
|
|
1654
1749
|
/* Convert to pixels. */
|
|
@@ -1684,6 +1779,9 @@ _worksheet_size_row(lxw_worksheet *self, lxw_row_t row_num)
|
|
|
1684
1779
|
row = lxw_worksheet_find_row(self, row_num);
|
|
1685
1780
|
|
|
1686
1781
|
if (row) {
|
|
1782
|
+
if (row->hidden)
|
|
1783
|
+
return 0;
|
|
1784
|
+
|
|
1687
1785
|
height = row->height;
|
|
1688
1786
|
|
|
1689
1787
|
if (height == 0)
|
|
@@ -1810,23 +1908,30 @@ _worksheet_position_object_pixels(lxw_worksheet *self,
|
|
|
1810
1908
|
y_abs += y1;
|
|
1811
1909
|
|
|
1812
1910
|
/* Adjust start col for offsets that are greater than the col width. */
|
|
1813
|
-
|
|
1814
|
-
x1
|
|
1815
|
-
|
|
1911
|
+
if (_worksheet_size_col(self, col_start) > 0) {
|
|
1912
|
+
while (x1 >= _worksheet_size_col(self, col_start)) {
|
|
1913
|
+
x1 -= _worksheet_size_col(self, col_start);
|
|
1914
|
+
col_start++;
|
|
1915
|
+
}
|
|
1816
1916
|
}
|
|
1817
1917
|
|
|
1818
1918
|
/* Adjust start row for offsets that are greater than the row height. */
|
|
1819
|
-
|
|
1820
|
-
y1
|
|
1821
|
-
|
|
1919
|
+
if (_worksheet_size_row(self, row_start) > 0) {
|
|
1920
|
+
while (y1 >= _worksheet_size_row(self, row_start)) {
|
|
1921
|
+
y1 -= _worksheet_size_row(self, row_start);
|
|
1922
|
+
row_start++;
|
|
1923
|
+
}
|
|
1822
1924
|
}
|
|
1823
1925
|
|
|
1824
1926
|
/* Initialize end cell to the same as the start cell. */
|
|
1825
1927
|
col_end = col_start;
|
|
1826
1928
|
row_end = row_start;
|
|
1827
1929
|
|
|
1828
|
-
|
|
1829
|
-
|
|
1930
|
+
/* Only offset the image in the cell if the row/col isn't hidden. */
|
|
1931
|
+
if (_worksheet_size_col(self, col_start) > 0)
|
|
1932
|
+
width = width + x1;
|
|
1933
|
+
if (_worksheet_size_row(self, row_start) > 0)
|
|
1934
|
+
height = height + y1;
|
|
1830
1935
|
|
|
1831
1936
|
/* Subtract the underlying cell widths to find the end cell. */
|
|
1832
1937
|
while (width >= _worksheet_size_col(self, col_end)) {
|
|
@@ -1888,7 +1993,7 @@ _worksheet_position_object_emus(lxw_worksheet *self,
|
|
|
1888
1993
|
*/
|
|
1889
1994
|
void
|
|
1890
1995
|
lxw_worksheet_prepare_image(lxw_worksheet *self,
|
|
1891
|
-
|
|
1996
|
+
uint32_t image_ref_id, uint32_t drawing_id,
|
|
1892
1997
|
lxw_image_options *image_data)
|
|
1893
1998
|
{
|
|
1894
1999
|
lxw_drawing_object *drawing_object;
|
|
@@ -1923,7 +2028,7 @@ lxw_worksheet_prepare_image(lxw_worksheet *self,
|
|
|
1923
2028
|
|
|
1924
2029
|
drawing_object->anchor_type = LXW_ANCHOR_TYPE_IMAGE;
|
|
1925
2030
|
drawing_object->edit_as = LXW_ANCHOR_EDIT_AS_ONE_CELL;
|
|
1926
|
-
drawing_object->description = lxw_strdup(image_data->
|
|
2031
|
+
drawing_object->description = lxw_strdup(image_data->description);
|
|
1927
2032
|
|
|
1928
2033
|
/* Scale to user scale. */
|
|
1929
2034
|
width = image_data->width * image_data->x_scale;
|
|
@@ -1975,8 +2080,10 @@ mem_error:
|
|
|
1975
2080
|
*/
|
|
1976
2081
|
void
|
|
1977
2082
|
lxw_worksheet_prepare_chart(lxw_worksheet *self,
|
|
1978
|
-
|
|
1979
|
-
|
|
2083
|
+
uint32_t chart_ref_id,
|
|
2084
|
+
uint32_t drawing_id,
|
|
2085
|
+
lxw_image_options *image_data,
|
|
2086
|
+
uint8_t is_chartsheet)
|
|
1980
2087
|
{
|
|
1981
2088
|
lxw_drawing_object *drawing_object;
|
|
1982
2089
|
lxw_rel_tuple *relationship;
|
|
@@ -1986,9 +2093,16 @@ lxw_worksheet_prepare_chart(lxw_worksheet *self,
|
|
|
1986
2093
|
|
|
1987
2094
|
if (!self->drawing) {
|
|
1988
2095
|
self->drawing = lxw_drawing_new();
|
|
1989
|
-
self->drawing->embedded = LXW_TRUE;
|
|
1990
2096
|
RETURN_VOID_ON_MEM_ERROR(self->drawing);
|
|
1991
2097
|
|
|
2098
|
+
if (is_chartsheet) {
|
|
2099
|
+
self->drawing->embedded = LXW_FALSE;
|
|
2100
|
+
self->drawing->orientation = self->orientation;
|
|
2101
|
+
}
|
|
2102
|
+
else {
|
|
2103
|
+
self->drawing->embedded = LXW_TRUE;
|
|
2104
|
+
}
|
|
2105
|
+
|
|
1992
2106
|
relationship = calloc(1, sizeof(lxw_rel_tuple));
|
|
1993
2107
|
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
|
|
1994
2108
|
|
|
@@ -2155,8 +2269,7 @@ _process_png(lxw_image_options *image_options)
|
|
|
2155
2269
|
|
|
2156
2270
|
file_error:
|
|
2157
2271
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
|
2158
|
-
"no size data found in
|
|
2159
|
-
image_options->filename);
|
|
2272
|
+
"no size data found in: %s.", image_options->filename);
|
|
2160
2273
|
|
|
2161
2274
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
|
2162
2275
|
}
|
|
@@ -2183,8 +2296,7 @@ _process_jpeg(lxw_image_options *image_options)
|
|
|
2183
2296
|
if (fseek_err)
|
|
2184
2297
|
goto file_error;
|
|
2185
2298
|
|
|
2186
|
-
/* Search through the image data
|
|
2187
|
-
/* 0xFFC0/C2 element. Also read the DPI in the 0xFFE0 element. */
|
|
2299
|
+
/* Search through the image data and read the JPEG markers. */
|
|
2188
2300
|
while (!feof(stream)) {
|
|
2189
2301
|
|
|
2190
2302
|
/* Read the JPEG marker and length fields for the sub-section. */
|
|
@@ -2201,7 +2313,10 @@ _process_jpeg(lxw_image_options *image_options)
|
|
|
2201
2313
|
/* The offset for next fseek() is the field length + type length. */
|
|
2202
2314
|
offset = length - 2;
|
|
2203
2315
|
|
|
2204
|
-
|
|
2316
|
+
/* Read the height and width in the 0xFFCn elements (except C4, C8 */
|
|
2317
|
+
/* and CC which aren't SOF markers). */
|
|
2318
|
+
if ((marker & 0xFFF0) == 0xFFC0 && marker != 0xFFC4
|
|
2319
|
+
&& marker != 0xFFC8 && marker != 0xFFCC) {
|
|
2205
2320
|
/* Skip 1 byte to height and width. */
|
|
2206
2321
|
fseek_err = fseek(stream, 1, SEEK_CUR);
|
|
2207
2322
|
if (fseek_err)
|
|
@@ -2219,6 +2334,7 @@ _process_jpeg(lxw_image_options *image_options)
|
|
|
2219
2334
|
offset -= 9;
|
|
2220
2335
|
}
|
|
2221
2336
|
|
|
2337
|
+
/* Read the DPI in the 0xFFE0 element. */
|
|
2222
2338
|
if (marker == 0xFFE0) {
|
|
2223
2339
|
uint16_t x_density = 0;
|
|
2224
2340
|
uint16_t y_density = 0;
|
|
@@ -2279,8 +2395,7 @@ _process_jpeg(lxw_image_options *image_options)
|
|
|
2279
2395
|
|
|
2280
2396
|
file_error:
|
|
2281
2397
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
|
2282
|
-
"no size data found in
|
|
2283
|
-
image_options->filename);
|
|
2398
|
+
"no size data found in: %s.", image_options->filename);
|
|
2284
2399
|
|
|
2285
2400
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
|
2286
2401
|
}
|
|
@@ -2314,6 +2429,9 @@ _process_bmp(lxw_image_options *image_options)
|
|
|
2314
2429
|
if (width == 0)
|
|
2315
2430
|
goto file_error;
|
|
2316
2431
|
|
|
2432
|
+
height = LXW_UINT32_HOST(height);
|
|
2433
|
+
width = LXW_UINT32_HOST(width);
|
|
2434
|
+
|
|
2317
2435
|
/* Set the image metadata. */
|
|
2318
2436
|
image_options->image_type = LXW_IMAGE_BMP;
|
|
2319
2437
|
image_options->width = width;
|
|
@@ -2326,8 +2444,7 @@ _process_bmp(lxw_image_options *image_options)
|
|
|
2326
2444
|
|
|
2327
2445
|
file_error:
|
|
2328
2446
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
|
2329
|
-
"no size data found in
|
|
2330
|
-
image_options->filename);
|
|
2447
|
+
"no size data found in: %s.", image_options->filename);
|
|
2331
2448
|
|
|
2332
2449
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
|
2333
2450
|
}
|
|
@@ -2344,7 +2461,7 @@ _get_image_properties(lxw_image_options *image_options)
|
|
|
2344
2461
|
/* Read 4 bytes to look for the file header/signature. */
|
|
2345
2462
|
if (fread(signature, 1, 4, image_options->stream) < 4) {
|
|
2346
2463
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
|
2347
|
-
"couldn't read
|
|
2464
|
+
"couldn't read image type for: %s.",
|
|
2348
2465
|
image_options->filename);
|
|
2349
2466
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
|
2350
2467
|
}
|
|
@@ -2363,7 +2480,7 @@ _get_image_properties(lxw_image_options *image_options)
|
|
|
2363
2480
|
}
|
|
2364
2481
|
else {
|
|
2365
2482
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
|
2366
|
-
"unsupported image format for
|
|
2483
|
+
"unsupported image format for: %s.",
|
|
2367
2484
|
image_options->filename);
|
|
2368
2485
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
|
2369
2486
|
}
|
|
@@ -2385,6 +2502,18 @@ STATIC void
|
|
|
2385
2502
|
_write_number_cell(lxw_worksheet *self, char *range,
|
|
2386
2503
|
int32_t style_index, lxw_cell *cell)
|
|
2387
2504
|
{
|
|
2505
|
+
#ifdef USE_DOUBLE_FUNCTION
|
|
2506
|
+
char data[LXW_ATTR_32];
|
|
2507
|
+
|
|
2508
|
+
lxw_sprintf_dbl(data, cell->u.number);
|
|
2509
|
+
|
|
2510
|
+
if (style_index)
|
|
2511
|
+
fprintf(self->file,
|
|
2512
|
+
"<c r=\"%s\" s=\"%d\"><v>%s</v></c>",
|
|
2513
|
+
range, style_index, data);
|
|
2514
|
+
else
|
|
2515
|
+
fprintf(self->file, "<c r=\"%s\"><v>%s</v></c>", range, data);
|
|
2516
|
+
#else
|
|
2388
2517
|
if (style_index)
|
|
2389
2518
|
fprintf(self->file,
|
|
2390
2519
|
"<c r=\"%s\" s=\"%d\"><v>%.16g</v></c>",
|
|
@@ -2392,6 +2521,8 @@ _write_number_cell(lxw_worksheet *self, char *range,
|
|
|
2392
2521
|
else
|
|
2393
2522
|
fprintf(self->file,
|
|
2394
2523
|
"<c r=\"%s\"><v>%.16g</v></c>", range, cell->u.number);
|
|
2524
|
+
|
|
2525
|
+
#endif
|
|
2395
2526
|
}
|
|
2396
2527
|
|
|
2397
2528
|
/*
|
|
@@ -2402,6 +2533,7 @@ STATIC void
|
|
|
2402
2533
|
_write_string_cell(lxw_worksheet *self, char *range,
|
|
2403
2534
|
int32_t style_index, lxw_cell *cell)
|
|
2404
2535
|
{
|
|
2536
|
+
|
|
2405
2537
|
if (style_index)
|
|
2406
2538
|
fprintf(self->file,
|
|
2407
2539
|
"<c r=\"%s\" s=\"%d\" t=\"s\"><v>%d</v></c>",
|
|
@@ -2451,6 +2583,41 @@ _write_inline_string_cell(lxw_worksheet *self, char *range,
|
|
|
2451
2583
|
free(string);
|
|
2452
2584
|
}
|
|
2453
2585
|
|
|
2586
|
+
/*
|
|
2587
|
+
* Write out an inline rich string. Doesn't use the xml functions as an
|
|
2588
|
+
* optimization in the inner cell writing loop.
|
|
2589
|
+
*/
|
|
2590
|
+
STATIC void
|
|
2591
|
+
_write_inline_rich_string_cell(lxw_worksheet *self, char *range,
|
|
2592
|
+
int32_t style_index, lxw_cell *cell)
|
|
2593
|
+
{
|
|
2594
|
+
char *string = cell->u.string;
|
|
2595
|
+
|
|
2596
|
+
/* Add attribute to preserve leading or trailing whitespace. */
|
|
2597
|
+
if (isspace((unsigned char) string[0])
|
|
2598
|
+
|| isspace((unsigned char) string[strlen(string) - 1])) {
|
|
2599
|
+
|
|
2600
|
+
if (style_index)
|
|
2601
|
+
fprintf(self->file,
|
|
2602
|
+
"<c r=\"%s\" s=\"%d\" t=\"inlineStr\"><is>%s</is></c>",
|
|
2603
|
+
range, style_index, string);
|
|
2604
|
+
else
|
|
2605
|
+
fprintf(self->file,
|
|
2606
|
+
"<c r=\"%s\" t=\"inlineStr\"><is>%s</is></c>",
|
|
2607
|
+
range, string);
|
|
2608
|
+
}
|
|
2609
|
+
else {
|
|
2610
|
+
if (style_index)
|
|
2611
|
+
fprintf(self->file,
|
|
2612
|
+
"<c r=\"%s\" s=\"%d\" t=\"inlineStr\">"
|
|
2613
|
+
"<is>%s</is></c>", range, style_index, string);
|
|
2614
|
+
else
|
|
2615
|
+
fprintf(self->file,
|
|
2616
|
+
"<c r=\"%s\" t=\"inlineStr\">"
|
|
2617
|
+
"<is>%s</is></c>", range, string);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2454
2621
|
/*
|
|
2455
2622
|
* Write out a formula worksheet cell with a numeric result.
|
|
2456
2623
|
*/
|
|
@@ -2459,8 +2626,7 @@ _write_formula_num_cell(lxw_worksheet *self, lxw_cell *cell)
|
|
|
2459
2626
|
{
|
|
2460
2627
|
char data[LXW_ATTR_32];
|
|
2461
2628
|
|
|
2462
|
-
|
|
2463
|
-
|
|
2629
|
+
lxw_sprintf_dbl(data, cell->formula_result);
|
|
2464
2630
|
lxw_xml_data_element(self->file, "f", cell->u.string, NULL);
|
|
2465
2631
|
lxw_xml_data_element(self->file, "v", data, NULL);
|
|
2466
2632
|
}
|
|
@@ -2479,7 +2645,7 @@ _write_array_formula_num_cell(lxw_worksheet *self, lxw_cell *cell)
|
|
|
2479
2645
|
LXW_PUSH_ATTRIBUTES_STR("t", "array");
|
|
2480
2646
|
LXW_PUSH_ATTRIBUTES_STR("ref", cell->user_data1);
|
|
2481
2647
|
|
|
2482
|
-
|
|
2648
|
+
lxw_sprintf_dbl(data, cell->formula_result);
|
|
2483
2649
|
|
|
2484
2650
|
lxw_xml_data_element(self->file, "f", cell->u.string, &attributes);
|
|
2485
2651
|
lxw_xml_data_element(self->file, "v", data, NULL);
|
|
@@ -2515,8 +2681,10 @@ _write_boolean_cell(lxw_worksheet *self, lxw_cell *cell)
|
|
|
2515
2681
|
STATIC void
|
|
2516
2682
|
_calculate_spans(struct lxw_row *row, char *span, int32_t *block_num)
|
|
2517
2683
|
{
|
|
2518
|
-
|
|
2519
|
-
|
|
2684
|
+
lxw_cell *cell_min = RB_MIN(lxw_table_cells, row->cells);
|
|
2685
|
+
lxw_cell *cell_max = RB_MAX(lxw_table_cells, row->cells);
|
|
2686
|
+
lxw_col_t span_col_min = cell_min->col_num;
|
|
2687
|
+
lxw_col_t span_col_max = cell_max->col_num;
|
|
2520
2688
|
lxw_col_t col_min;
|
|
2521
2689
|
lxw_col_t col_max;
|
|
2522
2690
|
*block_num = row->row_num / 16;
|
|
@@ -2526,8 +2694,10 @@ _calculate_spans(struct lxw_row *row, char *span, int32_t *block_num)
|
|
|
2526
2694
|
while (row && (int32_t) (row->row_num / 16) == *block_num) {
|
|
2527
2695
|
|
|
2528
2696
|
if (!RB_EMPTY(row->cells)) {
|
|
2529
|
-
|
|
2530
|
-
|
|
2697
|
+
cell_min = RB_MIN(lxw_table_cells, row->cells);
|
|
2698
|
+
cell_max = RB_MAX(lxw_table_cells, row->cells);
|
|
2699
|
+
col_min = cell_min->col_num;
|
|
2700
|
+
col_max = cell_max->col_num;
|
|
2531
2701
|
|
|
2532
2702
|
if (col_min < span_col_min)
|
|
2533
2703
|
span_col_min = col_min;
|
|
@@ -2584,6 +2754,11 @@ _write_cell(lxw_worksheet *self, lxw_cell *cell, lxw_format *row_format)
|
|
|
2584
2754
|
return;
|
|
2585
2755
|
}
|
|
2586
2756
|
|
|
2757
|
+
if (cell->type == INLINE_RICH_STRING_CELL) {
|
|
2758
|
+
_write_inline_rich_string_cell(self, range, style_index, cell);
|
|
2759
|
+
return;
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2587
2762
|
/* For other cell types use the general functions. */
|
|
2588
2763
|
LXW_INIT_ATTRIBUTES();
|
|
2589
2764
|
LXW_PUSH_ATTRIBUTES_STR("r", range);
|
|
@@ -2922,6 +3097,37 @@ _worksheet_write_tab_color(lxw_worksheet *self)
|
|
|
2922
3097
|
LXW_FREE_ATTRIBUTES();
|
|
2923
3098
|
}
|
|
2924
3099
|
|
|
3100
|
+
/*
|
|
3101
|
+
* Write the <outlinePr> element.
|
|
3102
|
+
*/
|
|
3103
|
+
STATIC void
|
|
3104
|
+
_worksheet_write_outline_pr(lxw_worksheet *self)
|
|
3105
|
+
{
|
|
3106
|
+
struct xml_attribute_list attributes;
|
|
3107
|
+
struct xml_attribute *attribute;
|
|
3108
|
+
|
|
3109
|
+
if (!self->outline_changed)
|
|
3110
|
+
return;
|
|
3111
|
+
|
|
3112
|
+
LXW_INIT_ATTRIBUTES();
|
|
3113
|
+
|
|
3114
|
+
if (self->outline_style)
|
|
3115
|
+
LXW_PUSH_ATTRIBUTES_STR("applyStyles", "1");
|
|
3116
|
+
|
|
3117
|
+
if (!self->outline_below)
|
|
3118
|
+
LXW_PUSH_ATTRIBUTES_STR("summaryBelow", "0");
|
|
3119
|
+
|
|
3120
|
+
if (!self->outline_right)
|
|
3121
|
+
LXW_PUSH_ATTRIBUTES_STR("summaryRight", "0");
|
|
3122
|
+
|
|
3123
|
+
if (!self->outline_on)
|
|
3124
|
+
LXW_PUSH_ATTRIBUTES_STR("showOutlineSymbols", "0");
|
|
3125
|
+
|
|
3126
|
+
lxw_xml_empty_tag(self->file, "outlinePr", &attributes);
|
|
3127
|
+
|
|
3128
|
+
LXW_FREE_ATTRIBUTES();
|
|
3129
|
+
}
|
|
3130
|
+
|
|
2925
3131
|
/*
|
|
2926
3132
|
* Write the <sheetPr> element for Sheet level properties.
|
|
2927
3133
|
*/
|
|
@@ -2934,14 +3140,15 @@ _worksheet_write_sheet_pr(lxw_worksheet *self)
|
|
|
2934
3140
|
if (!self->fit_page
|
|
2935
3141
|
&& !self->filter_on
|
|
2936
3142
|
&& self->tab_color == LXW_COLOR_UNSET
|
|
2937
|
-
&& !self->outline_changed
|
|
3143
|
+
&& !self->outline_changed
|
|
3144
|
+
&& !self->vba_codename && !self->is_chartsheet) {
|
|
2938
3145
|
return;
|
|
2939
3146
|
}
|
|
2940
3147
|
|
|
2941
3148
|
LXW_INIT_ATTRIBUTES();
|
|
2942
3149
|
|
|
2943
3150
|
if (self->vba_codename)
|
|
2944
|
-
|
|
3151
|
+
LXW_PUSH_ATTRIBUTES_STR("codeName", self->vba_codename);
|
|
2945
3152
|
|
|
2946
3153
|
if (self->filter_on)
|
|
2947
3154
|
LXW_PUSH_ATTRIBUTES_STR("filterMode", "1");
|
|
@@ -2950,7 +3157,7 @@ _worksheet_write_sheet_pr(lxw_worksheet *self)
|
|
|
2950
3157
|
|| self->outline_changed) {
|
|
2951
3158
|
lxw_xml_start_tag(self->file, "sheetPr", &attributes);
|
|
2952
3159
|
_worksheet_write_tab_color(self);
|
|
2953
|
-
|
|
3160
|
+
_worksheet_write_outline_pr(self);
|
|
2954
3161
|
_worksheet_write_page_set_up_pr(self);
|
|
2955
3162
|
lxw_xml_end_tag(self->file, "sheetPr");
|
|
2956
3163
|
}
|
|
@@ -3205,13 +3412,12 @@ mem_error:
|
|
|
3205
3412
|
* Write the <sheetProtection> element.
|
|
3206
3413
|
*/
|
|
3207
3414
|
STATIC void
|
|
3208
|
-
_worksheet_write_sheet_protection(lxw_worksheet *self
|
|
3415
|
+
_worksheet_write_sheet_protection(lxw_worksheet *self,
|
|
3416
|
+
lxw_protection *protect)
|
|
3209
3417
|
{
|
|
3210
3418
|
struct xml_attribute_list attributes;
|
|
3211
3419
|
struct xml_attribute *attribute;
|
|
3212
3420
|
|
|
3213
|
-
struct lxw_protection *protect = &self->protection;
|
|
3214
|
-
|
|
3215
3421
|
if (!protect->is_configured)
|
|
3216
3422
|
return;
|
|
3217
3423
|
|
|
@@ -3223,7 +3429,7 @@ _worksheet_write_sheet_protection(lxw_worksheet *self)
|
|
|
3223
3429
|
if (!protect->no_sheet)
|
|
3224
3430
|
LXW_PUSH_ATTRIBUTES_INT("sheet", 1);
|
|
3225
3431
|
|
|
3226
|
-
if (protect->
|
|
3432
|
+
if (!protect->no_content)
|
|
3227
3433
|
LXW_PUSH_ATTRIBUTES_INT("content", 1);
|
|
3228
3434
|
|
|
3229
3435
|
if (!protect->objects)
|
|
@@ -3280,7 +3486,7 @@ _worksheet_write_sheet_protection(lxw_worksheet *self)
|
|
|
3280
3486
|
* Write the <drawing> element.
|
|
3281
3487
|
*/
|
|
3282
3488
|
STATIC void
|
|
3283
|
-
|
|
3489
|
+
_worksheet_write_drawing(lxw_worksheet *self, uint16_t id)
|
|
3284
3490
|
{
|
|
3285
3491
|
struct xml_attribute_list attributes;
|
|
3286
3492
|
struct xml_attribute *attribute;
|
|
@@ -3302,120 +3508,387 @@ _write_drawing(lxw_worksheet *self, uint16_t id)
|
|
|
3302
3508
|
* Write the <drawing> elements.
|
|
3303
3509
|
*/
|
|
3304
3510
|
STATIC void
|
|
3305
|
-
|
|
3511
|
+
_worksheet_write_drawings(lxw_worksheet *self)
|
|
3306
3512
|
{
|
|
3307
3513
|
if (!self->drawing)
|
|
3308
3514
|
return;
|
|
3309
3515
|
|
|
3310
3516
|
self->rel_count++;
|
|
3311
3517
|
|
|
3312
|
-
|
|
3518
|
+
_worksheet_write_drawing(self, self->rel_count);
|
|
3313
3519
|
}
|
|
3314
3520
|
|
|
3315
3521
|
/*
|
|
3316
|
-
*
|
|
3522
|
+
* Write the <formula1> element for numbers.
|
|
3317
3523
|
*/
|
|
3318
|
-
void
|
|
3319
|
-
|
|
3524
|
+
STATIC void
|
|
3525
|
+
_worksheet_write_formula1_num(lxw_worksheet *self, double number)
|
|
3320
3526
|
{
|
|
3321
|
-
|
|
3322
|
-
_worksheet_xml_declaration(self);
|
|
3527
|
+
char data[LXW_ATTR_32];
|
|
3323
3528
|
|
|
3324
|
-
|
|
3325
|
-
_worksheet_write_worksheet(self);
|
|
3529
|
+
lxw_sprintf_dbl(data, number);
|
|
3326
3530
|
|
|
3327
|
-
|
|
3328
|
-
|
|
3531
|
+
lxw_xml_data_element(self->file, "formula1", data, NULL);
|
|
3532
|
+
}
|
|
3329
3533
|
|
|
3330
|
-
|
|
3331
|
-
|
|
3534
|
+
/*
|
|
3535
|
+
* Write the <formula1> element for strings/formulas.
|
|
3536
|
+
*/
|
|
3537
|
+
STATIC void
|
|
3538
|
+
_worksheet_write_formula1_str(lxw_worksheet *self, char *str)
|
|
3539
|
+
{
|
|
3540
|
+
lxw_xml_data_element(self->file, "formula1", str, NULL);
|
|
3541
|
+
}
|
|
3332
3542
|
|
|
3333
|
-
|
|
3334
|
-
|
|
3543
|
+
/*
|
|
3544
|
+
* Write the <formula2> element for numbers.
|
|
3545
|
+
*/
|
|
3546
|
+
STATIC void
|
|
3547
|
+
_worksheet_write_formula2_num(lxw_worksheet *self, double number)
|
|
3548
|
+
{
|
|
3549
|
+
char data[LXW_ATTR_32];
|
|
3335
3550
|
|
|
3336
|
-
|
|
3337
|
-
_worksheet_write_sheet_format_pr(self);
|
|
3551
|
+
lxw_sprintf_dbl(data, number);
|
|
3338
3552
|
|
|
3339
|
-
|
|
3340
|
-
|
|
3553
|
+
lxw_xml_data_element(self->file, "formula2", data, NULL);
|
|
3554
|
+
}
|
|
3341
3555
|
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3556
|
+
/*
|
|
3557
|
+
* Write the <formula2> element for strings/formulas.
|
|
3558
|
+
*/
|
|
3559
|
+
STATIC void
|
|
3560
|
+
_worksheet_write_formula2_str(lxw_worksheet *self, char *str)
|
|
3561
|
+
{
|
|
3562
|
+
lxw_xml_data_element(self->file, "formula2", str, NULL);
|
|
3563
|
+
}
|
|
3347
3564
|
|
|
3348
|
-
|
|
3349
|
-
|
|
3565
|
+
/*
|
|
3566
|
+
* Write the <dataValidation> element.
|
|
3567
|
+
*/
|
|
3568
|
+
STATIC void
|
|
3569
|
+
_worksheet_write_data_validation(lxw_worksheet *self,
|
|
3570
|
+
lxw_data_validation *validation)
|
|
3571
|
+
{
|
|
3572
|
+
struct xml_attribute_list attributes;
|
|
3573
|
+
struct xml_attribute *attribute;
|
|
3574
|
+
uint8_t is_between = 0;
|
|
3350
3575
|
|
|
3351
|
-
|
|
3352
|
-
_worksheet_write_auto_filter(self);
|
|
3576
|
+
LXW_INIT_ATTRIBUTES();
|
|
3353
3577
|
|
|
3354
|
-
|
|
3355
|
-
|
|
3578
|
+
switch (validation->validate) {
|
|
3579
|
+
case LXW_VALIDATION_TYPE_INTEGER:
|
|
3580
|
+
case LXW_VALIDATION_TYPE_INTEGER_FORMULA:
|
|
3581
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "whole");
|
|
3582
|
+
break;
|
|
3583
|
+
case LXW_VALIDATION_TYPE_DECIMAL:
|
|
3584
|
+
case LXW_VALIDATION_TYPE_DECIMAL_FORMULA:
|
|
3585
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "decimal");
|
|
3586
|
+
break;
|
|
3587
|
+
case LXW_VALIDATION_TYPE_LIST:
|
|
3588
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
|
3589
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "list");
|
|
3590
|
+
break;
|
|
3591
|
+
case LXW_VALIDATION_TYPE_DATE:
|
|
3592
|
+
case LXW_VALIDATION_TYPE_DATE_FORMULA:
|
|
3593
|
+
case LXW_VALIDATION_TYPE_DATE_NUMBER:
|
|
3594
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "date");
|
|
3595
|
+
break;
|
|
3596
|
+
case LXW_VALIDATION_TYPE_TIME:
|
|
3597
|
+
case LXW_VALIDATION_TYPE_TIME_FORMULA:
|
|
3598
|
+
case LXW_VALIDATION_TYPE_TIME_NUMBER:
|
|
3599
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "time");
|
|
3600
|
+
break;
|
|
3601
|
+
case LXW_VALIDATION_TYPE_LENGTH:
|
|
3602
|
+
case LXW_VALIDATION_TYPE_LENGTH_FORMULA:
|
|
3603
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "textLength");
|
|
3604
|
+
break;
|
|
3605
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
|
3606
|
+
LXW_PUSH_ATTRIBUTES_STR("type", "custom");
|
|
3607
|
+
break;
|
|
3608
|
+
}
|
|
3356
3609
|
|
|
3357
|
-
|
|
3358
|
-
|
|
3610
|
+
switch (validation->criteria) {
|
|
3611
|
+
case LXW_VALIDATION_CRITERIA_EQUAL_TO:
|
|
3612
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "equal");
|
|
3613
|
+
break;
|
|
3614
|
+
case LXW_VALIDATION_CRITERIA_NOT_EQUAL_TO:
|
|
3615
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "notEqual");
|
|
3616
|
+
break;
|
|
3617
|
+
case LXW_VALIDATION_CRITERIA_LESS_THAN:
|
|
3618
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "lessThan");
|
|
3619
|
+
break;
|
|
3620
|
+
case LXW_VALIDATION_CRITERIA_LESS_THAN_OR_EQUAL_TO:
|
|
3621
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "lessThanOrEqual");
|
|
3622
|
+
break;
|
|
3623
|
+
case LXW_VALIDATION_CRITERIA_GREATER_THAN:
|
|
3624
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "greaterThan");
|
|
3625
|
+
break;
|
|
3626
|
+
case LXW_VALIDATION_CRITERIA_GREATER_THAN_OR_EQUAL_TO:
|
|
3627
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "greaterThanOrEqual");
|
|
3628
|
+
break;
|
|
3629
|
+
case LXW_VALIDATION_CRITERIA_BETWEEN:
|
|
3630
|
+
/* Between is the default for 2 formulas and isn't added. */
|
|
3631
|
+
is_between = 1;
|
|
3632
|
+
break;
|
|
3633
|
+
case LXW_VALIDATION_CRITERIA_NOT_BETWEEN:
|
|
3634
|
+
is_between = 1;
|
|
3635
|
+
LXW_PUSH_ATTRIBUTES_STR("operator", "notBetween");
|
|
3636
|
+
break;
|
|
3637
|
+
}
|
|
3359
3638
|
|
|
3360
|
-
|
|
3361
|
-
|
|
3639
|
+
if (validation->error_type == LXW_VALIDATION_ERROR_TYPE_WARNING)
|
|
3640
|
+
LXW_PUSH_ATTRIBUTES_STR("errorStyle", "warning");
|
|
3362
3641
|
|
|
3363
|
-
|
|
3364
|
-
|
|
3642
|
+
if (validation->error_type == LXW_VALIDATION_ERROR_TYPE_INFORMATION)
|
|
3643
|
+
LXW_PUSH_ATTRIBUTES_STR("errorStyle", "information");
|
|
3365
3644
|
|
|
3366
|
-
|
|
3367
|
-
|
|
3645
|
+
if (validation->ignore_blank)
|
|
3646
|
+
LXW_PUSH_ATTRIBUTES_INT("allowBlank", 1);
|
|
3368
3647
|
|
|
3369
|
-
|
|
3370
|
-
|
|
3648
|
+
if (validation->dropdown == LXW_VALIDATION_OFF)
|
|
3649
|
+
LXW_PUSH_ATTRIBUTES_INT("showDropDown", 1);
|
|
3371
3650
|
|
|
3372
|
-
|
|
3373
|
-
|
|
3651
|
+
if (validation->show_input)
|
|
3652
|
+
LXW_PUSH_ATTRIBUTES_INT("showInputMessage", 1);
|
|
3374
3653
|
|
|
3375
|
-
|
|
3376
|
-
|
|
3654
|
+
if (validation->show_error)
|
|
3655
|
+
LXW_PUSH_ATTRIBUTES_INT("showErrorMessage", 1);
|
|
3377
3656
|
|
|
3378
|
-
|
|
3379
|
-
|
|
3657
|
+
if (validation->error_title)
|
|
3658
|
+
LXW_PUSH_ATTRIBUTES_STR("errorTitle", validation->error_title);
|
|
3380
3659
|
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
}
|
|
3660
|
+
if (validation->error_message)
|
|
3661
|
+
LXW_PUSH_ATTRIBUTES_STR("error", validation->error_message);
|
|
3384
3662
|
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
* Public functions.
|
|
3388
|
-
*
|
|
3389
|
-
****************************************************************************/
|
|
3663
|
+
if (validation->input_title)
|
|
3664
|
+
LXW_PUSH_ATTRIBUTES_STR("promptTitle", validation->input_title);
|
|
3390
3665
|
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
*/
|
|
3394
|
-
lxw_error
|
|
3395
|
-
worksheet_write_number(lxw_worksheet *self,
|
|
3396
|
-
lxw_row_t row_num,
|
|
3397
|
-
lxw_col_t col_num, double value, lxw_format *format)
|
|
3398
|
-
{
|
|
3399
|
-
lxw_cell *cell;
|
|
3400
|
-
lxw_error err;
|
|
3666
|
+
if (validation->input_message)
|
|
3667
|
+
LXW_PUSH_ATTRIBUTES_STR("prompt", validation->input_message);
|
|
3401
3668
|
|
|
3402
|
-
|
|
3403
|
-
if (err)
|
|
3404
|
-
return err;
|
|
3669
|
+
LXW_PUSH_ATTRIBUTES_STR("sqref", validation->sqref);
|
|
3405
3670
|
|
|
3406
|
-
|
|
3671
|
+
if (validation->validate == LXW_VALIDATION_TYPE_ANY)
|
|
3672
|
+
lxw_xml_empty_tag(self->file, "dataValidation", &attributes);
|
|
3673
|
+
else
|
|
3674
|
+
lxw_xml_start_tag(self->file, "dataValidation", &attributes);
|
|
3675
|
+
|
|
3676
|
+
/* Write the formula1 and formula2 elements. */
|
|
3677
|
+
switch (validation->validate) {
|
|
3678
|
+
case LXW_VALIDATION_TYPE_INTEGER:
|
|
3679
|
+
case LXW_VALIDATION_TYPE_DECIMAL:
|
|
3680
|
+
case LXW_VALIDATION_TYPE_LENGTH:
|
|
3681
|
+
case LXW_VALIDATION_TYPE_DATE:
|
|
3682
|
+
case LXW_VALIDATION_TYPE_TIME:
|
|
3683
|
+
case LXW_VALIDATION_TYPE_DATE_NUMBER:
|
|
3684
|
+
case LXW_VALIDATION_TYPE_TIME_NUMBER:
|
|
3685
|
+
_worksheet_write_formula1_num(self, validation->value_number);
|
|
3686
|
+
if (is_between)
|
|
3687
|
+
_worksheet_write_formula2_num(self,
|
|
3688
|
+
validation->maximum_number);
|
|
3689
|
+
break;
|
|
3690
|
+
case LXW_VALIDATION_TYPE_INTEGER_FORMULA:
|
|
3691
|
+
case LXW_VALIDATION_TYPE_DECIMAL_FORMULA:
|
|
3692
|
+
case LXW_VALIDATION_TYPE_LENGTH_FORMULA:
|
|
3693
|
+
case LXW_VALIDATION_TYPE_DATE_FORMULA:
|
|
3694
|
+
case LXW_VALIDATION_TYPE_TIME_FORMULA:
|
|
3695
|
+
case LXW_VALIDATION_TYPE_LIST:
|
|
3696
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
|
3697
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
|
3698
|
+
_worksheet_write_formula1_str(self, validation->value_formula);
|
|
3699
|
+
if (is_between)
|
|
3700
|
+
_worksheet_write_formula2_str(self,
|
|
3701
|
+
validation->maximum_formula);
|
|
3702
|
+
break;
|
|
3703
|
+
}
|
|
3407
3704
|
|
|
3408
|
-
|
|
3705
|
+
if (validation->validate != LXW_VALIDATION_TYPE_ANY)
|
|
3706
|
+
lxw_xml_end_tag(self->file, "dataValidation");
|
|
3409
3707
|
|
|
3410
|
-
|
|
3708
|
+
LXW_FREE_ATTRIBUTES();
|
|
3411
3709
|
}
|
|
3412
3710
|
|
|
3413
3711
|
/*
|
|
3414
|
-
* Write
|
|
3712
|
+
* Write the <dataValidations> element.
|
|
3415
3713
|
*/
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3714
|
+
STATIC void
|
|
3715
|
+
_worksheet_write_data_validations(lxw_worksheet *self)
|
|
3716
|
+
{
|
|
3717
|
+
struct xml_attribute_list attributes;
|
|
3718
|
+
struct xml_attribute *attribute;
|
|
3719
|
+
lxw_data_validation *data_validation;
|
|
3720
|
+
|
|
3721
|
+
if (self->num_validations == 0)
|
|
3722
|
+
return;
|
|
3723
|
+
|
|
3724
|
+
LXW_INIT_ATTRIBUTES();
|
|
3725
|
+
LXW_PUSH_ATTRIBUTES_INT("count", self->num_validations);
|
|
3726
|
+
|
|
3727
|
+
lxw_xml_start_tag(self->file, "dataValidations", &attributes);
|
|
3728
|
+
|
|
3729
|
+
STAILQ_FOREACH(data_validation, self->data_validations, list_pointers) {
|
|
3730
|
+
/* Write the dataValidation element. */
|
|
3731
|
+
_worksheet_write_data_validation(self, data_validation);
|
|
3732
|
+
}
|
|
3733
|
+
|
|
3734
|
+
lxw_xml_end_tag(self->file, "dataValidations");
|
|
3735
|
+
|
|
3736
|
+
LXW_FREE_ATTRIBUTES();
|
|
3737
|
+
}
|
|
3738
|
+
|
|
3739
|
+
/*
|
|
3740
|
+
* External functions to call intern XML methods shared with chartsheet.
|
|
3741
|
+
*/
|
|
3742
|
+
void
|
|
3743
|
+
lxw_worksheet_write_sheet_views(lxw_worksheet *self)
|
|
3744
|
+
{
|
|
3745
|
+
_worksheet_write_sheet_views(self);
|
|
3746
|
+
}
|
|
3747
|
+
|
|
3748
|
+
void
|
|
3749
|
+
lxw_worksheet_write_page_margins(lxw_worksheet *self)
|
|
3750
|
+
{
|
|
3751
|
+
_worksheet_write_page_margins(self);
|
|
3752
|
+
}
|
|
3753
|
+
|
|
3754
|
+
void
|
|
3755
|
+
lxw_worksheet_write_drawings(lxw_worksheet *self)
|
|
3756
|
+
{
|
|
3757
|
+
_worksheet_write_drawings(self);
|
|
3758
|
+
}
|
|
3759
|
+
|
|
3760
|
+
void
|
|
3761
|
+
lxw_worksheet_write_sheet_protection(lxw_worksheet *self,
|
|
3762
|
+
lxw_protection *protect)
|
|
3763
|
+
{
|
|
3764
|
+
_worksheet_write_sheet_protection(self, protect);
|
|
3765
|
+
}
|
|
3766
|
+
|
|
3767
|
+
void
|
|
3768
|
+
lxw_worksheet_write_sheet_pr(lxw_worksheet *self)
|
|
3769
|
+
{
|
|
3770
|
+
_worksheet_write_sheet_pr(self);
|
|
3771
|
+
}
|
|
3772
|
+
|
|
3773
|
+
void
|
|
3774
|
+
lxw_worksheet_write_page_setup(lxw_worksheet *self)
|
|
3775
|
+
{
|
|
3776
|
+
_worksheet_write_page_setup(self);
|
|
3777
|
+
}
|
|
3778
|
+
|
|
3779
|
+
void
|
|
3780
|
+
lxw_worksheet_write_header_footer(lxw_worksheet *self)
|
|
3781
|
+
{
|
|
3782
|
+
_worksheet_write_header_footer(self);
|
|
3783
|
+
}
|
|
3784
|
+
|
|
3785
|
+
/*
|
|
3786
|
+
* Assemble and write the XML file.
|
|
3787
|
+
*/
|
|
3788
|
+
void
|
|
3789
|
+
lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
|
|
3790
|
+
{
|
|
3791
|
+
/* Write the XML declaration. */
|
|
3792
|
+
_worksheet_xml_declaration(self);
|
|
3793
|
+
|
|
3794
|
+
/* Write the worksheet element. */
|
|
3795
|
+
_worksheet_write_worksheet(self);
|
|
3796
|
+
|
|
3797
|
+
/* Write the worksheet properties. */
|
|
3798
|
+
_worksheet_write_sheet_pr(self);
|
|
3799
|
+
|
|
3800
|
+
/* Write the worksheet dimensions. */
|
|
3801
|
+
_worksheet_write_dimension(self);
|
|
3802
|
+
|
|
3803
|
+
/* Write the sheet view properties. */
|
|
3804
|
+
_worksheet_write_sheet_views(self);
|
|
3805
|
+
|
|
3806
|
+
/* Write the sheet format properties. */
|
|
3807
|
+
_worksheet_write_sheet_format_pr(self);
|
|
3808
|
+
|
|
3809
|
+
/* Write the sheet column info. */
|
|
3810
|
+
_worksheet_write_cols(self);
|
|
3811
|
+
|
|
3812
|
+
/* Write the sheetData element. */
|
|
3813
|
+
if (!self->optimize)
|
|
3814
|
+
_worksheet_write_sheet_data(self);
|
|
3815
|
+
else
|
|
3816
|
+
_worksheet_write_optimized_sheet_data(self);
|
|
3817
|
+
|
|
3818
|
+
/* Write the sheetProtection element. */
|
|
3819
|
+
_worksheet_write_sheet_protection(self, &self->protection);
|
|
3820
|
+
|
|
3821
|
+
/* Write the autoFilter element. */
|
|
3822
|
+
_worksheet_write_auto_filter(self);
|
|
3823
|
+
|
|
3824
|
+
/* Write the mergeCells element. */
|
|
3825
|
+
_worksheet_write_merge_cells(self);
|
|
3826
|
+
|
|
3827
|
+
/* Write the dataValidations element. */
|
|
3828
|
+
_worksheet_write_data_validations(self);
|
|
3829
|
+
|
|
3830
|
+
/* Write the hyperlink element. */
|
|
3831
|
+
_worksheet_write_hyperlinks(self);
|
|
3832
|
+
|
|
3833
|
+
/* Write the printOptions element. */
|
|
3834
|
+
_worksheet_write_print_options(self);
|
|
3835
|
+
|
|
3836
|
+
/* Write the worksheet page_margins. */
|
|
3837
|
+
_worksheet_write_page_margins(self);
|
|
3838
|
+
|
|
3839
|
+
/* Write the worksheet page setup. */
|
|
3840
|
+
_worksheet_write_page_setup(self);
|
|
3841
|
+
|
|
3842
|
+
/* Write the headerFooter element. */
|
|
3843
|
+
_worksheet_write_header_footer(self);
|
|
3844
|
+
|
|
3845
|
+
/* Write the rowBreaks element. */
|
|
3846
|
+
_worksheet_write_row_breaks(self);
|
|
3847
|
+
|
|
3848
|
+
/* Write the colBreaks element. */
|
|
3849
|
+
_worksheet_write_col_breaks(self);
|
|
3850
|
+
|
|
3851
|
+
/* Write the drawing element. */
|
|
3852
|
+
_worksheet_write_drawings(self);
|
|
3853
|
+
|
|
3854
|
+
/* Close the worksheet tag. */
|
|
3855
|
+
lxw_xml_end_tag(self->file, "worksheet");
|
|
3856
|
+
}
|
|
3857
|
+
|
|
3858
|
+
/*****************************************************************************
|
|
3859
|
+
*
|
|
3860
|
+
* Public functions.
|
|
3861
|
+
*
|
|
3862
|
+
****************************************************************************/
|
|
3863
|
+
|
|
3864
|
+
/*
|
|
3865
|
+
* Write a number to a cell in Excel.
|
|
3866
|
+
*/
|
|
3867
|
+
lxw_error
|
|
3868
|
+
worksheet_write_number(lxw_worksheet *self,
|
|
3869
|
+
lxw_row_t row_num,
|
|
3870
|
+
lxw_col_t col_num, double value, lxw_format *format)
|
|
3871
|
+
{
|
|
3872
|
+
lxw_cell *cell;
|
|
3873
|
+
lxw_error err;
|
|
3874
|
+
|
|
3875
|
+
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
|
3876
|
+
if (err)
|
|
3877
|
+
return err;
|
|
3878
|
+
|
|
3879
|
+
cell = _new_number_cell(row_num, col_num, value, format);
|
|
3880
|
+
|
|
3881
|
+
_insert_cell(self, row_num, col_num, cell);
|
|
3882
|
+
|
|
3883
|
+
return LXW_NO_ERROR;
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
/*
|
|
3887
|
+
* Write a string to an Excel file.
|
|
3888
|
+
*/
|
|
3889
|
+
lxw_error
|
|
3890
|
+
worksheet_write_string(lxw_worksheet *self,
|
|
3891
|
+
lxw_row_t row_num,
|
|
3419
3892
|
lxw_col_t col_num, const char *string,
|
|
3420
3893
|
lxw_format *format)
|
|
3421
3894
|
{
|
|
@@ -3431,7 +3904,7 @@ worksheet_write_string(lxw_worksheet *self,
|
|
|
3431
3904
|
if (format)
|
|
3432
3905
|
return worksheet_write_blank(self, row_num, col_num, format);
|
|
3433
3906
|
else
|
|
3434
|
-
return
|
|
3907
|
+
return LXW_NO_ERROR;
|
|
3435
3908
|
}
|
|
3436
3909
|
|
|
3437
3910
|
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
|
@@ -3443,7 +3916,7 @@ worksheet_write_string(lxw_worksheet *self,
|
|
|
3443
3916
|
|
|
3444
3917
|
if (!self->optimize) {
|
|
3445
3918
|
/* Get the SST element and string id. */
|
|
3446
|
-
sst_element = lxw_get_sst_index(self->sst, string);
|
|
3919
|
+
sst_element = lxw_get_sst_index(self->sst, string, LXW_FALSE);
|
|
3447
3920
|
|
|
3448
3921
|
if (!sst_element)
|
|
3449
3922
|
return LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND;
|
|
@@ -3918,6 +4391,156 @@ worksheet_write_url(lxw_worksheet *self,
|
|
|
3918
4391
|
NULL);
|
|
3919
4392
|
}
|
|
3920
4393
|
|
|
4394
|
+
/*
|
|
4395
|
+
* Write a rich string to an Excel file.
|
|
4396
|
+
*
|
|
4397
|
+
* Rather than duplicate several of the styles.c font xml methods of styles.c
|
|
4398
|
+
* and write the data to a memory buffer this function creates a temporary
|
|
4399
|
+
* styles object and uses it to write the data to a file. It then reads that
|
|
4400
|
+
* data back into memory and closes the file.
|
|
4401
|
+
*/
|
|
4402
|
+
lxw_error
|
|
4403
|
+
worksheet_write_rich_string(lxw_worksheet *self,
|
|
4404
|
+
lxw_row_t row_num,
|
|
4405
|
+
lxw_col_t col_num,
|
|
4406
|
+
lxw_rich_string_tuple *rich_strings[],
|
|
4407
|
+
lxw_format *format)
|
|
4408
|
+
{
|
|
4409
|
+
lxw_cell *cell;
|
|
4410
|
+
int32_t string_id;
|
|
4411
|
+
struct sst_element *sst_element;
|
|
4412
|
+
lxw_error err;
|
|
4413
|
+
uint8_t i;
|
|
4414
|
+
long file_size;
|
|
4415
|
+
char *rich_string = NULL;
|
|
4416
|
+
char *string_copy = NULL;
|
|
4417
|
+
lxw_styles *styles = NULL;
|
|
4418
|
+
lxw_format *default_format = NULL;
|
|
4419
|
+
lxw_rich_string_tuple *rich_string_tuple = NULL;
|
|
4420
|
+
FILE *tmpfile;
|
|
4421
|
+
|
|
4422
|
+
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
|
4423
|
+
if (err)
|
|
4424
|
+
return err;
|
|
4425
|
+
|
|
4426
|
+
/* Iterate through rich string fragments to check for input errors. */
|
|
4427
|
+
i = 0;
|
|
4428
|
+
err = LXW_NO_ERROR;
|
|
4429
|
+
while ((rich_string_tuple = rich_strings[i++]) != NULL) {
|
|
4430
|
+
|
|
4431
|
+
/* Check for NULL or empty strings. */
|
|
4432
|
+
if (!rich_string_tuple->string || !*rich_string_tuple->string) {
|
|
4433
|
+
err = LXW_ERROR_PARAMETER_VALIDATION;
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4437
|
+
/* If there are less than 2 fragments it isn't a rich string. */
|
|
4438
|
+
if (i <= 2)
|
|
4439
|
+
err = LXW_ERROR_PARAMETER_VALIDATION;
|
|
4440
|
+
|
|
4441
|
+
if (err)
|
|
4442
|
+
return err;
|
|
4443
|
+
|
|
4444
|
+
/* Create a tmp file for the styles object. */
|
|
4445
|
+
tmpfile = lxw_tmpfile(self->tmpdir);
|
|
4446
|
+
if (!tmpfile)
|
|
4447
|
+
return LXW_ERROR_CREATING_TMPFILE;
|
|
4448
|
+
|
|
4449
|
+
/* Create a temp styles object for writing the font data. */
|
|
4450
|
+
styles = lxw_styles_new();
|
|
4451
|
+
GOTO_LABEL_ON_MEM_ERROR(styles, mem_error);
|
|
4452
|
+
styles->file = tmpfile;
|
|
4453
|
+
|
|
4454
|
+
/* Create a default format for non-formatted text. */
|
|
4455
|
+
default_format = lxw_format_new();
|
|
4456
|
+
GOTO_LABEL_ON_MEM_ERROR(default_format, mem_error);
|
|
4457
|
+
|
|
4458
|
+
/* Iterate through the rich string fragments and write each one out. */
|
|
4459
|
+
i = 0;
|
|
4460
|
+
while ((rich_string_tuple = rich_strings[i++]) != NULL) {
|
|
4461
|
+
lxw_xml_start_tag(tmpfile, "r", NULL);
|
|
4462
|
+
|
|
4463
|
+
if (rich_string_tuple->format) {
|
|
4464
|
+
/* Write the user defined font format. */
|
|
4465
|
+
lxw_styles_write_rich_font(styles, rich_string_tuple->format);
|
|
4466
|
+
}
|
|
4467
|
+
else {
|
|
4468
|
+
/* Write a default font format. Except for the first fragment. */
|
|
4469
|
+
if (i > 1)
|
|
4470
|
+
lxw_styles_write_rich_font(styles, default_format);
|
|
4471
|
+
}
|
|
4472
|
+
|
|
4473
|
+
lxw_styles_write_string_fragment(styles, rich_string_tuple->string);
|
|
4474
|
+
lxw_xml_end_tag(tmpfile, "r");
|
|
4475
|
+
}
|
|
4476
|
+
|
|
4477
|
+
/* Free the temp objects. */
|
|
4478
|
+
lxw_styles_free(styles);
|
|
4479
|
+
lxw_format_free(default_format);
|
|
4480
|
+
|
|
4481
|
+
/* Flush the file and read the size to calculate the required memory. */
|
|
4482
|
+
fflush(tmpfile);
|
|
4483
|
+
file_size = ftell(tmpfile);
|
|
4484
|
+
|
|
4485
|
+
/* Allocate a buffer for the rich string xml data. */
|
|
4486
|
+
rich_string = calloc(file_size + 1, 1);
|
|
4487
|
+
GOTO_LABEL_ON_MEM_ERROR(rich_string, mem_error);
|
|
4488
|
+
|
|
4489
|
+
/* Rewind the file and read the data into the memory buffer. */
|
|
4490
|
+
rewind(tmpfile);
|
|
4491
|
+
if (fread(rich_string, file_size, 1, tmpfile) < 1) {
|
|
4492
|
+
fclose(tmpfile);
|
|
4493
|
+
free(rich_string);
|
|
4494
|
+
return LXW_ERROR_READING_TMPFILE;
|
|
4495
|
+
}
|
|
4496
|
+
|
|
4497
|
+
/* Close the temp file. */
|
|
4498
|
+
fclose(tmpfile);
|
|
4499
|
+
|
|
4500
|
+
if (lxw_utf8_strlen(rich_string) > LXW_STR_MAX) {
|
|
4501
|
+
free(rich_string);
|
|
4502
|
+
return LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED;
|
|
4503
|
+
}
|
|
4504
|
+
|
|
4505
|
+
if (!self->optimize) {
|
|
4506
|
+
/* Get the SST element and string id. */
|
|
4507
|
+
sst_element = lxw_get_sst_index(self->sst, rich_string, LXW_TRUE);
|
|
4508
|
+
free(rich_string);
|
|
4509
|
+
|
|
4510
|
+
if (!sst_element)
|
|
4511
|
+
return LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND;
|
|
4512
|
+
|
|
4513
|
+
string_id = sst_element->index;
|
|
4514
|
+
cell = _new_string_cell(row_num, col_num, string_id,
|
|
4515
|
+
sst_element->string, format);
|
|
4516
|
+
}
|
|
4517
|
+
else {
|
|
4518
|
+
/* Look for and escape control chars in the string. */
|
|
4519
|
+
if (strpbrk(rich_string, "\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C"
|
|
4520
|
+
"\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16"
|
|
4521
|
+
"\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")) {
|
|
4522
|
+
string_copy = lxw_escape_control_characters(rich_string);
|
|
4523
|
+
free(rich_string);
|
|
4524
|
+
}
|
|
4525
|
+
else {
|
|
4526
|
+
string_copy = rich_string;
|
|
4527
|
+
}
|
|
4528
|
+
cell = _new_inline_rich_string_cell(row_num, col_num, string_copy,
|
|
4529
|
+
format);
|
|
4530
|
+
}
|
|
4531
|
+
|
|
4532
|
+
_insert_cell(self, row_num, col_num, cell);
|
|
4533
|
+
|
|
4534
|
+
return LXW_NO_ERROR;
|
|
4535
|
+
|
|
4536
|
+
mem_error:
|
|
4537
|
+
lxw_styles_free(styles);
|
|
4538
|
+
lxw_format_free(default_format);
|
|
4539
|
+
fclose(tmpfile);
|
|
4540
|
+
|
|
4541
|
+
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
|
4542
|
+
}
|
|
4543
|
+
|
|
3921
4544
|
/*
|
|
3922
4545
|
* Set the properties of a single column or a range of columns with options.
|
|
3923
4546
|
*/
|
|
@@ -4010,6 +4633,14 @@ worksheet_set_column_opt(lxw_worksheet *self,
|
|
|
4010
4633
|
copied_options = calloc(1, sizeof(lxw_col_options));
|
|
4011
4634
|
RETURN_ON_MEM_ERROR(copied_options, LXW_ERROR_MEMORY_MALLOC_FAILED);
|
|
4012
4635
|
|
|
4636
|
+
/* Ensure the level is <= 7). */
|
|
4637
|
+
if (level > 7)
|
|
4638
|
+
level = 7;
|
|
4639
|
+
|
|
4640
|
+
if (level > self->outline_col_level)
|
|
4641
|
+
self->outline_col_level = level;
|
|
4642
|
+
|
|
4643
|
+
/* Set the column properties. */
|
|
4013
4644
|
copied_options->firstcol = firstcol;
|
|
4014
4645
|
copied_options->lastcol = lastcol;
|
|
4015
4646
|
copied_options->width = width;
|
|
@@ -4082,6 +4713,14 @@ worksheet_set_row_opt(lxw_worksheet *self,
|
|
|
4082
4713
|
height = self->default_row_height;
|
|
4083
4714
|
}
|
|
4084
4715
|
|
|
4716
|
+
/* Ensure the level is <= 7). */
|
|
4717
|
+
if (level > 7)
|
|
4718
|
+
level = 7;
|
|
4719
|
+
|
|
4720
|
+
if (level > self->outline_row_level)
|
|
4721
|
+
self->outline_row_level = level;
|
|
4722
|
+
|
|
4723
|
+
/* Store the row properties. */
|
|
4085
4724
|
row = _get_row(self, row_num);
|
|
4086
4725
|
|
|
4087
4726
|
row->height = height;
|
|
@@ -4467,7 +5106,7 @@ worksheet_set_header_opt(lxw_worksheet *self, const char *string,
|
|
|
4467
5106
|
lxw_header_footer_options *options)
|
|
4468
5107
|
{
|
|
4469
5108
|
if (options) {
|
|
4470
|
-
if (options->margin
|
|
5109
|
+
if (options->margin >= 0.0)
|
|
4471
5110
|
self->margin_header = options->margin;
|
|
4472
5111
|
}
|
|
4473
5112
|
|
|
@@ -4491,7 +5130,7 @@ worksheet_set_footer_opt(lxw_worksheet *self, const char *string,
|
|
|
4491
5130
|
lxw_header_footer_options *options)
|
|
4492
5131
|
{
|
|
4493
5132
|
if (options) {
|
|
4494
|
-
if (options->margin
|
|
5133
|
+
if (options->margin >= 0.0)
|
|
4495
5134
|
self->margin_footer = options->margin;
|
|
4496
5135
|
}
|
|
4497
5136
|
|
|
@@ -4819,20 +5458,50 @@ worksheet_protect(lxw_worksheet *self, const char *password,
|
|
|
4819
5458
|
struct lxw_protection *protect = &self->protection;
|
|
4820
5459
|
|
|
4821
5460
|
/* Copy any user parameters to the internal structure. */
|
|
4822
|
-
if (options)
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
5461
|
+
if (options) {
|
|
5462
|
+
protect->no_select_locked_cells = options->no_select_locked_cells;
|
|
5463
|
+
protect->no_select_unlocked_cells = options->no_select_unlocked_cells;
|
|
5464
|
+
protect->format_cells = options->format_cells;
|
|
5465
|
+
protect->format_columns = options->format_columns;
|
|
5466
|
+
protect->format_rows = options->format_rows;
|
|
5467
|
+
protect->insert_columns = options->insert_columns;
|
|
5468
|
+
protect->insert_rows = options->insert_rows;
|
|
5469
|
+
protect->insert_hyperlinks = options->insert_hyperlinks;
|
|
5470
|
+
protect->delete_columns = options->delete_columns;
|
|
5471
|
+
protect->delete_rows = options->delete_rows;
|
|
5472
|
+
protect->sort = options->sort;
|
|
5473
|
+
protect->autofilter = options->autofilter;
|
|
5474
|
+
protect->pivot_tables = options->pivot_tables;
|
|
5475
|
+
protect->scenarios = options->scenarios;
|
|
5476
|
+
protect->objects = options->objects;
|
|
5477
|
+
}
|
|
4827
5478
|
|
|
4828
5479
|
if (password) {
|
|
4829
|
-
uint16_t hash =
|
|
5480
|
+
uint16_t hash = lxw_hash_password(password);
|
|
4830
5481
|
lxw_snprintf(protect->hash, 5, "%X", hash);
|
|
4831
5482
|
}
|
|
4832
5483
|
|
|
5484
|
+
protect->no_content = LXW_TRUE;
|
|
4833
5485
|
protect->is_configured = LXW_TRUE;
|
|
4834
5486
|
}
|
|
4835
5487
|
|
|
5488
|
+
/*
|
|
5489
|
+
* Set the worksheet properties for outlines and grouping.
|
|
5490
|
+
*/
|
|
5491
|
+
void
|
|
5492
|
+
worksheet_outline_settings(lxw_worksheet *self,
|
|
5493
|
+
uint8_t visible,
|
|
5494
|
+
uint8_t symbols_below,
|
|
5495
|
+
uint8_t symbols_right, uint8_t auto_style)
|
|
5496
|
+
{
|
|
5497
|
+
self->outline_on = visible;
|
|
5498
|
+
self->outline_below = symbols_below;
|
|
5499
|
+
self->outline_right = symbols_right;
|
|
5500
|
+
self->outline_style = auto_style;
|
|
5501
|
+
|
|
5502
|
+
self->outline_changed = LXW_TRUE;
|
|
5503
|
+
}
|
|
5504
|
+
|
|
4836
5505
|
/*
|
|
4837
5506
|
* Set the default row properties
|
|
4838
5507
|
*/
|
|
@@ -4864,7 +5533,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
|
4864
5533
|
lxw_image_options *user_options)
|
|
4865
5534
|
{
|
|
4866
5535
|
FILE *image_stream;
|
|
4867
|
-
char *
|
|
5536
|
+
char *description;
|
|
4868
5537
|
lxw_image_options *options;
|
|
4869
5538
|
|
|
4870
5539
|
if (!filename) {
|
|
@@ -4882,9 +5551,9 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
|
4882
5551
|
return LXW_ERROR_PARAMETER_VALIDATION;
|
|
4883
5552
|
}
|
|
4884
5553
|
|
|
4885
|
-
/*
|
|
4886
|
-
|
|
4887
|
-
if (!
|
|
5554
|
+
/* Use the filename as the default description, like Excel. */
|
|
5555
|
+
description = lxw_basename(filename);
|
|
5556
|
+
if (!description) {
|
|
4888
5557
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
|
4889
5558
|
"couldn't get basename for file: %s.", filename);
|
|
4890
5559
|
fclose(image_stream);
|
|
@@ -4899,14 +5568,15 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
|
4899
5568
|
}
|
|
4900
5569
|
|
|
4901
5570
|
if (user_options) {
|
|
4902
|
-
|
|
4903
|
-
options->
|
|
4904
|
-
options->
|
|
5571
|
+
options->x_offset = user_options->x_offset;
|
|
5572
|
+
options->y_offset = user_options->y_offset;
|
|
5573
|
+
options->x_scale = user_options->x_scale;
|
|
5574
|
+
options->y_scale = user_options->y_scale;
|
|
4905
5575
|
}
|
|
4906
5576
|
|
|
4907
5577
|
/* Copy other options or set defaults. */
|
|
4908
5578
|
options->filename = lxw_strdup(filename);
|
|
4909
|
-
options->
|
|
5579
|
+
options->description = lxw_strdup(description);
|
|
4910
5580
|
options->stream = image_stream;
|
|
4911
5581
|
options->row = row_num;
|
|
4912
5582
|
options->col = col_num;
|
|
@@ -4919,10 +5589,12 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
|
4919
5589
|
|
|
4920
5590
|
if (_get_image_properties(options) == LXW_NO_ERROR) {
|
|
4921
5591
|
STAILQ_INSERT_TAIL(self->image_data, options, list_pointers);
|
|
5592
|
+
fclose(image_stream);
|
|
4922
5593
|
return LXW_NO_ERROR;
|
|
4923
5594
|
}
|
|
4924
5595
|
else {
|
|
4925
|
-
|
|
5596
|
+
_free_image_options(options);
|
|
5597
|
+
fclose(image_stream);
|
|
4926
5598
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
|
4927
5599
|
}
|
|
4928
5600
|
}
|
|
@@ -4938,6 +5610,95 @@ worksheet_insert_image(lxw_worksheet *self,
|
|
|
4938
5610
|
return worksheet_insert_image_opt(self, row_num, col_num, filename, NULL);
|
|
4939
5611
|
}
|
|
4940
5612
|
|
|
5613
|
+
lxw_error
|
|
5614
|
+
worksheet_insert_image_buffer_opt(lxw_worksheet *self,
|
|
5615
|
+
lxw_row_t row_num,
|
|
5616
|
+
lxw_col_t col_num,
|
|
5617
|
+
const unsigned char *image_buffer,
|
|
5618
|
+
size_t image_size,
|
|
5619
|
+
lxw_image_options *user_options)
|
|
5620
|
+
{
|
|
5621
|
+
FILE *image_stream;
|
|
5622
|
+
lxw_image_options *options;
|
|
5623
|
+
|
|
5624
|
+
if (!image_size) {
|
|
5625
|
+
LXW_WARN("worksheet_insert_image_buffer()/_opt(): "
|
|
5626
|
+
"size must be non-zero.");
|
|
5627
|
+
return LXW_ERROR_NULL_PARAMETER_IGNORED;
|
|
5628
|
+
}
|
|
5629
|
+
|
|
5630
|
+
/* Write the image buffer to a temporary file so we can read the
|
|
5631
|
+
* dimensions like an ordinary file. */
|
|
5632
|
+
image_stream = lxw_tmpfile(self->tmpdir);
|
|
5633
|
+
if (!image_stream)
|
|
5634
|
+
return LXW_ERROR_CREATING_TMPFILE;
|
|
5635
|
+
|
|
5636
|
+
fwrite(image_buffer, 1, image_size, image_stream);
|
|
5637
|
+
rewind(image_stream);
|
|
5638
|
+
|
|
5639
|
+
/* Create a new object to hold the image options. */
|
|
5640
|
+
options = calloc(1, sizeof(lxw_image_options));
|
|
5641
|
+
if (!options) {
|
|
5642
|
+
fclose(image_stream);
|
|
5643
|
+
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
|
5644
|
+
}
|
|
5645
|
+
|
|
5646
|
+
/* Store the image data in the options structure. */
|
|
5647
|
+
options->image_buffer = calloc(1, image_size);
|
|
5648
|
+
if (!options->image_buffer) {
|
|
5649
|
+
_free_image_options(options);
|
|
5650
|
+
fclose(image_stream);
|
|
5651
|
+
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
|
5652
|
+
}
|
|
5653
|
+
else {
|
|
5654
|
+
memcpy(options->image_buffer, image_buffer, image_size);
|
|
5655
|
+
options->image_buffer_size = image_size;
|
|
5656
|
+
options->is_image_buffer = LXW_TRUE;
|
|
5657
|
+
}
|
|
5658
|
+
|
|
5659
|
+
if (user_options) {
|
|
5660
|
+
options->x_offset = user_options->x_offset;
|
|
5661
|
+
options->y_offset = user_options->y_offset;
|
|
5662
|
+
options->x_scale = user_options->x_scale;
|
|
5663
|
+
options->y_scale = user_options->y_scale;
|
|
5664
|
+
options->description = lxw_strdup(user_options->description);
|
|
5665
|
+
}
|
|
5666
|
+
|
|
5667
|
+
/* Copy other options or set defaults. */
|
|
5668
|
+
options->filename = lxw_strdup("image_buffer");
|
|
5669
|
+
options->stream = image_stream;
|
|
5670
|
+
options->row = row_num;
|
|
5671
|
+
options->col = col_num;
|
|
5672
|
+
|
|
5673
|
+
if (!options->x_scale)
|
|
5674
|
+
options->x_scale = 1;
|
|
5675
|
+
|
|
5676
|
+
if (!options->y_scale)
|
|
5677
|
+
options->y_scale = 1;
|
|
5678
|
+
|
|
5679
|
+
if (_get_image_properties(options) == LXW_NO_ERROR) {
|
|
5680
|
+
STAILQ_INSERT_TAIL(self->image_data, options, list_pointers);
|
|
5681
|
+
fclose(image_stream);
|
|
5682
|
+
return LXW_NO_ERROR;
|
|
5683
|
+
}
|
|
5684
|
+
else {
|
|
5685
|
+
_free_image_options(options);
|
|
5686
|
+
fclose(image_stream);
|
|
5687
|
+
return LXW_ERROR_IMAGE_DIMENSIONS;
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
|
|
5691
|
+
lxw_error
|
|
5692
|
+
worksheet_insert_image_buffer(lxw_worksheet *self,
|
|
5693
|
+
lxw_row_t row_num,
|
|
5694
|
+
lxw_col_t col_num,
|
|
5695
|
+
const unsigned char *image_buffer,
|
|
5696
|
+
size_t image_size)
|
|
5697
|
+
{
|
|
5698
|
+
return worksheet_insert_image_buffer_opt(self, row_num, col_num,
|
|
5699
|
+
image_buffer, image_size, NULL);
|
|
5700
|
+
}
|
|
5701
|
+
|
|
4941
5702
|
/*
|
|
4942
5703
|
* Insert an chart into the worksheet.
|
|
4943
5704
|
*/
|
|
@@ -4984,8 +5745,12 @@ worksheet_insert_chart_opt(lxw_worksheet *self,
|
|
|
4984
5745
|
options = calloc(1, sizeof(lxw_image_options));
|
|
4985
5746
|
RETURN_ON_MEM_ERROR(options, LXW_ERROR_MEMORY_MALLOC_FAILED);
|
|
4986
5747
|
|
|
4987
|
-
if (user_options)
|
|
4988
|
-
|
|
5748
|
+
if (user_options) {
|
|
5749
|
+
options->x_offset = user_options->x_offset;
|
|
5750
|
+
options->y_offset = user_options->y_offset;
|
|
5751
|
+
options->x_scale = user_options->x_scale;
|
|
5752
|
+
options->y_scale = user_options->y_scale;
|
|
5753
|
+
}
|
|
4989
5754
|
|
|
4990
5755
|
/* Copy other options or set defaults. */
|
|
4991
5756
|
options->row = row_num;
|
|
@@ -5020,3 +5785,304 @@ worksheet_insert_chart(lxw_worksheet *self,
|
|
|
5020
5785
|
{
|
|
5021
5786
|
return worksheet_insert_chart_opt(self, row_num, col_num, chart, NULL);
|
|
5022
5787
|
}
|
|
5788
|
+
|
|
5789
|
+
/*
|
|
5790
|
+
* Add a data validation to a worksheet, for a range. Ironically this requires
|
|
5791
|
+
* a lot of validation of the user input.
|
|
5792
|
+
*/
|
|
5793
|
+
lxw_error
|
|
5794
|
+
worksheet_data_validation_range(lxw_worksheet *self, lxw_row_t first_row,
|
|
5795
|
+
lxw_col_t first_col,
|
|
5796
|
+
lxw_row_t last_row,
|
|
5797
|
+
lxw_col_t last_col,
|
|
5798
|
+
lxw_data_validation *validation)
|
|
5799
|
+
{
|
|
5800
|
+
lxw_data_validation *copy;
|
|
5801
|
+
uint8_t is_between = LXW_FALSE;
|
|
5802
|
+
uint8_t is_formula = LXW_FALSE;
|
|
5803
|
+
uint8_t has_criteria = LXW_TRUE;
|
|
5804
|
+
lxw_error err;
|
|
5805
|
+
lxw_row_t tmp_row;
|
|
5806
|
+
lxw_col_t tmp_col;
|
|
5807
|
+
size_t length;
|
|
5808
|
+
|
|
5809
|
+
/* No action is required for validation type 'any' unless there are
|
|
5810
|
+
* input messages to display.*/
|
|
5811
|
+
if (validation->validate == LXW_VALIDATION_TYPE_ANY
|
|
5812
|
+
&& !(validation->input_title || validation->input_message)) {
|
|
5813
|
+
|
|
5814
|
+
return LXW_NO_ERROR;
|
|
5815
|
+
}
|
|
5816
|
+
|
|
5817
|
+
/* Check for formula types. */
|
|
5818
|
+
switch (validation->validate) {
|
|
5819
|
+
case LXW_VALIDATION_TYPE_INTEGER_FORMULA:
|
|
5820
|
+
case LXW_VALIDATION_TYPE_DECIMAL_FORMULA:
|
|
5821
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
|
5822
|
+
case LXW_VALIDATION_TYPE_LENGTH_FORMULA:
|
|
5823
|
+
case LXW_VALIDATION_TYPE_DATE_FORMULA:
|
|
5824
|
+
case LXW_VALIDATION_TYPE_TIME_FORMULA:
|
|
5825
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
|
5826
|
+
is_formula = LXW_TRUE;
|
|
5827
|
+
break;
|
|
5828
|
+
}
|
|
5829
|
+
|
|
5830
|
+
/* Check for types without a criteria. */
|
|
5831
|
+
switch (validation->validate) {
|
|
5832
|
+
case LXW_VALIDATION_TYPE_LIST:
|
|
5833
|
+
case LXW_VALIDATION_TYPE_LIST_FORMULA:
|
|
5834
|
+
case LXW_VALIDATION_TYPE_ANY:
|
|
5835
|
+
case LXW_VALIDATION_TYPE_CUSTOM_FORMULA:
|
|
5836
|
+
has_criteria = LXW_FALSE;
|
|
5837
|
+
break;
|
|
5838
|
+
}
|
|
5839
|
+
|
|
5840
|
+
/* Check that a validation parameter has been specified
|
|
5841
|
+
* except for 'list', 'any' and 'custom'. */
|
|
5842
|
+
if (has_criteria && validation->criteria == LXW_VALIDATION_CRITERIA_NONE) {
|
|
5843
|
+
|
|
5844
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
|
5845
|
+
"criteria parameter must be specified.");
|
|
5846
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
|
5847
|
+
}
|
|
5848
|
+
|
|
5849
|
+
/* Check for "between" criteria so we can do additional checks. */
|
|
5850
|
+
if (has_criteria
|
|
5851
|
+
&& (validation->criteria == LXW_VALIDATION_CRITERIA_BETWEEN
|
|
5852
|
+
|| validation->criteria == LXW_VALIDATION_CRITERIA_NOT_BETWEEN)) {
|
|
5853
|
+
|
|
5854
|
+
is_between = LXW_TRUE;
|
|
5855
|
+
}
|
|
5856
|
+
|
|
5857
|
+
/* Check that formula values are non NULL. */
|
|
5858
|
+
if (is_formula) {
|
|
5859
|
+
if (is_between) {
|
|
5860
|
+
if (!validation->minimum_formula) {
|
|
5861
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
|
5862
|
+
"minimum_formula parameter cannot be NULL.");
|
|
5863
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
|
5864
|
+
}
|
|
5865
|
+
if (!validation->maximum_formula) {
|
|
5866
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
|
5867
|
+
"maximum_formula parameter cannot be NULL.");
|
|
5868
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
|
5869
|
+
}
|
|
5870
|
+
}
|
|
5871
|
+
else {
|
|
5872
|
+
if (!validation->value_formula) {
|
|
5873
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
|
5874
|
+
"formula parameter cannot be NULL.");
|
|
5875
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
|
5876
|
+
}
|
|
5877
|
+
}
|
|
5878
|
+
}
|
|
5879
|
+
|
|
5880
|
+
/* Check Excel limitations on input strings. */
|
|
5881
|
+
if (validation->input_title) {
|
|
5882
|
+
length = lxw_utf8_strlen(validation->input_title);
|
|
5883
|
+
if (length > LXW_VALIDATION_MAX_TITLE_LENGTH) {
|
|
5884
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
|
5885
|
+
"input_title length > Excel limit of %d.",
|
|
5886
|
+
LXW_VALIDATION_MAX_TITLE_LENGTH);
|
|
5887
|
+
return LXW_ERROR_32_STRING_LENGTH_EXCEEDED;
|
|
5888
|
+
}
|
|
5889
|
+
}
|
|
5890
|
+
|
|
5891
|
+
if (validation->error_title) {
|
|
5892
|
+
length = lxw_utf8_strlen(validation->error_title);
|
|
5893
|
+
if (length > LXW_VALIDATION_MAX_TITLE_LENGTH) {
|
|
5894
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
|
5895
|
+
"error_title length > Excel limit of %d.",
|
|
5896
|
+
LXW_VALIDATION_MAX_TITLE_LENGTH);
|
|
5897
|
+
return LXW_ERROR_32_STRING_LENGTH_EXCEEDED;
|
|
5898
|
+
}
|
|
5899
|
+
}
|
|
5900
|
+
|
|
5901
|
+
if (validation->input_message) {
|
|
5902
|
+
length = lxw_utf8_strlen(validation->input_message);
|
|
5903
|
+
if (length > LXW_VALIDATION_MAX_STRING_LENGTH) {
|
|
5904
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
|
5905
|
+
"input_message length > Excel limit of %d.",
|
|
5906
|
+
LXW_VALIDATION_MAX_STRING_LENGTH);
|
|
5907
|
+
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
|
|
5908
|
+
}
|
|
5909
|
+
}
|
|
5910
|
+
|
|
5911
|
+
if (validation->error_message) {
|
|
5912
|
+
length = lxw_utf8_strlen(validation->error_message);
|
|
5913
|
+
if (length > LXW_VALIDATION_MAX_STRING_LENGTH) {
|
|
5914
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
|
5915
|
+
"error_message length > Excel limit of %d.",
|
|
5916
|
+
LXW_VALIDATION_MAX_STRING_LENGTH);
|
|
5917
|
+
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
|
|
5918
|
+
}
|
|
5919
|
+
}
|
|
5920
|
+
|
|
5921
|
+
if (validation->validate == LXW_VALIDATION_TYPE_LIST) {
|
|
5922
|
+
length = _validation_list_length(validation->value_list);
|
|
5923
|
+
|
|
5924
|
+
if (length == 0) {
|
|
5925
|
+
LXW_WARN_FORMAT("worksheet_data_validation_cell()/_range(): "
|
|
5926
|
+
"list parameters cannot be zero.");
|
|
5927
|
+
return LXW_ERROR_PARAMETER_VALIDATION;
|
|
5928
|
+
}
|
|
5929
|
+
|
|
5930
|
+
if (length > LXW_VALIDATION_MAX_STRING_LENGTH) {
|
|
5931
|
+
LXW_WARN_FORMAT1("worksheet_data_validation_cell()/_range(): "
|
|
5932
|
+
"list length with commas > Excel limit of %d.",
|
|
5933
|
+
LXW_VALIDATION_MAX_STRING_LENGTH);
|
|
5934
|
+
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
|
|
5938
|
+
/* Swap last row/col with first row/col as necessary */
|
|
5939
|
+
if (first_row > last_row) {
|
|
5940
|
+
tmp_row = last_row;
|
|
5941
|
+
last_row = first_row;
|
|
5942
|
+
first_row = tmp_row;
|
|
5943
|
+
}
|
|
5944
|
+
if (first_col > last_col) {
|
|
5945
|
+
tmp_col = last_col;
|
|
5946
|
+
last_col = first_col;
|
|
5947
|
+
first_col = tmp_col;
|
|
5948
|
+
}
|
|
5949
|
+
|
|
5950
|
+
/* Check that dimensions are valid but don't store them. */
|
|
5951
|
+
err = _check_dimensions(self, last_row, last_col, LXW_TRUE, LXW_TRUE);
|
|
5952
|
+
if (err)
|
|
5953
|
+
return err;
|
|
5954
|
+
|
|
5955
|
+
/* Create a copy of the parameters from the user data validation. */
|
|
5956
|
+
copy = calloc(1, sizeof(lxw_data_validation));
|
|
5957
|
+
GOTO_LABEL_ON_MEM_ERROR(copy, mem_error);
|
|
5958
|
+
|
|
5959
|
+
/* Create the data validation range. */
|
|
5960
|
+
if (first_row == last_row && first_col == last_col)
|
|
5961
|
+
lxw_rowcol_to_cell(copy->sqref, first_row, last_col);
|
|
5962
|
+
else
|
|
5963
|
+
lxw_rowcol_to_range(copy->sqref, first_row, first_col, last_row,
|
|
5964
|
+
last_col);
|
|
5965
|
+
|
|
5966
|
+
/* Copy the parameters from the user data validation. */
|
|
5967
|
+
copy->validate = validation->validate;
|
|
5968
|
+
copy->value_number = validation->value_number;
|
|
5969
|
+
copy->error_type = validation->error_type;
|
|
5970
|
+
copy->dropdown = validation->dropdown;
|
|
5971
|
+
copy->is_between = is_between;
|
|
5972
|
+
|
|
5973
|
+
if (has_criteria)
|
|
5974
|
+
copy->criteria = validation->criteria;
|
|
5975
|
+
|
|
5976
|
+
if (is_between) {
|
|
5977
|
+
copy->value_number = validation->minimum_number;
|
|
5978
|
+
copy->maximum_number = validation->maximum_number;
|
|
5979
|
+
}
|
|
5980
|
+
|
|
5981
|
+
/* Copy the input/error titles and messages. */
|
|
5982
|
+
if (validation->input_title) {
|
|
5983
|
+
copy->input_title = lxw_strdup_formula(validation->input_title);
|
|
5984
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->input_title, mem_error);
|
|
5985
|
+
}
|
|
5986
|
+
|
|
5987
|
+
if (validation->input_message) {
|
|
5988
|
+
copy->input_message = lxw_strdup_formula(validation->input_message);
|
|
5989
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->input_message, mem_error);
|
|
5990
|
+
}
|
|
5991
|
+
|
|
5992
|
+
if (validation->error_title) {
|
|
5993
|
+
copy->error_title = lxw_strdup_formula(validation->error_title);
|
|
5994
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->error_title, mem_error);
|
|
5995
|
+
}
|
|
5996
|
+
|
|
5997
|
+
if (validation->error_message) {
|
|
5998
|
+
copy->error_message = lxw_strdup_formula(validation->error_message);
|
|
5999
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->error_message, mem_error);
|
|
6000
|
+
}
|
|
6001
|
+
|
|
6002
|
+
/* Copy the formula strings. */
|
|
6003
|
+
if (is_formula) {
|
|
6004
|
+
if (is_between) {
|
|
6005
|
+
copy->value_formula =
|
|
6006
|
+
lxw_strdup_formula(validation->minimum_formula);
|
|
6007
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
|
6008
|
+
copy->maximum_formula =
|
|
6009
|
+
lxw_strdup_formula(validation->maximum_formula);
|
|
6010
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->maximum_formula, mem_error);
|
|
6011
|
+
}
|
|
6012
|
+
else {
|
|
6013
|
+
copy->value_formula =
|
|
6014
|
+
lxw_strdup_formula(validation->value_formula);
|
|
6015
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
|
6016
|
+
}
|
|
6017
|
+
}
|
|
6018
|
+
|
|
6019
|
+
/* Copy the validation list as a csv string. */
|
|
6020
|
+
if (validation->validate == LXW_VALIDATION_TYPE_LIST) {
|
|
6021
|
+
copy->value_formula = _validation_list_to_csv(validation->value_list);
|
|
6022
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
|
6023
|
+
}
|
|
6024
|
+
|
|
6025
|
+
if (validation->validate == LXW_VALIDATION_TYPE_LIST_FORMULA) {
|
|
6026
|
+
copy->value_formula = lxw_strdup_formula(validation->value_formula);
|
|
6027
|
+
GOTO_LABEL_ON_MEM_ERROR(copy->value_formula, mem_error);
|
|
6028
|
+
}
|
|
6029
|
+
|
|
6030
|
+
if (validation->validate == LXW_VALIDATION_TYPE_DATE
|
|
6031
|
+
|| validation->validate == LXW_VALIDATION_TYPE_TIME) {
|
|
6032
|
+
if (is_between) {
|
|
6033
|
+
copy->value_number =
|
|
6034
|
+
lxw_datetime_to_excel_date(&validation->minimum_datetime,
|
|
6035
|
+
LXW_EPOCH_1900);
|
|
6036
|
+
copy->maximum_number =
|
|
6037
|
+
lxw_datetime_to_excel_date(&validation->maximum_datetime,
|
|
6038
|
+
LXW_EPOCH_1900);
|
|
6039
|
+
}
|
|
6040
|
+
else {
|
|
6041
|
+
copy->value_number =
|
|
6042
|
+
lxw_datetime_to_excel_date(&validation->value_datetime,
|
|
6043
|
+
LXW_EPOCH_1900);
|
|
6044
|
+
}
|
|
6045
|
+
}
|
|
6046
|
+
|
|
6047
|
+
/* These options are on by default so we can't take plain booleans. */
|
|
6048
|
+
copy->ignore_blank = validation->ignore_blank ^ 1;
|
|
6049
|
+
copy->show_input = validation->show_input ^ 1;
|
|
6050
|
+
copy->show_error = validation->show_error ^ 1;
|
|
6051
|
+
|
|
6052
|
+
STAILQ_INSERT_TAIL(self->data_validations, copy, list_pointers);
|
|
6053
|
+
|
|
6054
|
+
self->num_validations++;
|
|
6055
|
+
|
|
6056
|
+
return LXW_NO_ERROR;
|
|
6057
|
+
|
|
6058
|
+
mem_error:
|
|
6059
|
+
_free_data_validation(copy);
|
|
6060
|
+
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
|
6061
|
+
}
|
|
6062
|
+
|
|
6063
|
+
/*
|
|
6064
|
+
* Add a data validation to a worksheet, for a cell.
|
|
6065
|
+
*/
|
|
6066
|
+
lxw_error
|
|
6067
|
+
worksheet_data_validation_cell(lxw_worksheet *self, lxw_row_t row,
|
|
6068
|
+
lxw_col_t col, lxw_data_validation *validation)
|
|
6069
|
+
{
|
|
6070
|
+
return worksheet_data_validation_range(self, row, col,
|
|
6071
|
+
row, col, validation);
|
|
6072
|
+
}
|
|
6073
|
+
|
|
6074
|
+
/*
|
|
6075
|
+
* Set the VBA name for the worksheet.
|
|
6076
|
+
*/
|
|
6077
|
+
lxw_error
|
|
6078
|
+
worksheet_set_vba_name(lxw_worksheet *self, const char *name)
|
|
6079
|
+
{
|
|
6080
|
+
if (!name) {
|
|
6081
|
+
LXW_WARN("worksheet_set_vba_name(): " "name must be specified.");
|
|
6082
|
+
return LXW_ERROR_NULL_PARAMETER_IGNORED;
|
|
6083
|
+
}
|
|
6084
|
+
|
|
6085
|
+
self->vba_codename = lxw_strdup(name);
|
|
6086
|
+
|
|
6087
|
+
return LXW_NO_ERROR;
|
|
6088
|
+
}
|