fast_excel 0.5.0 → 0.6.1

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.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +5 -1
  3. data/.gitignore +3 -0
  4. data/.octocov.yml +28 -0
  5. data/CHANGELOG.md +9 -0
  6. data/Gemfile +4 -2
  7. data/Rakefile +4 -1
  8. data/examples/comment_options.rb +39 -0
  9. data/fast_excel.gemspec +3 -2
  10. data/lib/fast_excel/binding/workbook.rb +53 -6
  11. data/lib/fast_excel/binding/worksheet.rb +28 -4
  12. data/lib/fast_excel/binding.rb +116 -13
  13. data/lib/fast_excel.rb +13 -12
  14. data/libxlsxwriter/.cirrus.yml +9 -0
  15. data/libxlsxwriter/.github/workflows/cmake_actions.yml +10 -6
  16. data/libxlsxwriter/.github/workflows/code_style.yml +2 -0
  17. data/libxlsxwriter/.github/workflows/make_32_actions.yml +43 -0
  18. data/libxlsxwriter/.github/workflows/windows_build.yml +7 -6
  19. data/libxlsxwriter/.github/workflows/zig_build.yml +1 -3
  20. data/libxlsxwriter/.gitignore +9 -7
  21. data/libxlsxwriter/.indent.pro +6 -0
  22. data/libxlsxwriter/CMakeLists.txt +377 -238
  23. data/libxlsxwriter/Changes.txt +189 -0
  24. data/libxlsxwriter/LICENSE.txt +1 -1
  25. data/libxlsxwriter/Makefile +36 -4
  26. data/libxlsxwriter/Readme.md +1 -1
  27. data/libxlsxwriter/build.zig +181 -92
  28. data/libxlsxwriter/build.zig.zon +15 -4
  29. data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +4 -0
  30. data/libxlsxwriter/include/xlsxwriter/app.h +2 -1
  31. data/libxlsxwriter/include/xlsxwriter/chart.h +134 -1
  32. data/libxlsxwriter/include/xlsxwriter/chartsheet.h +2 -1
  33. data/libxlsxwriter/include/xlsxwriter/comment.h +2 -1
  34. data/libxlsxwriter/include/xlsxwriter/common.h +12 -8
  35. data/libxlsxwriter/include/xlsxwriter/content_types.h +3 -1
  36. data/libxlsxwriter/include/xlsxwriter/core.h +2 -1
  37. data/libxlsxwriter/include/xlsxwriter/custom.h +2 -1
  38. data/libxlsxwriter/include/xlsxwriter/drawing.h +2 -1
  39. data/libxlsxwriter/include/xlsxwriter/format.h +34 -3
  40. data/libxlsxwriter/include/xlsxwriter/hash_table.h +2 -1
  41. data/libxlsxwriter/include/xlsxwriter/metadata.h +5 -1
  42. data/libxlsxwriter/include/xlsxwriter/packager.h +6 -1
  43. data/libxlsxwriter/include/xlsxwriter/relationships.h +3 -1
  44. data/libxlsxwriter/include/xlsxwriter/rich_value.h +51 -0
  45. data/libxlsxwriter/include/xlsxwriter/rich_value_rel.h +50 -0
  46. data/libxlsxwriter/include/xlsxwriter/rich_value_structure.h +53 -0
  47. data/libxlsxwriter/include/xlsxwriter/rich_value_types.h +49 -0
  48. data/libxlsxwriter/include/xlsxwriter/shared_strings.h +2 -1
  49. data/libxlsxwriter/include/xlsxwriter/styles.h +2 -1
  50. data/libxlsxwriter/include/xlsxwriter/table.h +2 -1
  51. data/libxlsxwriter/include/xlsxwriter/theme.h +2 -1
  52. data/libxlsxwriter/include/xlsxwriter/third_party/ioapi.h +4 -4
  53. data/libxlsxwriter/include/xlsxwriter/third_party/zip.h +3 -3
  54. data/libxlsxwriter/include/xlsxwriter/utility.h +58 -7
  55. data/libxlsxwriter/include/xlsxwriter/vml.h +2 -1
  56. data/libxlsxwriter/include/xlsxwriter/workbook.h +59 -2
  57. data/libxlsxwriter/include/xlsxwriter/worksheet.h +159 -13
  58. data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +11 -10
  59. data/libxlsxwriter/include/xlsxwriter.h +5 -4
  60. data/libxlsxwriter/libxlsxwriter.podspec +6 -6
  61. data/libxlsxwriter/src/Makefile +2 -1
  62. data/libxlsxwriter/src/app.c +2 -1
  63. data/libxlsxwriter/src/chart.c +360 -63
  64. data/libxlsxwriter/src/chartsheet.c +2 -1
  65. data/libxlsxwriter/src/comment.c +2 -1
  66. data/libxlsxwriter/src/content_types.c +22 -1
  67. data/libxlsxwriter/src/core.c +2 -1
  68. data/libxlsxwriter/src/custom.c +2 -1
  69. data/libxlsxwriter/src/drawing.c +7 -3
  70. data/libxlsxwriter/src/format.c +21 -1
  71. data/libxlsxwriter/src/hash_table.c +2 -1
  72. data/libxlsxwriter/src/metadata.c +176 -20
  73. data/libxlsxwriter/src/packager.c +306 -6
  74. data/libxlsxwriter/src/relationships.c +25 -1
  75. data/libxlsxwriter/src/rich_value.c +191 -0
  76. data/libxlsxwriter/src/rich_value_rel.c +142 -0
  77. data/libxlsxwriter/src/rich_value_structure.c +162 -0
  78. data/libxlsxwriter/src/rich_value_types.c +199 -0
  79. data/libxlsxwriter/src/shared_strings.c +2 -1
  80. data/libxlsxwriter/src/styles.c +31 -7
  81. data/libxlsxwriter/src/table.c +2 -1
  82. data/libxlsxwriter/src/theme.c +2 -1
  83. data/libxlsxwriter/src/utility.c +136 -46
  84. data/libxlsxwriter/src/vml.c +2 -1
  85. data/libxlsxwriter/src/workbook.c +191 -10
  86. data/libxlsxwriter/src/worksheet.c +514 -34
  87. data/libxlsxwriter/src/xmlwriter.c +17 -22
  88. data/libxlsxwriter/third_party/minizip/Makefile.orig +1 -1
  89. data/libxlsxwriter/third_party/minizip/configure.ac +1 -1
  90. data/libxlsxwriter/third_party/minizip/ioapi.h +6 -6
  91. data/libxlsxwriter/third_party/minizip/miniunz.c +16 -2
  92. data/libxlsxwriter/third_party/minizip/unzip.c +4 -4
  93. data/libxlsxwriter/third_party/minizip/unzip.h +1 -1
  94. data/libxlsxwriter/third_party/minizip/zip.c +5 -5
  95. data/libxlsxwriter/third_party/minizip/zip.h +3 -3
  96. data/libxlsxwriter/version.txt +1 -1
  97. data/sonar-project.properties +4 -0
  98. data/test/color_to_hex_test.rb +15 -0
  99. data/test/comment_opt_test.rb +76 -0
  100. data/test/date_test.rb +14 -0
  101. data/test/format_test.rb +5 -1
  102. data/test/get_worksheet_test.rb +28 -0
  103. data/test/test_helper.rb +7 -4
  104. data/test/tmpdir_test.rb +32 -0
  105. data/test/validations_test.rb +25 -19
  106. data/test/worksheet_test.rb +10 -2
  107. metadata +42 -12
  108. data/libxlsxwriter/cmake/FindMINIZIP.cmake +0 -121
  109. data/libxlsxwriter/cmake/FindPackage.cmake +0 -183
  110. data/libxlsxwriter/cmake/i686-toolchain.cmake +0 -7
  111. data/test/reopen_test.rb +0 -22
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * SPDX-License-Identifier: BSD-2-Clause
7
+ * Copyright 2014-2026, John McNamara, jmcnamara@cpan.org.
7
8
  *
