fast_excel 0.2.6 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.dockerignore +2 -0
- data/.gitignore +3 -0
- data/.travis.yml +18 -6
- data/CHANGELOG.md +14 -1
- data/Dockerfile.test +16 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +21 -21
- data/Makefile +13 -2
- data/README.md +148 -38
- data/Rakefile +2 -0
- data/examples/example.rb +3 -3
- data/examples/example_filters.rb +36 -0
- data/examples/example_formula.rb +1 -3
- data/examples/example_hyperlink.rb +20 -0
- data/fast_excel.gemspec +1 -1
- data/lib/fast_excel.rb +36 -12
- data/lib/fast_excel/binding.rb +31 -21
- data/lib/fast_excel/binding/chart.rb +20 -1
- 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 +5 -0
- data/libxlsxwriter/CMakeLists.txt +1 -11
- data/libxlsxwriter/CONTRIBUTING.md +1 -1
- data/libxlsxwriter/Changes.txt +84 -0
- data/libxlsxwriter/LICENSE.txt +1 -1
- data/libxlsxwriter/Makefile +7 -5
- data/libxlsxwriter/Readme.md +1 -1
- data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +1 -0
- data/libxlsxwriter/include/xlsxwriter.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/app.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/chart.h +56 -6
- data/libxlsxwriter/include/xlsxwriter/chartsheet.h +544 -0
- data/libxlsxwriter/include/xlsxwriter/common.h +27 -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 +3 -3
- data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
- data/libxlsxwriter/include/xlsxwriter/packager.h +13 -8
- data/libxlsxwriter/include/xlsxwriter/relationships.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/shared_strings.h +5 -3
- data/libxlsxwriter/include/xlsxwriter/styles.h +9 -4
- data/libxlsxwriter/include/xlsxwriter/theme.h +2 -2
- data/libxlsxwriter/include/xlsxwriter/utility.h +26 -2
- data/libxlsxwriter/include/xlsxwriter/workbook.h +232 -55
- data/libxlsxwriter/include/xlsxwriter/worksheet.h +264 -53
- data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +3 -1
- data/libxlsxwriter/libxlsxwriter.podspec +1 -1
- data/libxlsxwriter/src/Makefile +3 -3
- data/libxlsxwriter/src/app.c +2 -2
- data/libxlsxwriter/src/chart.c +41 -5
- data/libxlsxwriter/src/chartsheet.c +508 -0
- data/libxlsxwriter/src/content_types.c +12 -4
- data/libxlsxwriter/src/core.c +2 -2
- data/libxlsxwriter/src/custom.c +2 -2
- data/libxlsxwriter/src/drawing.c +114 -17
- data/libxlsxwriter/src/format.c +3 -3
- data/libxlsxwriter/src/hash_table.c +1 -1
- data/libxlsxwriter/src/packager.c +369 -65
- data/libxlsxwriter/src/relationships.c +2 -2
- data/libxlsxwriter/src/shared_strings.c +18 -4
- data/libxlsxwriter/src/styles.c +56 -9
- data/libxlsxwriter/src/theme.c +2 -2
- data/libxlsxwriter/src/utility.c +53 -6
- data/libxlsxwriter/src/workbook.c +372 -56
- data/libxlsxwriter/src/worksheet.c +425 -76
- data/libxlsxwriter/src/xmlwriter.c +17 -8
- 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/tmpfile_test.rb +1 -0
- data/test/validations_test.rb +26 -6
- data/test/worksheet_test.rb +43 -0
- metadata +9 -6
- data/libxlsxwriter/.drone.yml +0 -27
- data/libxlsxwriter/appveyor.yml +0 -65
- data/libxlsxwriter/cmake/FindZLIB.cmake +0 -123
@@ -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
|
|
@@ -17,8 +17,6 @@
|
|
17
17
|
|
18
18
|
#define LXW_STR_MAX 32767
|
19
19
|
#define LXW_BUFFER_SIZE 4096
|
20
|
-
#define LXW_PORTRAIT 1
|
21
|
-
#define LXW_LANDSCAPE 0
|
22
20
|
#define LXW_PRINT_ACROSS 1
|
23
21
|
#define LXW_VALIDATION_MAX_TITLE_LENGTH 32
|
24
22
|
#define LXW_VALIDATION_MAX_STRING_LENGTH 255
|
@@ -271,10 +269,11 @@ _free_image_options(lxw_image_options *image)
|
|
271
269
|
return;
|
272
270
|
|
273
271
|
free(image->filename);
|
274
|
-
free(image->
|
272
|
+
free(image->description);
|
275
273
|
free(image->extension);
|
276
274
|
free(image->url);
|
277
275
|
free(image->tip);
|
276
|
+
free(image->image_buffer);
|
278
277
|
free(image);
|
279
278
|
}
|
280
279
|
|
@@ -449,6 +448,7 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|
449
448
|
free(worksheet->vbreaks);
|
450
449
|
free(worksheet->name);
|
451
450
|
free(worksheet->quoted_name);
|
451
|
+
free(worksheet->vba_codename);
|
452
452
|
|
453
453
|
free(worksheet);
|
454
454
|
worksheet = NULL;
|
@@ -538,6 +538,26 @@ _new_inline_string_cell(lxw_row_t row_num,
|
|
538
538
|
return cell;
|
539
539
|
}
|
540
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
|
+
|
541
561
|
/*
|
542
562
|
* Create a new worksheet formula cell object.
|
543
563
|
*/
|
@@ -841,38 +861,6 @@ _cell_cmp(lxw_cell *cell1, lxw_cell *cell2)
|
|
841
861
|
return 0;
|
842
862
|
}
|
843
863
|
|
844
|
-
/*
|
845
|
-
* Hash a worksheet password. Based on the algorithm provided by Daniel Rentz
|
846
|
-
* of OpenOffice.
|
847
|
-
*/
|
848
|
-
STATIC uint16_t
|
849
|
-
_hash_password(const char *password)
|
850
|
-
{
|
851
|
-
size_t count;
|
852
|
-
uint8_t i;
|
853
|
-
uint16_t hash = 0x0000;
|
854
|
-
|
855
|
-
count = strlen(password);
|
856
|
-
|
857
|
-
for (i = 0; i < count; i++) {
|
858
|
-
uint32_t low_15;
|
859
|
-
uint32_t high_15;
|
860
|
-
uint32_t letter = password[i] << (i + 1);
|
861
|
-
|
862
|
-
low_15 = letter & 0x7fff;
|
863
|
-
high_15 = letter & (0x7fff << 15);
|
864
|
-
high_15 = high_15 >> 15;
|
865
|
-
letter = low_15 | high_15;
|
866
|
-
|
867
|
-
hash ^= letter;
|
868
|
-
}
|
869
|
-
|
870
|
-
hash ^= count;
|
871
|
-
hash ^= 0xCE4B;
|
872
|
-
|
873
|
-
return hash;
|
874
|
-
}
|
875
|
-
|
876
864
|
/*
|
877
865
|
* Simple replacement for libgen.h basename() for compatibility with MSVC. It
|
878
866
|
* handles forward and back slashes. It doesn't copy exactly the return
|
@@ -1753,6 +1741,9 @@ _worksheet_size_col(lxw_worksheet *self, lxw_col_t col_num)
|
|
1753
1741
|
}
|
1754
1742
|
|
1755
1743
|
if (col_opt) {
|
1744
|
+
if (col_opt->hidden)
|
1745
|
+
return 0;
|
1746
|
+
|
1756
1747
|
width = col_opt->width;
|
1757
1748
|
|
1758
1749
|
/* Convert to pixels. */
|
@@ -1788,6 +1779,9 @@ _worksheet_size_row(lxw_worksheet *self, lxw_row_t row_num)
|
|
1788
1779
|
row = lxw_worksheet_find_row(self, row_num);
|
1789
1780
|
|
1790
1781
|
if (row) {
|
1782
|
+
if (row->hidden)
|
1783
|
+
return 0;
|
1784
|
+
|
1791
1785
|
height = row->height;
|
1792
1786
|
|
1793
1787
|
if (height == 0)
|
@@ -1914,23 +1908,30 @@ _worksheet_position_object_pixels(lxw_worksheet *self,
|
|
1914
1908
|
y_abs += y1;
|
1915
1909
|
|
1916
1910
|
/* Adjust start col for offsets that are greater than the col width. */
|
1917
|
-
|
1918
|
-
x1
|
1919
|
-
|
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
|
+
}
|
1920
1916
|
}
|
1921
1917
|
|
1922
1918
|
/* Adjust start row for offsets that are greater than the row height. */
|
1923
|
-
|
1924
|
-
y1
|
1925
|
-
|
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
|
+
}
|
1926
1924
|
}
|
1927
1925
|
|
1928
1926
|
/* Initialize end cell to the same as the start cell. */
|
1929
1927
|
col_end = col_start;
|
1930
1928
|
row_end = row_start;
|
1931
1929
|
|
1932
|
-
|
1933
|
-
|
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;
|
1934
1935
|
|
1935
1936
|
/* Subtract the underlying cell widths to find the end cell. */
|
1936
1937
|
while (width >= _worksheet_size_col(self, col_end)) {
|
@@ -1992,7 +1993,7 @@ _worksheet_position_object_emus(lxw_worksheet *self,
|
|
1992
1993
|
*/
|
1993
1994
|
void
|
1994
1995
|
lxw_worksheet_prepare_image(lxw_worksheet *self,
|
1995
|
-
|
1996
|
+
uint32_t image_ref_id, uint32_t drawing_id,
|
1996
1997
|
lxw_image_options *image_data)
|
1997
1998
|
{
|
1998
1999
|
lxw_drawing_object *drawing_object;
|
@@ -2027,7 +2028,7 @@ lxw_worksheet_prepare_image(lxw_worksheet *self,
|
|
2027
2028
|
|
2028
2029
|
drawing_object->anchor_type = LXW_ANCHOR_TYPE_IMAGE;
|
2029
2030
|
drawing_object->edit_as = LXW_ANCHOR_EDIT_AS_ONE_CELL;
|
2030
|
-
drawing_object->description = lxw_strdup(image_data->
|
2031
|
+
drawing_object->description = lxw_strdup(image_data->description);
|
2031
2032
|
|
2032
2033
|
/* Scale to user scale. */
|
2033
2034
|
width = image_data->width * image_data->x_scale;
|
@@ -2079,8 +2080,10 @@ mem_error:
|
|
2079
2080
|
*/
|
2080
2081
|
void
|
2081
2082
|
lxw_worksheet_prepare_chart(lxw_worksheet *self,
|
2082
|
-
|
2083
|
-
|
2083
|
+
uint32_t chart_ref_id,
|
2084
|
+
uint32_t drawing_id,
|
2085
|
+
lxw_image_options *image_data,
|
2086
|
+
uint8_t is_chartsheet)
|
2084
2087
|
{
|
2085
2088
|
lxw_drawing_object *drawing_object;
|
2086
2089
|
lxw_rel_tuple *relationship;
|
@@ -2090,9 +2093,16 @@ lxw_worksheet_prepare_chart(lxw_worksheet *self,
|
|
2090
2093
|
|
2091
2094
|
if (!self->drawing) {
|
2092
2095
|
self->drawing = lxw_drawing_new();
|
2093
|
-
self->drawing->embedded = LXW_TRUE;
|
2094
2096
|
RETURN_VOID_ON_MEM_ERROR(self->drawing);
|
2095
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
|
+
|
2096
2106
|
relationship = calloc(1, sizeof(lxw_rel_tuple));
|
2097
2107
|
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
|
2098
2108
|
|
@@ -2259,8 +2269,7 @@ _process_png(lxw_image_options *image_options)
|
|
2259
2269
|
|
2260
2270
|
file_error:
|
2261
2271
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
2262
|
-
"no size data found in
|
2263
|
-
image_options->filename);
|
2272
|
+
"no size data found in: %s.", image_options->filename);
|
2264
2273
|
|
2265
2274
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2266
2275
|
}
|
@@ -2386,8 +2395,7 @@ _process_jpeg(lxw_image_options *image_options)
|
|
2386
2395
|
|
2387
2396
|
file_error:
|
2388
2397
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
2389
|
-
"no size data found in
|
2390
|
-
image_options->filename);
|
2398
|
+
"no size data found in: %s.", image_options->filename);
|
2391
2399
|
|
2392
2400
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2393
2401
|
}
|
@@ -2436,8 +2444,7 @@ _process_bmp(lxw_image_options *image_options)
|
|
2436
2444
|
|
2437
2445
|
file_error:
|
2438
2446
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
2439
|
-
"no size data found in
|
2440
|
-
image_options->filename);
|
2447
|
+
"no size data found in: %s.", image_options->filename);
|
2441
2448
|
|
2442
2449
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2443
2450
|
}
|
@@ -2454,7 +2461,7 @@ _get_image_properties(lxw_image_options *image_options)
|
|
2454
2461
|
/* Read 4 bytes to look for the file header/signature. */
|
2455
2462
|
if (fread(signature, 1, 4, image_options->stream) < 4) {
|
2456
2463
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
2457
|
-
"couldn't read
|
2464
|
+
"couldn't read image type for: %s.",
|
2458
2465
|
image_options->filename);
|
2459
2466
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2460
2467
|
}
|
@@ -2473,7 +2480,7 @@ _get_image_properties(lxw_image_options *image_options)
|
|
2473
2480
|
}
|
2474
2481
|
else {
|
2475
2482
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
2476
|
-
"unsupported image format for
|
2483
|
+
"unsupported image format for: %s.",
|
2477
2484
|
image_options->filename);
|
2478
2485
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
2479
2486
|
}
|
@@ -2576,6 +2583,41 @@ _write_inline_string_cell(lxw_worksheet *self, char *range,
|
|
2576
2583
|
free(string);
|
2577
2584
|
}
|
2578
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
|
+
|
2579
2621
|
/*
|
2580
2622
|
* Write out a formula worksheet cell with a numeric result.
|
2581
2623
|
*/
|
@@ -2712,6 +2754,11 @@ _write_cell(lxw_worksheet *self, lxw_cell *cell, lxw_format *row_format)
|
|
2712
2754
|
return;
|
2713
2755
|
}
|
2714
2756
|
|
2757
|
+
if (cell->type == INLINE_RICH_STRING_CELL) {
|
2758
|
+
_write_inline_rich_string_cell(self, range, style_index, cell);
|
2759
|
+
return;
|
2760
|
+
}
|
2761
|
+
|
2715
2762
|
/* For other cell types use the general functions. */
|
2716
2763
|
LXW_INIT_ATTRIBUTES();
|
2717
2764
|
LXW_PUSH_ATTRIBUTES_STR("r", range);
|
@@ -3093,14 +3140,15 @@ _worksheet_write_sheet_pr(lxw_worksheet *self)
|
|
3093
3140
|
if (!self->fit_page
|
3094
3141
|
&& !self->filter_on
|
3095
3142
|
&& self->tab_color == LXW_COLOR_UNSET
|
3096
|
-
&& !self->outline_changed
|
3143
|
+
&& !self->outline_changed
|
3144
|
+
&& !self->vba_codename && !self->is_chartsheet) {
|
3097
3145
|
return;
|
3098
3146
|
}
|
3099
3147
|
|
3100
3148
|
LXW_INIT_ATTRIBUTES();
|
3101
3149
|
|
3102
3150
|
if (self->vba_codename)
|
3103
|
-
|
3151
|
+
LXW_PUSH_ATTRIBUTES_STR("codeName", self->vba_codename);
|
3104
3152
|
|
3105
3153
|
if (self->filter_on)
|
3106
3154
|
LXW_PUSH_ATTRIBUTES_STR("filterMode", "1");
|
@@ -3364,13 +3412,12 @@ mem_error:
|
|
3364
3412
|
* Write the <sheetProtection> element.
|
3365
3413
|
*/
|
3366
3414
|
STATIC void
|
3367
|
-
_worksheet_write_sheet_protection(lxw_worksheet *self
|
3415
|
+
_worksheet_write_sheet_protection(lxw_worksheet *self,
|
3416
|
+
lxw_protection *protect)
|
3368
3417
|
{
|
3369
3418
|
struct xml_attribute_list attributes;
|
3370
3419
|
struct xml_attribute *attribute;
|
3371
3420
|
|
3372
|
-
struct lxw_protection *protect = &self->protection;
|
3373
|
-
|
3374
3421
|
if (!protect->is_configured)
|
3375
3422
|
return;
|
3376
3423
|
|
@@ -3382,7 +3429,7 @@ _worksheet_write_sheet_protection(lxw_worksheet *self)
|
|
3382
3429
|
if (!protect->no_sheet)
|
3383
3430
|
LXW_PUSH_ATTRIBUTES_INT("sheet", 1);
|
3384
3431
|
|
3385
|
-
if (protect->
|
3432
|
+
if (!protect->no_content)
|
3386
3433
|
LXW_PUSH_ATTRIBUTES_INT("content", 1);
|
3387
3434
|
|
3388
3435
|
if (!protect->objects)
|
@@ -3439,7 +3486,7 @@ _worksheet_write_sheet_protection(lxw_worksheet *self)
|
|
3439
3486
|
* Write the <drawing> element.
|
3440
3487
|
*/
|
3441
3488
|
STATIC void
|
3442
|
-
|
3489
|
+
_worksheet_write_drawing(lxw_worksheet *self, uint16_t id)
|
3443
3490
|
{
|
3444
3491
|
struct xml_attribute_list attributes;
|
3445
3492
|
struct xml_attribute *attribute;
|
@@ -3461,14 +3508,14 @@ _write_drawing(lxw_worksheet *self, uint16_t id)
|
|
3461
3508
|
* Write the <drawing> elements.
|
3462
3509
|
*/
|
3463
3510
|
STATIC void
|
3464
|
-
|
3511
|
+
_worksheet_write_drawings(lxw_worksheet *self)
|
3465
3512
|
{
|
3466
3513
|
if (!self->drawing)
|
3467
3514
|
return;
|
3468
3515
|
|
3469
3516
|
self->rel_count++;
|
3470
3517
|
|
3471
|
-
|
3518
|
+
_worksheet_write_drawing(self, self->rel_count);
|
3472
3519
|
}
|
3473
3520
|
|
3474
3521
|
/*
|
@@ -3689,6 +3736,52 @@ _worksheet_write_data_validations(lxw_worksheet *self)
|
|
3689
3736
|
LXW_FREE_ATTRIBUTES();
|
3690
3737
|
}
|
3691
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
|
+
|
3692
3785
|
/*
|
3693
3786
|
* Assemble and write the XML file.
|
3694
3787
|
*/
|
@@ -3723,7 +3816,7 @@ lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
|
|
3723
3816
|
_worksheet_write_optimized_sheet_data(self);
|
3724
3817
|
|
3725
3818
|
/* Write the sheetProtection element. */
|
3726
|
-
_worksheet_write_sheet_protection(self);
|
3819
|
+
_worksheet_write_sheet_protection(self, &self->protection);
|
3727
3820
|
|
3728
3821
|
/* Write the autoFilter element. */
|
3729
3822
|
_worksheet_write_auto_filter(self);
|
@@ -3756,7 +3849,7 @@ lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
|
|
3756
3849
|
_worksheet_write_col_breaks(self);
|
3757
3850
|
|
3758
3851
|
/* Write the drawing element. */
|
3759
|
-
|
3852
|
+
_worksheet_write_drawings(self);
|
3760
3853
|
|
3761
3854
|
/* Close the worksheet tag. */
|
3762
3855
|
lxw_xml_end_tag(self->file, "worksheet");
|
@@ -3823,7 +3916,7 @@ worksheet_write_string(lxw_worksheet *self,
|
|
3823
3916
|
|
3824
3917
|
if (!self->optimize) {
|
3825
3918
|
/* Get the SST element and string id. */
|
3826
|
-
sst_element = lxw_get_sst_index(self->sst, string);
|
3919
|
+
sst_element = lxw_get_sst_index(self->sst, string, LXW_FALSE);
|
3827
3920
|
|
3828
3921
|
if (!sst_element)
|
3829
3922
|
return LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND;
|
@@ -4298,6 +4391,156 @@ worksheet_write_url(lxw_worksheet *self,
|
|
4298
4391
|
NULL);
|
4299
4392
|
}
|
4300
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
|
+
|
4301
4544
|
/*
|
4302
4545
|
* Set the properties of a single column or a range of columns with options.
|
4303
4546
|
*/
|
@@ -5234,10 +5477,11 @@ worksheet_protect(lxw_worksheet *self, const char *password,
|
|
5234
5477
|
}
|
5235
5478
|
|
5236
5479
|
if (password) {
|
5237
|
-
uint16_t hash =
|
5480
|
+
uint16_t hash = lxw_hash_password(password);
|
5238
5481
|
lxw_snprintf(protect->hash, 5, "%X", hash);
|
5239
5482
|
}
|
5240
5483
|
|
5484
|
+
protect->no_content = LXW_TRUE;
|
5241
5485
|
protect->is_configured = LXW_TRUE;
|
5242
5486
|
}
|
5243
5487
|
|
@@ -5289,7 +5533,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
5289
5533
|
lxw_image_options *user_options)
|
5290
5534
|
{
|
5291
5535
|
FILE *image_stream;
|
5292
|
-
char *
|
5536
|
+
char *description;
|
5293
5537
|
lxw_image_options *options;
|
5294
5538
|
|
5295
5539
|
if (!filename) {
|
@@ -5307,9 +5551,9 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
5307
5551
|
return LXW_ERROR_PARAMETER_VALIDATION;
|
5308
5552
|
}
|
5309
5553
|
|
5310
|
-
/*
|
5311
|
-
|
5312
|
-
if (!
|
5554
|
+
/* Use the filename as the default description, like Excel. */
|
5555
|
+
description = lxw_basename(filename);
|
5556
|
+
if (!description) {
|
5313
5557
|
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
|
5314
5558
|
"couldn't get basename for file: %s.", filename);
|
5315
5559
|
fclose(image_stream);
|
@@ -5332,7 +5576,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
5332
5576
|
|
5333
5577
|
/* Copy other options or set defaults. */
|
5334
5578
|
options->filename = lxw_strdup(filename);
|
5335
|
-
options->
|
5579
|
+
options->description = lxw_strdup(description);
|
5336
5580
|
options->stream = image_stream;
|
5337
5581
|
options->row = row_num;
|
5338
5582
|
options->col = col_num;
|
@@ -5349,7 +5593,7 @@ worksheet_insert_image_opt(lxw_worksheet *self,
|
|
5349
5593
|
return LXW_NO_ERROR;
|
5350
5594
|
}
|
5351
5595
|
else {
|
5352
|
-
|
5596
|
+
_free_image_options(options);
|
5353
5597
|
fclose(image_stream);
|
5354
5598
|
return LXW_ERROR_IMAGE_DIMENSIONS;
|
5355
5599
|
}
|
@@ -5366,6 +5610,95 @@ worksheet_insert_image(lxw_worksheet *self,
|
|
5366
5610
|
return worksheet_insert_image_opt(self, row_num, col_num, filename, NULL);
|
5367
5611
|
}
|
5368
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
|
+
|
5369
5702
|
/*
|
5370
5703
|
* Insert an chart into the worksheet.
|
5371
5704
|
*/
|
@@ -5737,3 +6070,19 @@ worksheet_data_validation_cell(lxw_worksheet *self, lxw_row_t row,
|
|
5737
6070
|
return worksheet_data_validation_range(self, row, col,
|
5738
6071
|
row, col, validation);
|
5739
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
|
+
}
|