xlsxwriter 0.2.1.pre → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +4 -3
- data/ext/xlsxwriter/chart.c +88 -80
- data/ext/xlsxwriter/chart.h +2 -2
- data/ext/xlsxwriter/chartsheet.c +307 -0
- data/ext/xlsxwriter/chartsheet.h +15 -0
- data/ext/xlsxwriter/common.h +104 -0
- data/ext/xlsxwriter/extconf.rb +8 -8
- data/ext/xlsxwriter/libxlsxwriter/License.txt +24 -2
- data/ext/xlsxwriter/libxlsxwriter/Makefile +46 -12
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/app.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chart.h +196 -30
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chartsheet.h +3 -3
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/comment.h +76 -0
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/common.h +24 -5
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/content_types.h +5 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/core.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/drawing.h +6 -17
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/format.h +20 -6
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/packager.h +3 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/styles.h +11 -5
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/third_party/md5.h +43 -0
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/utility.h +42 -3
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/vml.h +55 -0
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/workbook.h +83 -18
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/worksheet.h +1519 -109
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/xmlwriter.h +4 -2
- data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter.h +3 -2
- data/ext/xlsxwriter/libxlsxwriter/src/Makefile +25 -7
- data/ext/xlsxwriter/libxlsxwriter/src/app.c +1 -1
- data/ext/xlsxwriter/libxlsxwriter/src/chart.c +332 -48
- data/ext/xlsxwriter/libxlsxwriter/src/chartsheet.c +20 -19
- data/ext/xlsxwriter/libxlsxwriter/src/comment.c +443 -0
- data/ext/xlsxwriter/libxlsxwriter/src/content_types.c +20 -1
- data/ext/xlsxwriter/libxlsxwriter/src/core.c +2 -2
- data/ext/xlsxwriter/libxlsxwriter/src/custom.c +1 -1
- data/ext/xlsxwriter/libxlsxwriter/src/drawing.c +58 -20
- data/ext/xlsxwriter/libxlsxwriter/src/format.c +98 -25
- data/ext/xlsxwriter/libxlsxwriter/src/hash_table.c +1 -1
- data/ext/xlsxwriter/libxlsxwriter/src/packager.c +269 -12
- data/ext/xlsxwriter/libxlsxwriter/src/relationships.c +1 -1
- data/ext/xlsxwriter/libxlsxwriter/src/shared_strings.c +2 -4
- data/ext/xlsxwriter/libxlsxwriter/src/styles.c +334 -48
- data/ext/xlsxwriter/libxlsxwriter/src/theme.c +1 -1
- data/ext/xlsxwriter/libxlsxwriter/src/utility.c +71 -8
- data/ext/xlsxwriter/libxlsxwriter/src/vml.c +1032 -0
- data/ext/xlsxwriter/libxlsxwriter/src/workbook.c +343 -27
- data/ext/xlsxwriter/libxlsxwriter/src/worksheet.c +3759 -478
- data/ext/xlsxwriter/libxlsxwriter/src/xmlwriter.c +81 -2
- data/ext/xlsxwriter/libxlsxwriter/third_party/md5/Makefile +42 -0
- data/ext/xlsxwriter/libxlsxwriter/third_party/md5/md5.c +291 -0
- data/ext/xlsxwriter/libxlsxwriter/third_party/md5/md5.h +43 -0
- data/ext/xlsxwriter/shared_strings.c +65 -0
- data/ext/xlsxwriter/shared_strings.h +15 -0
- data/ext/xlsxwriter/workbook.c +96 -20
- data/ext/xlsxwriter/worksheet.c +125 -235
- data/ext/xlsxwriter/worksheet.h +2 -1
- data/ext/xlsxwriter/xlsxwriter.c +4 -0
- data/lib/xlsxwriter/rich_string.rb +0 -2
- data/lib/xlsxwriter/version.rb +1 -1
- data/lib/xlsxwriter/worksheet.rb +2 -2
- data/test/{run-test.rb → run_test.rb} +3 -3
- data/test/support/chart_test.rb +3 -3
- data/test/support/with_xlsx_file.rb +4 -2
- data/test/support/xlsx_comparable.rb +40 -26
- data/test/test_array_formula.rb +42 -0
- data/test/test_autofilter.rb +72 -0
- data/test/{test-chart-area.rb → test_chart_area.rb} +2 -2
- data/test/{test-chart-axis.rb → test_chart_axis.rb} +16 -16
- data/test/test_chart_bar.rb +382 -0
- data/test/test_chart_blank.rb +27 -0
- data/test/{test-chart-column.rb → test_chart_column.rb} +2 -2
- data/test/{test-chart-doughnut.rb → test_chart_doughnut.rb} +2 -2
- data/test/{test-chart-legend.rb → test_chart_legend.rb} +2 -2
- data/test/{test-chart-pie.rb → test_chart_pie.rb} +2 -2
- data/test/{test-chart-scatter.rb → test_chart_scatter.rb} +3 -4
- data/test/{test-chart-size.rb → test_chart_size.rb} +2 -2
- data/test/{test-chart-title.rb → test_chart_title.rb} +3 -3
- data/test/test_chartsheet.rb +201 -0
- data/test/{test-data.rb → test_data.rb} +1 -1
- data/test/{test-data-validation.rb → test_data_validation.rb} +23 -24
- data/test/{test-default-row.rb → test_default_row.rb} +1 -1
- data/test/{test-defined-name.rb → test_defined_name.rb} +12 -12
- data/test/{test-escapes.rb → test_escapes.rb} +5 -2
- data/test/{test-fit-to-pages.rb → test_fit_to_pages.rb} +6 -6
- data/test/{test-formatting.rb → test_formatting.rb} +10 -10
- data/test/{test-gridlines.rb → test_gridlines.rb} +3 -3
- data/test/{test-hyperlink.rb → test_hyperlink.rb} +22 -11
- data/test/{test-image.rb → test_image.rb} +6 -4
- data/test/{test-macro.rb → test_macro.rb} +1 -1
- data/test/{test-merge-range.rb → test_merge_range.rb} +1 -1
- data/test/{test-misc.rb → test_misc.rb} +2 -2
- data/test/{test-optimize.rb → test_optimize.rb} +2 -4
- data/test/{test-outline.rb → test_outline.rb} +14 -14
- data/test/{test-page-breaks.rb → test_page_breaks.rb} +2 -2
- data/test/{test-page-setup.rb → test_page_setup.rb} +2 -2
- data/test/{test-panes.rb → test_panes.rb} +1 -1
- data/test/{test-print-area.rb → test_print_area.rb} +3 -3
- data/test/{test-print-options.rb → test_print_options.rb} +7 -7
- data/test/{test-print-scale.rb → test_print_scale.rb} +2 -2
- data/test/{test-properties.rb → test_properties.rb} +2 -2
- data/test/{test-protect.rb → test_protect.rb} +3 -3
- data/test/{test-repeat.rb → test_repeat.rb} +3 -3
- data/test/{test-rich-string.rb → test_rich_string.rb} +5 -9
- data/test/{test-row-col-format.rb → test_row_col_format.rb} +1 -1
- data/test/{test-ruby-worksheet.rb → test_ruby_worksheet.rb} +2 -2
- data/test/{test-set-selection.rb → test_set_selection.rb} +2 -2
- data/test/{test-set-start-page.rb → test_set_start_page.rb} +2 -2
- data/test/{test-simple.rb → test_simple.rb} +10 -10
- data/test/{test-types.rb → test_types.rb} +1 -1
- data/test/{xlsx-func-testcase.rb → xlsx_func_testcase.rb} +1 -0
- metadata +135 -104
- data/test/test-array-formula.rb +0 -35
- data/test/test-autofilter.rb +0 -72
- data/test/test-chart-bar.rb +0 -74
- /data/test/{test-errors.rb → test_errors.rb} +0 -0
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* Used in conjunction with the libxlsxwriter library.
|
5
5
|
*
|
6
|
-
* Copyright 2014-
|
6
|
+
* Copyright 2014-2020, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
7
7
|
*
|
8
8
|
*/
|
9
9
|
|
@@ -17,11 +17,15 @@ STATIC int _worksheet_name_cmp(lxw_worksheet_name *name1,
|
|
17
17
|
lxw_worksheet_name *name2);
|
18
18
|
STATIC int _chartsheet_name_cmp(lxw_chartsheet_name *name1,
|
19
19
|
lxw_chartsheet_name *name2);
|
20
|
+
STATIC int _image_md5_cmp(lxw_image_md5 *tuple1, lxw_image_md5 *tuple2);
|
21
|
+
|
20
22
|
#ifndef __clang_analyzer__
|
21
23
|
LXW_RB_GENERATE_WORKSHEET_NAMES(lxw_worksheet_names, lxw_worksheet_name,
|
22
24
|
tree_pointers, _worksheet_name_cmp);
|
23
25
|
LXW_RB_GENERATE_CHARTSHEET_NAMES(lxw_chartsheet_names, lxw_chartsheet_name,
|
24
26
|
tree_pointers, _chartsheet_name_cmp);
|
27
|
+
LXW_RB_GENERATE_IMAGE_MD5S(lxw_image_md5s, lxw_image_md5,
|
28
|
+
tree_pointers, _image_md5_cmp);
|
25
29
|
#endif
|
26
30
|
|
27
31
|
/*
|
@@ -49,6 +53,12 @@ _chartsheet_name_cmp(lxw_chartsheet_name *name1, lxw_chartsheet_name *name2)
|
|
49
53
|
return lxw_strcasecmp(name1->name, name2->name);
|
50
54
|
}
|
51
55
|
|
56
|
+
STATIC int
|
57
|
+
_image_md5_cmp(lxw_image_md5 *tuple1, lxw_image_md5 *tuple2)
|
58
|
+
{
|
59
|
+
return strcmp(tuple1->md5, tuple2->md5);
|
60
|
+
}
|
61
|
+
|
52
62
|
/*
|
53
63
|
* Free workbook properties.
|
54
64
|
*/
|
@@ -97,6 +107,8 @@ lxw_workbook_free(lxw_workbook *workbook)
|
|
97
107
|
struct lxw_worksheet_name *next_worksheet_name;
|
98
108
|
struct lxw_chartsheet_name *chartsheet_name;
|
99
109
|
struct lxw_chartsheet_name *next_chartsheet_name;
|
110
|
+
struct lxw_image_md5 *image_md5;
|
111
|
+
struct lxw_image_md5 *next_image_md5;
|
100
112
|
lxw_chart *chart;
|
101
113
|
lxw_format *format;
|
102
114
|
lxw_defined_name *defined_name;
|
@@ -204,7 +216,36 @@ lxw_workbook_free(lxw_workbook *workbook)
|
|
204
216
|
free(workbook->chartsheet_names);
|
205
217
|
}
|
206
218
|
|
219
|
+
if (workbook->image_md5s) {
|
220
|
+
for (image_md5 = RB_MIN(lxw_image_md5s, workbook->image_md5s);
|
221
|
+
image_md5; image_md5 = next_image_md5) {
|
222
|
+
|
223
|
+
next_image_md5 =
|
224
|
+
RB_NEXT(lxw_image_md5s, workbook->image_md5, image_md5);
|
225
|
+
RB_REMOVE(lxw_image_md5s, workbook->image_md5s, image_md5);
|
226
|
+
free(image_md5->md5);
|
227
|
+
free(image_md5);
|
228
|
+
}
|
229
|
+
|
230
|
+
free(workbook->image_md5s);
|
231
|
+
}
|
232
|
+
|
233
|
+
if (workbook->header_image_md5s) {
|
234
|
+
for (image_md5 = RB_MIN(lxw_image_md5s, workbook->header_image_md5s);
|
235
|
+
image_md5; image_md5 = next_image_md5) {
|
236
|
+
|
237
|
+
next_image_md5 =
|
238
|
+
RB_NEXT(lxw_image_md5s, workbook->image_md5, image_md5);
|
239
|
+
RB_REMOVE(lxw_image_md5s, workbook->header_image_md5s, image_md5);
|
240
|
+
free(image_md5->md5);
|
241
|
+
free(image_md5);
|
242
|
+
}
|
243
|
+
|
244
|
+
free(workbook->header_image_md5s);
|
245
|
+
}
|
246
|
+
|
207
247
|
lxw_hash_free(workbook->used_xf_formats);
|
248
|
+
lxw_hash_free(workbook->used_dxf_formats);
|
208
249
|
lxw_sst_free(workbook->sst);
|
209
250
|
free(workbook->options.tmpdir);
|
210
251
|
free(workbook->ordered_charts);
|
@@ -220,9 +261,15 @@ void
|
|
220
261
|
lxw_workbook_set_default_xf_indices(lxw_workbook *self)
|
221
262
|
{
|
222
263
|
lxw_format *format;
|
264
|
+
int32_t index = 0;
|
223
265
|
|
224
266
|
STAILQ_FOREACH(format, self->formats, list_pointers) {
|
225
|
-
|
267
|
+
|
268
|
+
/* Skip the hyperlink format. */
|
269
|
+
if (index != 1)
|
270
|
+
lxw_format_get_xf_index(format);
|
271
|
+
|
272
|
+
index++;
|
226
273
|
}
|
227
274
|
}
|
228
275
|
|
@@ -258,7 +305,7 @@ _prepare_fonts(lxw_workbook *self)
|
|
258
305
|
uint16_t *font_index = calloc(1, sizeof(uint16_t));
|
259
306
|
*font_index = index;
|
260
307
|
format->font_index = index;
|
261
|
-
format->has_font =
|
308
|
+
format->has_font = LXW_TRUE;
|
262
309
|
lxw_insert_hash_element(fonts, key, font_index,
|
263
310
|
sizeof(lxw_font));
|
264
311
|
index++;
|
@@ -268,6 +315,18 @@ _prepare_fonts(lxw_workbook *self)
|
|
268
315
|
|
269
316
|
lxw_hash_free(fonts);
|
270
317
|
|
318
|
+
/* For DXF formats we only need to check if the properties have changed. */
|
319
|
+
LXW_FOREACH_ORDERED(used_format_element, self->used_dxf_formats) {
|
320
|
+
lxw_format *format = (lxw_format *) used_format_element->value;
|
321
|
+
|
322
|
+
/* The only font properties that can change for a DXF format are:
|
323
|
+
* color, bold, italic, underline and strikethrough. */
|
324
|
+
if (format->font_color || format->bold || format->italic
|
325
|
+
|| format->underline || format->font_strikeout) {
|
326
|
+
format->has_dxf_font = LXW_TRUE;
|
327
|
+
}
|
328
|
+
}
|
329
|
+
|
271
330
|
self->font_count = index;
|
272
331
|
}
|
273
332
|
|
@@ -312,6 +371,15 @@ _prepare_borders(lxw_workbook *self)
|
|
312
371
|
}
|
313
372
|
}
|
314
373
|
|
374
|
+
/* For DXF formats we only need to check if the properties have changed. */
|
375
|
+
LXW_FOREACH_ORDERED(used_format_element, self->used_dxf_formats) {
|
376
|
+
lxw_format *format = (lxw_format *) used_format_element->value;
|
377
|
+
|
378
|
+
if (format->left || format->right || format->top || format->bottom) {
|
379
|
+
format->has_dxf_border = LXW_TRUE;
|
380
|
+
}
|
381
|
+
}
|
382
|
+
|
315
383
|
lxw_hash_free(borders);
|
316
384
|
|
317
385
|
self->border_count = index;
|
@@ -361,6 +429,17 @@ _prepare_fills(lxw_workbook *self)
|
|
361
429
|
lxw_insert_hash_element(fills, default_fill_2, fill_index2,
|
362
430
|
sizeof(lxw_fill));
|
363
431
|
|
432
|
+
/* For DXF formats we only need to check if the properties have changed. */
|
433
|
+
LXW_FOREACH_ORDERED(used_format_element, self->used_dxf_formats) {
|
434
|
+
lxw_format *format = (lxw_format *) used_format_element->value;
|
435
|
+
|
436
|
+
if (format->pattern || format->bg_color || format->fg_color) {
|
437
|
+
format->has_dxf_fill = LXW_TRUE;
|
438
|
+
format->dxf_bg_color = format->bg_color;
|
439
|
+
format->dxf_fg_color = format->fg_color;
|
440
|
+
}
|
441
|
+
}
|
442
|
+
|
364
443
|
LXW_FOREACH_ORDERED(used_format_element, self->used_xf_formats) {
|
365
444
|
lxw_format *format = (lxw_format *) used_format_element->value;
|
366
445
|
lxw_fill *key = lxw_format_get_fill_key(format);
|
@@ -482,6 +561,41 @@ _prepare_num_formats(lxw_workbook *self)
|
|
482
561
|
}
|
483
562
|
}
|
484
563
|
|
564
|
+
LXW_FOREACH_ORDERED(used_format_element, self->used_dxf_formats) {
|
565
|
+
lxw_format *format = (lxw_format *) used_format_element->value;
|
566
|
+
|
567
|
+
/* Format already has a number format index. */
|
568
|
+
if (format->num_format_index)
|
569
|
+
continue;
|
570
|
+
|
571
|
+
/* Check if there is a user defined number format string. */
|
572
|
+
if (*format->num_format) {
|
573
|
+
char num_format[LXW_FORMAT_FIELD_LEN] = { 0 };
|
574
|
+
lxw_snprintf(num_format, LXW_FORMAT_FIELD_LEN, "%s",
|
575
|
+
format->num_format);
|
576
|
+
|
577
|
+
/* Look up the num_format in the hash table. */
|
578
|
+
hash_element = lxw_hash_key_exists(num_formats, num_format,
|
579
|
+
LXW_FORMAT_FIELD_LEN);
|
580
|
+
|
581
|
+
if (hash_element) {
|
582
|
+
/* Num_Format has already been used. */
|
583
|
+
format->num_format_index = *(uint16_t *) hash_element->value;
|
584
|
+
}
|
585
|
+
else {
|
586
|
+
/* This is a new num_format. */
|
587
|
+
num_format_index = calloc(1, sizeof(uint16_t));
|
588
|
+
*num_format_index = index;
|
589
|
+
format->num_format_index = index;
|
590
|
+
lxw_insert_hash_element(num_formats, format->num_format,
|
591
|
+
num_format_index,
|
592
|
+
LXW_FORMAT_FIELD_LEN);
|
593
|
+
index++;
|
594
|
+
/* Don't update num_format_count for DXF formats. */
|
595
|
+
}
|
596
|
+
}
|
597
|
+
}
|
598
|
+
|
485
599
|
lxw_hash_free(num_formats);
|
486
600
|
|
487
601
|
self->num_format_count = num_format_count;
|
@@ -735,7 +849,7 @@ _populate_range_data_cache(lxw_workbook *self, lxw_series_range *range)
|
|
735
849
|
return;
|
736
850
|
}
|
737
851
|
|
738
|
-
cell_obj =
|
852
|
+
cell_obj = lxw_worksheet_find_cell_in_row(row_obj, col_num);
|
739
853
|
|
740
854
|
if (cell_obj) {
|
741
855
|
if (cell_obj->type == NUMBER_CELL) {
|
@@ -847,6 +961,9 @@ _populate_range_dimensions(lxw_workbook *self, lxw_series_range *range)
|
|
847
961
|
STATIC void
|
848
962
|
_populate_range(lxw_workbook *self, lxw_series_range *range)
|
849
963
|
{
|
964
|
+
if (!range)
|
965
|
+
return;
|
966
|
+
|
850
967
|
_populate_range_dimensions(self, range);
|
851
968
|
_populate_range_data_cache(self, range);
|
852
969
|
}
|
@@ -860,6 +977,7 @@ _add_chart_cache_data(lxw_workbook *self)
|
|
860
977
|
{
|
861
978
|
lxw_chart *chart;
|
862
979
|
lxw_chart_series *series;
|
980
|
+
uint16_t i;
|
863
981
|
|
864
982
|
STAILQ_FOREACH(chart, self->ordered_charts, ordered_list_pointers) {
|
865
983
|
|
@@ -874,6 +992,11 @@ _add_chart_cache_data(lxw_workbook *self)
|
|
874
992
|
_populate_range(self, series->categories);
|
875
993
|
_populate_range(self, series->values);
|
876
994
|
_populate_range(self, series->title.range);
|
995
|
+
|
996
|
+
for (i = 0; i < series->data_label_count; i++) {
|
997
|
+
lxw_chart_custom_label *data_label = &series->data_labels[i];
|
998
|
+
_populate_range(self, data_label->range);
|
999
|
+
}
|
877
1000
|
}
|
878
1001
|
}
|
879
1002
|
}
|
@@ -886,11 +1009,16 @@ _prepare_drawings(lxw_workbook *self)
|
|
886
1009
|
{
|
887
1010
|
lxw_sheet *sheet;
|
888
1011
|
lxw_worksheet *worksheet;
|
889
|
-
|
1012
|
+
lxw_object_properties *object_props;
|
890
1013
|
uint32_t chart_ref_id = 0;
|
891
1014
|
uint32_t image_ref_id = 0;
|
1015
|
+
uint32_t ref_id = 0;
|
892
1016
|
uint32_t drawing_id = 0;
|
893
1017
|
uint8_t is_chartsheet;
|
1018
|
+
lxw_image_md5 tmp_image_md5;
|
1019
|
+
lxw_image_md5 *new_image_md5 = NULL;
|
1020
|
+
lxw_image_md5 *found_duplicate_image = NULL;
|
1021
|
+
uint8_t i;
|
894
1022
|
|
895
1023
|
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
896
1024
|
if (sheet->is_chartsheet) {
|
@@ -902,42 +1030,178 @@ _prepare_drawings(lxw_workbook *self)
|
|
902
1030
|
is_chartsheet = LXW_FALSE;
|
903
1031
|
}
|
904
1032
|
|
905
|
-
if (STAILQ_EMPTY(worksheet->
|
906
|
-
&& STAILQ_EMPTY(worksheet->chart_data)
|
1033
|
+
if (STAILQ_EMPTY(worksheet->image_props)
|
1034
|
+
&& STAILQ_EMPTY(worksheet->chart_data)
|
1035
|
+
&& !worksheet->has_header_vml) {
|
907
1036
|
continue;
|
1037
|
+
}
|
908
1038
|
|
909
1039
|
drawing_id++;
|
910
1040
|
|
911
|
-
|
1041
|
+
/* Prepare worksheet images. */
|
1042
|
+
STAILQ_FOREACH(object_props, worksheet->image_props, list_pointers) {
|
1043
|
+
|
1044
|
+
if (object_props->image_type == LXW_IMAGE_PNG)
|
1045
|
+
self->has_png = LXW_TRUE;
|
1046
|
+
|
1047
|
+
if (object_props->image_type == LXW_IMAGE_JPEG)
|
1048
|
+
self->has_jpeg = LXW_TRUE;
|
1049
|
+
|
1050
|
+
if (object_props->image_type == LXW_IMAGE_BMP)
|
1051
|
+
self->has_bmp = LXW_TRUE;
|
1052
|
+
|
1053
|
+
/* Check for duplicate images and only store the first instance. */
|
1054
|
+
if (object_props->md5) {
|
1055
|
+
tmp_image_md5.md5 = object_props->md5;
|
1056
|
+
found_duplicate_image = RB_FIND(lxw_image_md5s,
|
1057
|
+
self->image_md5s,
|
1058
|
+
&tmp_image_md5);
|
1059
|
+
}
|
1060
|
+
|
1061
|
+
if (found_duplicate_image) {
|
1062
|
+
ref_id = found_duplicate_image->id;
|
1063
|
+
object_props->is_duplicate = LXW_TRUE;
|
1064
|
+
}
|
1065
|
+
else {
|
1066
|
+
image_ref_id++;
|
1067
|
+
ref_id = image_ref_id;
|
1068
|
+
|
1069
|
+
#ifndef USE_NO_MD5
|
1070
|
+
new_image_md5 = calloc(1, sizeof(lxw_image_md5));
|
1071
|
+
#endif
|
1072
|
+
if (new_image_md5 && object_props->md5) {
|
1073
|
+
new_image_md5->id = ref_id;
|
1074
|
+
new_image_md5->md5 = lxw_strdup(object_props->md5);
|
1075
|
+
|
1076
|
+
RB_INSERT(lxw_image_md5s, self->image_md5s,
|
1077
|
+
new_image_md5);
|
1078
|
+
}
|
1079
|
+
}
|
1080
|
+
|
1081
|
+
lxw_worksheet_prepare_image(worksheet, ref_id, drawing_id,
|
1082
|
+
object_props);
|
1083
|
+
}
|
1084
|
+
|
1085
|
+
/* Prepare worksheet charts. */
|
1086
|
+
STAILQ_FOREACH(object_props, worksheet->chart_data, list_pointers) {
|
912
1087
|
chart_ref_id++;
|
913
1088
|
lxw_worksheet_prepare_chart(worksheet, chart_ref_id, drawing_id,
|
914
|
-
|
915
|
-
if (
|
916
|
-
STAILQ_INSERT_TAIL(self->ordered_charts,
|
1089
|
+
object_props, is_chartsheet);
|
1090
|
+
if (object_props->chart)
|
1091
|
+
STAILQ_INSERT_TAIL(self->ordered_charts, object_props->chart,
|
917
1092
|
ordered_list_pointers);
|
918
1093
|
}
|
919
1094
|
|
920
|
-
|
1095
|
+
/* Prepare worksheet header/footer images. */
|
1096
|
+
for (i = 0; i < LXW_HEADER_FOOTER_OBJS_MAX; i++) {
|
1097
|
+
|
1098
|
+
object_props = *worksheet->header_footer_objs[i];
|
1099
|
+
if (!object_props)
|
1100
|
+
continue;
|
921
1101
|
|
922
|
-
if (
|
1102
|
+
if (object_props->image_type == LXW_IMAGE_PNG)
|
923
1103
|
self->has_png = LXW_TRUE;
|
924
1104
|
|
925
|
-
if (
|
1105
|
+
if (object_props->image_type == LXW_IMAGE_JPEG)
|
926
1106
|
self->has_jpeg = LXW_TRUE;
|
927
1107
|
|
928
|
-
if (
|
1108
|
+
if (object_props->image_type == LXW_IMAGE_BMP)
|
929
1109
|
self->has_bmp = LXW_TRUE;
|
930
1110
|
|
931
|
-
|
1111
|
+
/* Check for duplicate images and only store the first instance. */
|
1112
|
+
if (object_props->md5) {
|
1113
|
+
tmp_image_md5.md5 = object_props->md5;
|
1114
|
+
found_duplicate_image = RB_FIND(lxw_image_md5s,
|
1115
|
+
self->header_image_md5s,
|
1116
|
+
&tmp_image_md5);
|
1117
|
+
}
|
1118
|
+
|
1119
|
+
if (found_duplicate_image) {
|
1120
|
+
ref_id = found_duplicate_image->id;
|
1121
|
+
object_props->is_duplicate = LXW_TRUE;
|
1122
|
+
}
|
1123
|
+
else {
|
1124
|
+
image_ref_id++;
|
1125
|
+
ref_id = image_ref_id;
|
1126
|
+
|
1127
|
+
#ifndef USE_NO_MD5
|
1128
|
+
new_image_md5 = calloc(1, sizeof(lxw_image_md5));
|
1129
|
+
#endif
|
1130
|
+
if (new_image_md5 && object_props->md5) {
|
1131
|
+
new_image_md5->id = ref_id;
|
1132
|
+
new_image_md5->md5 = lxw_strdup(object_props->md5);
|
1133
|
+
|
1134
|
+
RB_INSERT(lxw_image_md5s, self->header_image_md5s,
|
1135
|
+
new_image_md5);
|
1136
|
+
}
|
1137
|
+
}
|
932
1138
|
|
933
|
-
|
934
|
-
|
1139
|
+
lxw_worksheet_prepare_header_image(worksheet, ref_id,
|
1140
|
+
object_props);
|
935
1141
|
}
|
1142
|
+
|
936
1143
|
}
|
937
1144
|
|
938
1145
|
self->drawing_count = drawing_id;
|
939
1146
|
}
|
940
1147
|
|
1148
|
+
/*
|
1149
|
+
* Iterate through the worksheets and set up the VML objects.
|
1150
|
+
*/
|
1151
|
+
|
1152
|
+
STATIC void
|
1153
|
+
_prepare_vml(lxw_workbook *self)
|
1154
|
+
{
|
1155
|
+
lxw_worksheet *worksheet;
|
1156
|
+
lxw_sheet *sheet;
|
1157
|
+
uint32_t comment_id = 0;
|
1158
|
+
uint32_t vml_drawing_id = 0;
|
1159
|
+
uint32_t vml_data_id = 1;
|
1160
|
+
uint32_t vml_header_id = 0;
|
1161
|
+
uint32_t vml_shape_id = 1024;
|
1162
|
+
uint32_t comment_count = 0;
|
1163
|
+
|
1164
|
+
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
1165
|
+
if (sheet->is_chartsheet)
|
1166
|
+
continue;
|
1167
|
+
else
|
1168
|
+
worksheet = sheet->u.worksheet;
|
1169
|
+
|
1170
|
+
if (!worksheet->has_vml && !worksheet->has_header_vml)
|
1171
|
+
continue;
|
1172
|
+
|
1173
|
+
if (worksheet->has_vml) {
|
1174
|
+
self->has_vml = LXW_TRUE;
|
1175
|
+
if (worksheet->has_comments) {
|
1176
|
+
self->comment_count++;
|
1177
|
+
comment_id++;
|
1178
|
+
self->has_comments = LXW_TRUE;
|
1179
|
+
}
|
1180
|
+
|
1181
|
+
vml_drawing_id++;
|
1182
|
+
|
1183
|
+
comment_count = lxw_worksheet_prepare_vml_objects(worksheet,
|
1184
|
+
vml_data_id,
|
1185
|
+
vml_shape_id,
|
1186
|
+
vml_drawing_id,
|
1187
|
+
comment_id);
|
1188
|
+
|
1189
|
+
/* Each VML should start with a shape id incremented by 1024. */
|
1190
|
+
vml_data_id += 1 * ((1024 + comment_count) / 1024);
|
1191
|
+
vml_shape_id += 1024 * ((1024 + comment_count) / 1024);
|
1192
|
+
}
|
1193
|
+
|
1194
|
+
if (worksheet->has_header_vml) {
|
1195
|
+
self->has_vml = LXW_TRUE;
|
1196
|
+
vml_drawing_id++;
|
1197
|
+
vml_header_id++;
|
1198
|
+
lxw_worksheet_prepare_header_vml_objects(worksheet,
|
1199
|
+
vml_header_id,
|
1200
|
+
vml_drawing_id);
|
1201
|
+
}
|
1202
|
+
}
|
1203
|
+
}
|
1204
|
+
|
941
1205
|
/*
|
942
1206
|
* Iterate through the worksheets and store any defined names used for print
|
943
1207
|
* ranges or repeat rows/columns.
|
@@ -1432,6 +1696,16 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
|
1432
1696
|
GOTO_LABEL_ON_MEM_ERROR(workbook->chartsheet_names, mem_error);
|
1433
1697
|
RB_INIT(workbook->chartsheet_names);
|
1434
1698
|
|
1699
|
+
/* Add the image MD5 tree. */
|
1700
|
+
workbook->image_md5s = calloc(1, sizeof(struct lxw_image_md5s));
|
1701
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->image_md5s, mem_error);
|
1702
|
+
RB_INIT(workbook->image_md5s);
|
1703
|
+
|
1704
|
+
/* Add the image MD5 tree. */
|
1705
|
+
workbook->header_image_md5s = calloc(1, sizeof(struct lxw_image_md5s));
|
1706
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->header_image_md5s, mem_error);
|
1707
|
+
RB_INIT(workbook->header_image_md5s);
|
1708
|
+
|
1435
1709
|
/* Add the charts list. */
|
1436
1710
|
workbook->charts = calloc(1, sizeof(struct lxw_charts));
|
1437
1711
|
GOTO_LABEL_ON_MEM_ERROR(workbook->charts, mem_error);
|
@@ -1464,6 +1738,10 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
|
1464
1738
|
workbook->used_xf_formats = lxw_hash_new(128, 1, 0);
|
1465
1739
|
GOTO_LABEL_ON_MEM_ERROR(workbook->used_xf_formats, mem_error);
|
1466
1740
|
|
1741
|
+
/* Add a hash table to track format indices. */
|
1742
|
+
workbook->used_dxf_formats = lxw_hash_new(128, 1, 0);
|
1743
|
+
GOTO_LABEL_ON_MEM_ERROR(workbook->used_dxf_formats, mem_error);
|
1744
|
+
|
1467
1745
|
/* Add the worksheets list. */
|
1468
1746
|
workbook->custom_properties =
|
1469
1747
|
calloc(1, sizeof(struct lxw_custom_properties));
|
@@ -1477,12 +1755,20 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
|
1477
1755
|
/* Initialize its index. */
|
1478
1756
|
lxw_format_get_xf_index(format);
|
1479
1757
|
|
1758
|
+
/* Add the default hyperlink format. */
|
1759
|
+
format = workbook_add_format(workbook);
|
1760
|
+
GOTO_LABEL_ON_MEM_ERROR(format, mem_error);
|
1761
|
+
format_set_hyperlink(format);
|
1762
|
+
workbook->default_url_format = format;
|
1763
|
+
|
1480
1764
|
if (options) {
|
1481
1765
|
workbook->options.constant_memory = options->constant_memory;
|
1482
1766
|
workbook->options.tmpdir = lxw_strdup(options->tmpdir);
|
1483
1767
|
workbook->options.use_zip64 = options->use_zip64;
|
1484
1768
|
}
|
1485
1769
|
|
1770
|
+
workbook->max_url_length = 2079;
|
1771
|
+
|
1486
1772
|
return workbook;
|
1487
1773
|
|
1488
1774
|
mem_error:
|
@@ -1501,7 +1787,7 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
|
1501
1787
|
lxw_worksheet *worksheet = NULL;
|
1502
1788
|
lxw_worksheet_name *worksheet_name = NULL;
|
1503
1789
|
lxw_error error;
|
1504
|
-
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
1790
|
+
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
1505
1791
|
char *new_name = NULL;
|
1506
1792
|
|
1507
1793
|
if (sheetname) {
|
@@ -1540,6 +1826,8 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
|
|
1540
1826
|
init_data.active_sheet = &self->active_sheet;
|
1541
1827
|
init_data.first_sheet = &self->first_sheet;
|
1542
1828
|
init_data.tmpdir = self->options.tmpdir;
|
1829
|
+
init_data.default_url_format = self->default_url_format;
|
1830
|
+
init_data.max_url_length = self->max_url_length;
|
1543
1831
|
|
1544
1832
|
/* Create a new worksheet object. */
|
1545
1833
|
worksheet = lxw_worksheet_new(&init_data);
|
@@ -1583,7 +1871,7 @@ workbook_add_chartsheet(lxw_workbook *self, const char *sheetname)
|
|
1583
1871
|
lxw_chartsheet *chartsheet = NULL;
|
1584
1872
|
lxw_chartsheet_name *chartsheet_name = NULL;
|
1585
1873
|
lxw_error error;
|
1586
|
-
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
1874
|
+
lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
1587
1875
|
char *new_name = NULL;
|
1588
1876
|
|
1589
1877
|
if (sheetname) {
|
@@ -1685,6 +1973,7 @@ workbook_add_format(lxw_workbook *self)
|
|
1685
1973
|
RETURN_ON_MEM_ERROR(format, NULL);
|
1686
1974
|
|
1687
1975
|
format->xf_format_indices = self->used_xf_formats;
|
1976
|
+
format->dxf_format_indices = self->used_dxf_formats;
|
1688
1977
|
format->num_xf_formats = &self->num_xf_formats;
|
1689
1978
|
|
1690
1979
|
STAILQ_INSERT_TAIL(self->formats, format, list_pointers);
|
@@ -1702,6 +1991,7 @@ workbook_close(lxw_workbook *self)
|
|
1702
1991
|
lxw_worksheet *worksheet = NULL;
|
1703
1992
|
lxw_packager *packager = NULL;
|
1704
1993
|
lxw_error error = LXW_NO_ERROR;
|
1994
|
+
char codename[LXW_MAX_SHEETNAME_LENGTH] = { 0 };
|
1705
1995
|
|
1706
1996
|
/* Add a default worksheet if non have been added. */
|
1707
1997
|
if (!self->num_sheets)
|
@@ -1739,11 +2029,18 @@ workbook_close(lxw_workbook *self)
|
|
1739
2029
|
else
|
1740
2030
|
worksheet = sheet->u.worksheet;
|
1741
2031
|
|
1742
|
-
if (!worksheet->vba_codename)
|
1743
|
-
|
2032
|
+
if (!worksheet->vba_codename) {
|
2033
|
+
lxw_snprintf(codename, LXW_MAX_SHEETNAME_LENGTH, "Sheet%d",
|
2034
|
+
worksheet->index + 1);
|
2035
|
+
|
2036
|
+
worksheet_set_vba_name(worksheet, codename);
|
2037
|
+
}
|
1744
2038
|
}
|
1745
2039
|
}
|
1746
2040
|
|
2041
|
+
/* Prepare the worksheet VML elements such as comments. */
|
2042
|
+
_prepare_vml(self);
|
2043
|
+
|
1747
2044
|
/* Set the defined names for the worksheets such as Print Titles. */
|
1748
2045
|
_prepare_defined_names(self);
|
1749
2046
|
|
@@ -1903,6 +2200,8 @@ workbook_set_properties(lxw_workbook *self, lxw_doc_properties *user_props)
|
|
1903
2200
|
GOTO_LABEL_ON_MEM_ERROR(doc_props->hyperlink_base, mem_error);
|
1904
2201
|
}
|
1905
2202
|
|
2203
|
+
doc_props->created = user_props->created;
|
2204
|
+
|
1906
2205
|
self->properties = doc_props;
|
1907
2206
|
|
1908
2207
|
return LXW_NO_ERROR;
|
@@ -2150,6 +2449,27 @@ workbook_get_chartsheet_by_name(lxw_workbook *self, const char *name)
|
|
2150
2449
|
return NULL;
|
2151
2450
|
}
|
2152
2451
|
|
2452
|
+
/*
|
2453
|
+
* Get the default URL format.
|
2454
|
+
*/
|
2455
|
+
lxw_format *
|
2456
|
+
workbook_get_default_url_format(lxw_workbook *self)
|
2457
|
+
{
|
2458
|
+
return self->default_url_format;
|
2459
|
+
}
|
2460
|
+
|
2461
|
+
/*
|
2462
|
+
* Unset the default URL format.
|
2463
|
+
*/
|
2464
|
+
void
|
2465
|
+
workbook_unset_default_url_format(lxw_workbook *self)
|
2466
|
+
{
|
2467
|
+
self->default_url_format->hyperlink = LXW_FALSE;
|
2468
|
+
self->default_url_format->xf_id = 0;
|
2469
|
+
self->default_url_format->underline = LXW_UNDERLINE_NONE;
|
2470
|
+
self->default_url_format->theme = 0;
|
2471
|
+
}
|
2472
|
+
|
2153
2473
|
/*
|
2154
2474
|
* Validate the worksheet name based on Excel's rules.
|
2155
2475
|
*/
|
@@ -2168,10 +2488,6 @@ workbook_validate_sheet_name(lxw_workbook *self, const char *sheetname)
|
|
2168
2488
|
if (sheetname[0] == '\'' || sheetname[strlen(sheetname) - 1] == '\'')
|
2169
2489
|
return LXW_ERROR_SHEETNAME_START_END_APOSTROPHE;
|
2170
2490
|
|
2171
|
-
/* Check that the worksheet name isn't the reserved work "History". */
|
2172
|
-
if (lxw_strcasecmp(sheetname, "history") == 0)
|
2173
|
-
return LXW_ERROR_SHEETNAME_RESERVED;
|
2174
|
-
|
2175
2491
|
/* Check if the worksheet name is already in use. */
|
2176
2492
|
if (workbook_get_worksheet_by_name(self, sheetname))
|
2177
2493
|
return LXW_ERROR_SHEETNAME_ALREADY_USED;
|
@@ -2198,7 +2514,7 @@ workbook_add_vba_project(lxw_workbook *self, const char *filename)
|
|
2198
2514
|
}
|
2199
2515
|
|
2200
2516
|
/* Check that the vbaProject file exists and can be opened. */
|
2201
|
-
filehandle =
|
2517
|
+
filehandle = lxw_fopen(filename, "rb");
|
2202
2518
|
if (!filehandle) {
|
2203
2519
|
LXW_WARN_FORMAT1("workbook_add_vba_project(): "
|
2204
2520
|
"file doesn't exist or can't be opened: %s.",
|