8
9
  */
9
10
 
@@ -12,6 +13,7 @@
12
13
  #include "xlsxwriter/utility.h"
13
14
  #include "xlsxwriter/packager.h"
14
15
  #include "xlsxwriter/hash_table.h"
16
+ #include "xlsxwriter/hash_table.h"
15
17
 
16
18
  STATIC int _worksheet_name_cmp(lxw_worksheet_name *name1,
17
19
  lxw_worksheet_name *name2);
@@ -230,12 +232,30 @@ lxw_workbook_free(lxw_workbook *workbook)
230
232
  free(workbook->image_md5s);
231
233
  }
232
234
 
235
+ if (workbook->embedded_image_md5s) {
236
+ for (image_md5 =
237
+ RB_MIN(lxw_image_md5s, workbook->embedded_image_md5s); image_md5;
238
+ image_md5 = next_image_md5) {
239
+
240
+ next_image_md5 =
241
+ RB_NEXT(lxw_image_md5s, workbook->embedded_image_md5s,
242
+ image_md5);
243
+ RB_REMOVE(lxw_image_md5s, workbook->embedded_image_md5s,
244
+ image_md5);
245
+ free(image_md5->md5);
246
+ free(image_md5);
247
+ }
248
+
249
+ free(workbook->embedded_image_md5s);
250
+ }
251
+
233
252
  if (workbook->header_image_md5s) {
234
253
  for (image_md5 = RB_MIN(lxw_image_md5s, workbook->header_image_md5s);
235
254
  image_md5; image_md5 = next_image_md5) {
236
255
 
237
256
  next_image_md5 =
238
- RB_NEXT(lxw_image_md5s, workbook->image_md5, image_md5);
257
+ RB_NEXT(lxw_image_md5s, workbook->header_image_md5s,
258
+ image_md5);
239
259
  RB_REMOVE(lxw_image_md5s, workbook->header_image_md5s, image_md5);
240
260
  free(image_md5->md5);
241
261
  free(image_md5);
@@ -249,7 +269,7 @@ lxw_workbook_free(lxw_workbook *workbook)
249
269
  image_md5; image_md5 = next_image_md5) {
250
270
 
251
271
  next_image_md5 =
252
- RB_NEXT(lxw_image_md5s, workbook->image_md5, image_md5);
272
+ RB_NEXT(lxw_image_md5s, workbook->background_md5s, image_md5);
253
273
  RB_REMOVE(lxw_image_md5s, workbook->background_md5s, image_md5);
254
274
  free(image_md5->md5);
255
275
  free(image_md5);
@@ -677,6 +697,9 @@ _store_defined_name(lxw_workbook *self, const char *name,
677
697
  if (!name || !formula)
678
698
  return LXW_ERROR_NULL_PARAMETER_IGNORED;
679
699
 
700
+ if (lxw_str_is_empty(name) || lxw_str_is_empty(formula))
701
+ return LXW_ERROR_PARAMETER_IS_EMPTY;
702
+
680
703
  if (lxw_utf8_strlen(name) > LXW_DEFINED_NAME_LENGTH ||
681
704
  lxw_utf8_strlen(formula) > LXW_DEFINED_NAME_LENGTH) {
682
705
  return LXW_ERROR_128_STRING_LENGTH_EXCEEDED;
@@ -709,11 +732,16 @@ _store_defined_name(lxw_workbook *self, const char *name,
709
732
  tmp_str++;
710
733
  worksheet_name = name_copy;
711
734
 
735
+ if (lxw_str_is_empty(tmp_str) || lxw_str_is_empty(worksheet_name))
736
+ goto mem_error;
737
+
712
738
  /* Remove any worksheet quoting. */
713
739
  if (worksheet_name[0] == '\'')
714
740
  worksheet_name++;
715
- if (worksheet_name[strlen(worksheet_name) - 1] == '\'')
741
+ if (strlen(worksheet_name) > 0
742
+ && worksheet_name[strlen(worksheet_name) - 1] == '\'') {
716
743
  worksheet_name[strlen(worksheet_name) - 1] = '\0';
744
+ }
717
745
 
718
746
  /* Search for worksheet name to get the equivalent worksheet index. */
719
747
  STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
@@ -932,16 +960,28 @@ _populate_range_dimensions(lxw_workbook *self, lxw_series_range *range)
932
960
  return;
933
961
  }
934
962
  else {
963
+ /* Check for empty string. */
964
+ if (lxw_str_is_empty(tmp_str)) {
965
+ range->ignore_cache = LXW_TRUE;
966
+ return;
967
+ }
968
+
935
969
  /* Split the formulas into sheetname and row-col data. */
936
970
  *tmp_str = '\0';
937
971
  tmp_str++;
938
972
  sheetname = formula;
939
973
 
974
+ if (lxw_str_is_empty(tmp_str) || lxw_str_is_empty(sheetname)) {
975
+ range->ignore_cache = LXW_TRUE;
976
+ return;
977
+ }
978
+
940
979
  /* Remove any worksheet quoting. */
941
980
  if (sheetname[0] == '\'')
942
981
  sheetname++;
943
- if (sheetname[strlen(sheetname) - 1] == '\'')
982
+ if (strlen(sheetname) > 0 && sheetname[strlen(sheetname) - 1] == '\'') {
944
983
  sheetname[strlen(sheetname) - 1] = '\0';
984
+ }
945
985
 
946
986
  /* Check that the sheetname exists. */
947
987
  if (!workbook_get_worksheet_by_name(self, sheetname)) {
@@ -1064,6 +1104,7 @@ _prepare_drawings(lxw_workbook *self)
1064
1104
  }
1065
1105
 
1066
1106
  if (STAILQ_EMPTY(worksheet->image_props)
1107
+ && STAILQ_EMPTY(worksheet->embedded_image_props)
1067
1108
  && STAILQ_EMPTY(worksheet->chart_data)
1068
1109
  && !worksheet->has_header_vml && !worksheet->has_background_image) {
1069
1110
  continue;
@@ -1071,6 +1112,48 @@ _prepare_drawings(lxw_workbook *self)
1071
1112
 
1072
1113
  drawing_id++;
1073
1114
 
1115
+ /* Prepare embedded worksheet images. */
1116
+ STAILQ_FOREACH(object_props, worksheet->embedded_image_props,
1117
+ list_pointers) {
1118
+
1119
+ _store_image_type(self, object_props->image_type);
1120
+
1121
+ /* Check for images with alt-text. */
1122
+ if (object_props->description)
1123
+ self->has_embedded_image_descriptions = LXW_TRUE;
1124
+
1125
+ /* Check for duplicate images and only store the first instance. */
1126
+ if (object_props->md5) {
1127
+ tmp_image_md5.md5 = object_props->md5;
1128
+ found_duplicate_image = RB_FIND(lxw_image_md5s,
1129
+ self->embedded_image_md5s,
1130
+ &tmp_image_md5);
1131
+ }
1132
+
1133
+ if (found_duplicate_image) {
1134
+ ref_id = found_duplicate_image->id;
1135
+ object_props->is_duplicate = LXW_TRUE;
1136
+ }
1137
+ else {
1138
+ image_ref_id++;
1139
+ ref_id = image_ref_id;
1140
+ self->num_embedded_images++;
1141
+
1142
+ #ifndef USE_NO_MD5
1143
+ new_image_md5 = calloc(1, sizeof(lxw_image_md5));
1144
+ #endif
1145
+ if (new_image_md5 && object_props->md5) {
1146
+ new_image_md5->id = ref_id;
1147
+ new_image_md5->md5 = lxw_strdup(object_props->md5);
1148
+
1149
+ RB_INSERT(lxw_image_md5s, self->embedded_image_md5s,
1150
+ new_image_md5);
1151
+ }
1152
+ }
1153
+
1154
+ worksheet_set_error_cell(worksheet, object_props, ref_id);
1155
+ }
1156
+
1074
1157
  /* Prepare background images. */
1075
1158
  if (worksheet->has_background_image) {
1076
1159
 
@@ -1532,6 +1615,9 @@ _write_workbook_pr(lxw_workbook *self)
1532
1615
  if (self->vba_codename)
1533
1616
  LXW_PUSH_ATTRIBUTES_STR("codeName", self->vba_codename);
1534
1617
 
1618
+ if (self->use_1904_epoch)
1619
+ LXW_PUSH_ATTRIBUTES_STR("date1904", "1");
1620
+
1535
1621
  LXW_PUSH_ATTRIBUTES_STR("defaultThemeVersion", "124226");
1536
1622
 
1537
1623
  lxw_xml_empty_tag(self->file, "workbookPr", &attributes);
@@ -1551,8 +1637,8 @@ _write_workbook_view(lxw_workbook *self)
1551
1637
  LXW_INIT_ATTRIBUTES();
1552
1638
  LXW_PUSH_ATTRIBUTES_STR("xWindow", "240");
1553
1639
  LXW_PUSH_ATTRIBUTES_STR("yWindow", "15");
1554
- LXW_PUSH_ATTRIBUTES_STR("windowWidth", "16095");
1555
- LXW_PUSH_ATTRIBUTES_STR("windowHeight", "9660");
1640
+ LXW_PUSH_ATTRIBUTES_INT("windowWidth", self->window_width);
1641
+ LXW_PUSH_ATTRIBUTES_INT("windowHeight", self->window_height);
1556
1642
 
1557
1643
  if (self->first_sheet)
1558
1644
  LXW_PUSH_ATTRIBUTES_INT("firstSheet", self->first_sheet);
@@ -1812,6 +1898,11 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
1812
1898
  GOTO_LABEL_ON_MEM_ERROR(workbook->image_md5s, mem_error);
1813
1899
  RB_INIT(workbook->image_md5s);
1814
1900
 
1901
+ /* Add the embedded image MD5 tree. */
1902
+ workbook->embedded_image_md5s = calloc(1, sizeof(struct lxw_image_md5s));
1903
+ GOTO_LABEL_ON_MEM_ERROR(workbook->embedded_image_md5s, mem_error);
1904
+ RB_INIT(workbook->embedded_image_md5s);
1905
+
1815
1906
  /* Add the header image MD5 tree. */
1816
1907
  workbook->header_image_md5s = calloc(1, sizeof(struct lxw_image_md5s));
1817
1908
  GOTO_LABEL_ON_MEM_ERROR(workbook->header_image_md5s, mem_error);
@@ -1886,6 +1977,8 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
1886
1977
  }
1887
1978
 
1888
1979
  workbook->max_url_length = 2079;
1980
+ workbook->window_width = 16095;
1981
+ workbook->window_height = 9660;
1889
1982
 
1890
1983
  return workbook;
1891
1984
 
@@ -1905,7 +1998,8 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
1905
1998
  lxw_worksheet *worksheet = NULL;
1906
1999
  lxw_worksheet_name *worksheet_name = NULL;
1907
2000
  lxw_error error;
1908
- lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2001
+ lxw_worksheet_init_data init_data =
2002
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1909
2003
  char *new_name = NULL;
1910
2004
 
1911
2005
  if (sheetname) {
@@ -1946,6 +2040,7 @@ workbook_add_worksheet(lxw_workbook *self, const char *sheetname)
1946
2040
  init_data.tmpdir = self->options.tmpdir;
1947
2041
  init_data.default_url_format = self->default_url_format;
1948
2042
  init_data.max_url_length = self->max_url_length;
2043
+ init_data.use_1904_epoch = self->use_1904_epoch;
1949
2044
 
1950
2045
  /* Create a new worksheet object. */
1951
2046
  worksheet = lxw_worksheet_new(&init_data);
@@ -1989,7 +2084,8 @@ workbook_add_chartsheet(lxw_workbook *self, const char *sheetname)
1989
2084
  lxw_chartsheet *chartsheet = NULL;
1990
2085
  lxw_chartsheet_name *chartsheet_name = NULL;
1991
2086
  lxw_error error;
1992
- lxw_worksheet_init_data init_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2087
+ lxw_worksheet_init_data init_data =
2088
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1993
2089
  char *new_name = NULL;
1994
2090
 
1995
2091
  if (sheetname) {
@@ -2071,6 +2167,12 @@ workbook_add_chart(lxw_workbook *self, uint8_t type)
2071
2167
  {
2072
2168
  lxw_chart *chart;
2073
2169
 
2170
+ if (type == LXW_CHART_NONE || type > LXW_CHART_RADAR_FILLED) {
2171
+ LXW_WARN_FORMAT1("workbook_add_chart(): invalid chart type: %d",
2172
+ type);
2173
+ return NULL;
2174
+ }
2175
+
2074
2176
  /* Create a new chart object. */
2075
2177
  chart = lxw_chart_new(type);
2076
2178
 
@@ -2154,8 +2256,16 @@ workbook_close(lxw_workbook *self)
2154
2256
  if (worksheet->index == self->active_sheet)
2155
2257
  worksheet->active = LXW_TRUE;
2156
2258
 
2157
- if (worksheet->has_dynamic_arrays)
2259
+ if (worksheet->has_dynamic_functions) {
2260
+ self->has_metadata = LXW_TRUE;
2261
+ self->has_dynamic_functions = LXW_TRUE;
2262
+
2263
+ }
2264
+
2265
+ if (!STAILQ_EMPTY(worksheet->embedded_image_props)) {
2158
2266
  self->has_metadata = LXW_TRUE;
2267
+ self->has_embedded_images = LXW_TRUE;
2268
+ }
2159
2269
  }
2160
2270
 
2161
2271
  /* Set workbook and worksheet VBA codenames if a macro has been added. */
@@ -2375,6 +2485,12 @@ workbook_set_custom_property_string(lxw_workbook *self, const char *name,
2375
2485
  return LXW_ERROR_NULL_PARAMETER_IGNORED;
2376
2486
  }
2377
2487
 
2488
+ if (lxw_str_is_empty(name)) {
2489
+ LXW_WARN_FORMAT("workbook_set_custom_property_string(): "
2490
+ "parameter 'name' cannot be an empty string.");
2491
+ return LXW_ERROR_PARAMETER_IS_EMPTY;
2492
+ }
2493
+
2378
2494
  if (!value) {
2379
2495
  LXW_WARN_FORMAT("workbook_set_custom_property_string(): "
2380
2496
  "parameter 'value' cannot be NULL.");
@@ -2422,6 +2538,12 @@ workbook_set_custom_property_number(lxw_workbook *self, const char *name,
2422
2538
  return LXW_ERROR_NULL_PARAMETER_IGNORED;
2423
2539
  }
2424
2540
 
2541
+ if (lxw_str_is_empty(name)) {
2542
+ LXW_WARN_FORMAT("workbook_set_custom_property_number(): parameter "
2543
+ "'name' cannot be an empty string.");
2544
+ return LXW_ERROR_PARAMETER_IS_EMPTY;
2545
+ }
2546
+
2425
2547
  if (lxw_utf8_strlen(name) > 255) {
2426
2548
  LXW_WARN_FORMAT("workbook_set_custom_property_number(): parameter "
2427
2549
  "'name' exceeds Excel length limit of 255.");
@@ -2457,6 +2579,12 @@ workbook_set_custom_property_integer(lxw_workbook *self, const char *name,
2457
2579
  return LXW_ERROR_NULL_PARAMETER_IGNORED;
2458
2580
  }
2459
2581
 
2582
+ if (lxw_str_is_empty(name)) {
2583
+ LXW_WARN_FORMAT("workbook_set_custom_property_integer(): parameter "
2584
+ "'name' cannot be an empty string.");
2585
+ return LXW_ERROR_PARAMETER_IS_EMPTY;
2586
+ }
2587
+
2460
2588
  if (strlen(name) > 255) {
2461
2589
  LXW_WARN_FORMAT("workbook_set_custom_property_integer(): parameter "
2462
2590
  "'name' exceeds Excel length limit of 255.");
@@ -2492,6 +2620,12 @@ workbook_set_custom_property_boolean(lxw_workbook *self, const char *name,
2492
2620
  return LXW_ERROR_NULL_PARAMETER_IGNORED;
2493
2621
  }
2494
2622
 
2623
+ if (lxw_str_is_empty(name)) {
2624
+ LXW_WARN_FORMAT("workbook_set_custom_property_boolean(): parameter "
2625
+ "'name' cannot be an empty string.");
2626
+ return LXW_ERROR_PARAMETER_IS_EMPTY;
2627
+ }
2628
+
2495
2629
  if (lxw_utf8_strlen(name) > 255) {
2496
2630
  LXW_WARN_FORMAT("workbook_set_custom_property_boolean(): parameter "
2497
2631
  "'name' exceeds Excel length limit of 255.");
@@ -2527,6 +2661,12 @@ workbook_set_custom_property_datetime(lxw_workbook *self, const char *name,
2527
2661
  return LXW_ERROR_NULL_PARAMETER_IGNORED;
2528
2662
  }
2529
2663
 
2664
+ if (lxw_str_is_empty(name)) {
2665
+ LXW_WARN_FORMAT("workbook_set_custom_property_datetime(): parameter "
2666
+ "'name' cannot be an empty string.");
2667
+ return LXW_ERROR_PARAMETER_IS_EMPTY;
2668
+ }
2669
+
2530
2670
  if (lxw_utf8_strlen(name) > 255) {
2531
2671
  LXW_WARN_FORMAT("workbook_set_custom_property_datetime(): parameter "
2532
2672
  "'name' exceeds Excel length limit of 255.");
@@ -2539,6 +2679,10 @@ workbook_set_custom_property_datetime(lxw_workbook *self, const char *name,
2539
2679
  return LXW_ERROR_NULL_PARAMETER_IGNORED;
2540
2680
  }
2541
2681
 
2682
+ if (lxw_datetime_validate(datetime) != LXW_NO_ERROR) {
2683
+ return LXW_ERROR_DATETIME_VALIDATION;
2684
+ }
2685
+
2542
2686
  /* Create a struct to hold the custom property. */
2543
2687
  custom_property = calloc(1, sizeof(struct lxw_custom_property));
2544
2688
  RETURN_ON_MEM_ERROR(custom_property, LXW_ERROR_MEMORY_MALLOC_FAILED);
@@ -2625,6 +2769,13 @@ workbook_unset_default_url_format(lxw_workbook *self)
2625
2769
  lxw_error
2626
2770
  workbook_validate_sheet_name(lxw_workbook *self, const char *sheetname)
2627
2771
  {
2772
+ if (sheetname == NULL)
2773
+ return LXW_ERROR_NULL_PARAMETER_IGNORED;
2774
+
2775
+ /* Check for empty worksheet name. */
2776
+ if (lxw_str_is_empty(sheetname))
2777
+ return LXW_ERROR_PARAMETER_IS_EMPTY;
2778
+
2628
2779
  /* Check the UTF-8 length of the worksheet name. */
2629
2780
  if (lxw_utf8_strlen(sheetname) > LXW_SHEETNAME_MAX)
2630
2781
  return LXW_ERROR_SHEETNAME_LENGTH_EXCEEDED;
@@ -2723,6 +2874,12 @@ workbook_set_vba_name(lxw_workbook *self, const char *name)
2723
2874
  return LXW_ERROR_NULL_PARAMETER_IGNORED;
2724
2875
  }
2725
2876
 
2877
+ if (lxw_str_is_empty(name)) {
2878
+ LXW_WARN_FORMAT("workbook_set_vba_name(): parameter "
2879
+ "'name' cannot be an empty string.");
2880
+ return LXW_ERROR_PARAMETER_IS_EMPTY;
2881
+ }
2882
+
2726
2883
  self->vba_codename = lxw_strdup(name);
2727
2884
 
2728
2885
  return LXW_NO_ERROR;
@@ -2736,3 +2893,27 @@ workbook_read_only_recommended(lxw_workbook *self)
2736
2893
  {
2737
2894
  self->read_only = 2;
2738
2895
  }
2896
+
2897
+ /*
2898
+ * Use the 1904 epoch for dates in the workbook.
2899
+ */
2900
+ void
2901
+ workbook_use_1904_epoch(lxw_workbook *self)
2902
+ {
2903
+ self->use_1904_epoch = LXW_TRUE;
2904
+ }
2905
+
2906
+ /*
2907
+ * Set the size of a workbook window.
2908
+ */
2909
+ void
2910
+ workbook_set_size(lxw_workbook *workbook, uint16_t width, uint16_t height)
2911
+ {
2912
+ /* Convert the width/height to twips at 96 dpi. */
2913
+ if (width)
2914
+ workbook->window_width = width * 1440 / 96;
2915
+
2916
+ if (height)
2917
+ workbook->window_height = height * 1440 / 96;
2918
+
2919
+ }