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