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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +5 -1
- data/.gitignore +3 -0
- data/.octocov.yml +28 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +4 -2
- data/Rakefile +4 -1
- data/examples/comment_options.rb +39 -0
- data/fast_excel.gemspec +3 -2
- data/lib/fast_excel/binding/workbook.rb +53 -6
- data/lib/fast_excel/binding/worksheet.rb +28 -4
- data/lib/fast_excel/binding.rb +116 -13
- data/lib/fast_excel.rb +13 -12
- data/libxlsxwriter/.cirrus.yml +9 -0
- data/libxlsxwriter/.github/workflows/cmake_actions.yml +10 -6
- data/libxlsxwriter/.github/workflows/code_style.yml +2 -0
- data/libxlsxwriter/.github/workflows/make_32_actions.yml +43 -0
- data/libxlsxwriter/.github/workflows/windows_build.yml +7 -6
- data/libxlsxwriter/.github/workflows/zig_build.yml +1 -3
- data/libxlsxwriter/.gitignore +9 -7
- data/libxlsxwriter/.indent.pro +6 -0
- data/libxlsxwriter/CMakeLists.txt +377 -238
- data/libxlsxwriter/Changes.txt +189 -0
- data/libxlsxwriter/LICENSE.txt +1 -1
- data/libxlsxwriter/Makefile +36 -4
- data/libxlsxwriter/Readme.md +1 -1
- data/libxlsxwriter/build.zig +181 -92
- data/libxlsxwriter/build.zig.zon +15 -4
- data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +4 -0
- data/libxlsxwriter/include/xlsxwriter/app.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/chart.h +134 -1
- data/libxlsxwriter/include/xlsxwriter/chartsheet.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/comment.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/common.h +12 -8
- data/libxlsxwriter/include/xlsxwriter/content_types.h +3 -1
- data/libxlsxwriter/include/xlsxwriter/core.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/custom.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/drawing.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/format.h +34 -3
- data/libxlsxwriter/include/xlsxwriter/hash_table.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/metadata.h +5 -1
- data/libxlsxwriter/include/xlsxwriter/packager.h +6 -1
- data/libxlsxwriter/include/xlsxwriter/relationships.h +3 -1
- data/libxlsxwriter/include/xlsxwriter/rich_value.h +51 -0
- data/libxlsxwriter/include/xlsxwriter/rich_value_rel.h +50 -0
- data/libxlsxwriter/include/xlsxwriter/rich_value_structure.h +53 -0
- data/libxlsxwriter/include/xlsxwriter/rich_value_types.h +49 -0
- data/libxlsxwriter/include/xlsxwriter/shared_strings.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/styles.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/table.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/theme.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/third_party/ioapi.h +4 -4
- data/libxlsxwriter/include/xlsxwriter/third_party/zip.h +3 -3
- data/libxlsxwriter/include/xlsxwriter/utility.h +58 -7
- data/libxlsxwriter/include/xlsxwriter/vml.h +2 -1
- data/libxlsxwriter/include/xlsxwriter/workbook.h +59 -2
- data/libxlsxwriter/include/xlsxwriter/worksheet.h +159 -13
- data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +11 -10
- data/libxlsxwriter/include/xlsxwriter.h +5 -4
- data/libxlsxwriter/libxlsxwriter.podspec +6 -6
- data/libxlsxwriter/src/Makefile +2 -1
- data/libxlsxwriter/src/app.c +2 -1
- data/libxlsxwriter/src/chart.c +360 -63
- data/libxlsxwriter/src/chartsheet.c +2 -1
- data/libxlsxwriter/src/comment.c +2 -1
- data/libxlsxwriter/src/content_types.c +22 -1
- data/libxlsxwriter/src/core.c +2 -1
- data/libxlsxwriter/src/custom.c +2 -1
- data/libxlsxwriter/src/drawing.c +7 -3
- data/libxlsxwriter/src/format.c +21 -1
- data/libxlsxwriter/src/hash_table.c +2 -1
- data/libxlsxwriter/src/metadata.c +176 -20
- data/libxlsxwriter/src/packager.c +306 -6
- data/libxlsxwriter/src/relationships.c +25 -1
- data/libxlsxwriter/src/rich_value.c +191 -0
- data/libxlsxwriter/src/rich_value_rel.c +142 -0
- data/libxlsxwriter/src/rich_value_structure.c +162 -0
- data/libxlsxwriter/src/rich_value_types.c +199 -0
- data/libxlsxwriter/src/shared_strings.c +2 -1
- data/libxlsxwriter/src/styles.c +31 -7
- data/libxlsxwriter/src/table.c +2 -1
- data/libxlsxwriter/src/theme.c +2 -1
- data/libxlsxwriter/src/utility.c +136 -46
- data/libxlsxwriter/src/vml.c +2 -1
- data/libxlsxwriter/src/workbook.c +191 -10
- data/libxlsxwriter/src/worksheet.c +514 -34
- data/libxlsxwriter/src/xmlwriter.c +17 -22
- data/libxlsxwriter/third_party/minizip/Makefile.orig +1 -1
- data/libxlsxwriter/third_party/minizip/configure.ac +1 -1
- data/libxlsxwriter/third_party/minizip/ioapi.h +6 -6
- data/libxlsxwriter/third_party/minizip/miniunz.c +16 -2
- data/libxlsxwriter/third_party/minizip/unzip.c +4 -4
- data/libxlsxwriter/third_party/minizip/unzip.h +1 -1
- data/libxlsxwriter/third_party/minizip/zip.c +5 -5
- data/libxlsxwriter/third_party/minizip/zip.h +3 -3
- data/libxlsxwriter/version.txt +1 -1
- data/sonar-project.properties +4 -0
- data/test/color_to_hex_test.rb +15 -0
- data/test/comment_opt_test.rb +76 -0
- data/test/date_test.rb +14 -0
- data/test/format_test.rb +5 -1
- data/test/get_worksheet_test.rb +28 -0
- data/test/test_helper.rb +7 -4
- data/test/tmpdir_test.rb +32 -0
- data/test/validations_test.rb +25 -19
- data/test/worksheet_test.rb +10 -2
- metadata +42 -12
- data/libxlsxwriter/cmake/FindMINIZIP.cmake +0 -121
- data/libxlsxwriter/cmake/FindPackage.cmake +0 -183
- data/libxlsxwriter/cmake/i686-toolchain.cmake +0 -7
- 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
|
-
*
|
|
6
|
+
* SPDX-License-Identifier: BSD-2-Clause
|
|
7
|
+
* Copyright 2014-2026, John McNamara, jmcnamara@cpan.org.
|
|
7
8
|
*
|
|
8
9
|
*/
|
|
9
10
|
|
|
@@ -27,16 +28,16 @@ STATIC char *_escape_attributes(struct xml_attribute *attribute);
|
|
|
27
28
|
|
|
28
29
|
char *lxw_escape_data(const char *data);
|
|
29
30
|
|
|
30
|
-
STATIC void _fprint_escaped_attributes(FILE *
|
|
31
|
+
STATIC void _fprint_escaped_attributes(FILE *xmlfile,
|
|
31
32
|
struct xml_attribute_list *attributes);
|
|
32
33
|
|
|
33
|
-
STATIC void _fprint_escaped_data(FILE *
|
|
34
|
+
STATIC void _fprint_escaped_data(FILE *xmlfile, const char *data);
|
|
34
35
|
|
|
35
36
|
/*
|
|
36
37
|
* Write the XML declaration.
|
|
37
38
|
*/
|
|
38
39
|
void
|
|
39
|
-
lxw_xml_declaration(FILE *
|
|
40
|
+
lxw_xml_declaration(FILE *xmlfile)
|
|
40
41
|
{
|
|
41
42
|
fprintf(xmlfile, "<?xml version=\"1.0\" "
|
|
42
43
|
"encoding=\"UTF-8\" standalone=\"yes\"?>\n");
|
|
@@ -46,7 +47,7 @@ lxw_xml_declaration(FILE * xmlfile)
|
|
|
46
47
|
* Write an XML start tag with optional attributes.
|
|
47
48
|
*/
|
|
48
49
|
void
|
|
49
|
-
lxw_xml_start_tag(FILE *
|
|
50
|
+
lxw_xml_start_tag(FILE *xmlfile,
|
|
50
51
|
const char *tag, struct xml_attribute_list *attributes)
|
|
51
52
|
{
|
|
52
53
|
fprintf(xmlfile, "<%s", tag);
|
|
@@ -61,7 +62,7 @@ lxw_xml_start_tag(FILE * xmlfile,
|
|
|
61
62
|
* This is a minor speed optimization for elements that don't need encoding.
|
|
62
63
|
*/
|
|
63
64
|
void
|
|
64
|
-
lxw_xml_start_tag_unencoded(FILE *
|
|
65
|
+
lxw_xml_start_tag_unencoded(FILE *xmlfile,
|
|
65
66
|
const char *tag,
|
|
66
67
|
struct xml_attribute_list *attributes)
|
|
67
68
|
{
|
|
@@ -82,7 +83,7 @@ lxw_xml_start_tag_unencoded(FILE * xmlfile,
|
|
|
82
83
|
* Write an XML end tag.
|
|
83
84
|
*/
|
|
84
85
|
void
|
|
85
|
-
lxw_xml_end_tag(FILE *
|
|
86
|
+
lxw_xml_end_tag(FILE *xmlfile, const char *tag)
|
|
86
87
|
{
|
|
87
88
|
fprintf(xmlfile, "</%s>", tag);
|
|
88
89
|
}
|
|
@@ -91,7 +92,7 @@ lxw_xml_end_tag(FILE * xmlfile, const char *tag)
|
|
|
91
92
|
* Write an empty XML tag with optional attributes.
|
|
92
93
|
*/
|
|
93
94
|
void
|
|
94
|
-
lxw_xml_empty_tag(FILE *
|
|
95
|
+
lxw_xml_empty_tag(FILE *xmlfile,
|
|
95
96
|
const char *tag, struct xml_attribute_list *attributes)
|
|
96
97
|
{
|
|
97
98
|
fprintf(xmlfile, "<%s", tag);
|
|
@@ -106,7 +107,7 @@ lxw_xml_empty_tag(FILE * xmlfile,
|
|
|
106
107
|
* This is a minor speed optimization for elements that don't need encoding.
|
|
107
108
|
*/
|
|
108
109
|
void
|
|
109
|
-
lxw_xml_empty_tag_unencoded(FILE *
|
|
110
|
+
lxw_xml_empty_tag_unencoded(FILE *xmlfile,
|
|
110
111
|
const char *tag,
|
|
111
112
|
struct xml_attribute_list *attributes)
|
|
112
113
|
{
|
|
@@ -127,7 +128,7 @@ lxw_xml_empty_tag_unencoded(FILE * xmlfile,
|
|
|
127
128
|
* Write an XML element containing data with optional attributes.
|
|
128
129
|
*/
|
|
129
130
|
void
|
|
130
|
-
lxw_xml_data_element(FILE *
|
|
131
|
+
lxw_xml_data_element(FILE *xmlfile,
|
|
131
132
|
const char *tag,
|
|
132
133
|
const char *data, struct xml_attribute_list *attributes)
|
|
133
134
|
{
|
|
@@ -146,7 +147,7 @@ lxw_xml_data_element(FILE * xmlfile,
|
|
|
146
147
|
* Write an XML <si> element for rich strings, without encoding.
|
|
147
148
|
*/
|
|
148
149
|
void
|
|
149
|
-
lxw_xml_rich_si_element(FILE *
|
|
150
|
+
lxw_xml_rich_si_element(FILE *xmlfile, const char *string)
|
|
150
151
|
{
|
|
151
152
|
fprintf(xmlfile, "<si>%s</si>", string);
|
|
152
153
|
}
|
|
@@ -238,7 +239,7 @@ lxw_escape_data(const char *data)
|
|
|
238
239
|
uint8_t
|
|
239
240
|
lxw_has_control_characters(const char *string)
|
|
240
241
|
{
|
|
241
|
-
while (string) {
|
|
242
|
+
while (*string) {
|
|
242
243
|
/* 0xE0 == 0b11100000 masks values > 0x19 == 0b00011111. */
|
|
243
244
|
if (!(*string & 0xE0) && *string != 0x0A && *string != 0x09)
|
|
244
245
|
return LXW_TRUE;
|
|
@@ -369,7 +370,7 @@ lxw_escape_url_characters(const char *string, uint8_t escape_hash)
|
|
|
369
370
|
|
|
370
371
|
/* Write out escaped attributes. */
|
|
371
372
|
STATIC void
|
|
372
|
-
_fprint_escaped_attributes(FILE *
|
|
373
|
+
_fprint_escaped_attributes(FILE *xmlfile,
|
|
373
374
|
struct xml_attribute_list *attributes)
|
|
374
375
|
{
|
|
375
376
|
struct xml_attribute *attribute;
|
|
@@ -396,7 +397,7 @@ _fprint_escaped_attributes(FILE * xmlfile,
|
|
|
396
397
|
|
|
397
398
|
/* Write out escaped XML data. */
|
|
398
399
|
STATIC void
|
|
399
|
-
_fprint_escaped_data(FILE *
|
|
400
|
+
_fprint_escaped_data(FILE *xmlfile, const char *data)
|
|
400
401
|
{
|
|
401
402
|
/* Escape the data section of the XML element. */
|
|
402
403
|
if (!strpbrk(data, "&<>")) {
|
|
@@ -425,18 +426,12 @@ lxw_new_attribute_str(const char *key, const char *value)
|
|
|
425
426
|
|
|
426
427
|
/* Create a new integer XML attribute. */
|
|
427
428
|
struct xml_attribute *
|
|
428
|
-
lxw_new_attribute_int(const char *key,
|
|
429
|
+
lxw_new_attribute_int(const char *key, int32_t value)
|
|
429
430
|
{
|
|
430
431
|
struct xml_attribute *attribute = malloc(sizeof(struct xml_attribute));
|
|
431
432
|
|
|
432
433
|
LXW_ATTRIBUTE_COPY(attribute->key, key);
|
|
433
|
-
|
|
434
|
-
#if defined(_MSC_VER)
|
|
435
|
-
lxw_snprintf(attribute->value, LXW_MAX_ATTRIBUTE_LENGTH, "%lld", value);
|
|
436
|
-
#else
|
|
437
|
-
lxw_snprintf(attribute->value, LXW_MAX_ATTRIBUTE_LENGTH, "%ld",
|
|
438
|
-
(long) value);
|
|
439
|
-
#endif
|
|
434
|
+
lxw_snprintf(attribute->value, LXW_MAX_ATTRIBUTE_LENGTH, "%d", value);
|
|
440
435
|
|
|
441
436
|
return attribute;
|
|
442
437
|
}
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
|
|
30
30
|
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
/* Linux needs this to support file operation on files larger then 4+GB
|
|
33
|
+
* But might need better if/def to select just the platforms that needs them. */
|
|
34
34
|
|
|
35
35
|
#ifndef __USE_FILE_OFFSET64
|
|
36
36
|
#define __USE_FILE_OFFSET64
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
#if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
|
|
67
67
|
#define ftello64 _ftelli64
|
|
68
68
|
#define fseeko64 _fseeki64
|
|
69
|
-
#else
|
|
69
|
+
#else /* old MSC */
|
|
70
70
|
#define ftello64 ftell
|
|
71
71
|
#define fseeko64 fseek
|
|
72
72
|
#endif
|
|
@@ -150,7 +150,7 @@ typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream)
|
|
|
150
150
|
typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin);
|
|
151
151
|
|
|
152
152
|
|
|
153
|
-
/* here is the "old" 32 bits structure
|
|
153
|
+
/* here is the "old" 32 bits structure */
|
|
154
154
|
typedef struct zlib_filefunc_def_s
|
|
155
155
|
{
|
|
156
156
|
open_file_func zopen_file;
|
|
@@ -194,8 +194,8 @@ typedef struct zlib_filefunc64_32_def_s
|
|
|
194
194
|
|
|
195
195
|
#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
|
|
196
196
|
#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
/* #define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) */
|
|
198
|
+
/* #define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) */
|
|
199
199
|
#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
|
|
200
200
|
#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
|
|
201
201
|
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
|
|
80
80
|
/* change_file_date : change the date/time of a file
|
|
81
81
|
filename : the filename of the file where date/time must be modified
|
|
82
|
-
dosdate : the new date at the
|
|
82
|
+
dosdate : the new date at the MSDOS format (4 bytes)
|
|
83
83
|
tmu_date : the SAME new date at the tm_unz format */
|
|
84
84
|
static void change_file_date(const char *filename, uLong dosdate, tm_unz tmu_date) {
|
|
85
85
|
#ifdef _WIN32
|
|
@@ -186,7 +186,7 @@ static int makedir(const char *newdir) {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
static void do_banner(void) {
|
|
189
|
-
printf("MiniUnz 1.
|
|
189
|
+
printf("MiniUnz 1.1, demo of zLib + Unz package written by Gilles Vollant\n");
|
|
190
190
|
printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n");
|
|
191
191
|
}
|
|
192
192
|
|
|
@@ -356,6 +356,20 @@ static int do_extract_currentfile(unzFile uf, const int* popt_extract_without_pa
|
|
|
356
356
|
else
|
|
357
357
|
write_filename = filename_withoutpath;
|
|
358
358
|
|
|
359
|
+
if (write_filename[0]!='\0')
|
|
360
|
+
{
|
|
361
|
+
const char* relative_check = write_filename;
|
|
362
|
+
while (relative_check[1]!='\0')
|
|
363
|
+
{
|
|
364
|
+
if (relative_check[0]=='.' && relative_check[1]=='.')
|
|
365
|
+
write_filename = relative_check;
|
|
366
|
+
relative_check++;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
while (write_filename[0]=='/' || write_filename[0]=='.')
|
|
371
|
+
write_filename++;
|
|
372
|
+
|
|
359
373
|
err = unzOpenCurrentFilePassword(uf,password);
|
|
360
374
|
if (err!=UNZ_OK)
|
|
361
375
|
{
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
const char unz_copyright[] =
|
|
118
118
|
" unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
|
|
119
119
|
|
|
120
|
-
/*
|
|
120
|
+
/* unz_file_info64_internal contain internal info about a file in zipfile*/
|
|
121
121
|
typedef struct unz_file_info64_internal_s
|
|
122
122
|
{
|
|
123
123
|
ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
|
|
@@ -450,7 +450,7 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
|
|
|
450
450
|
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
|
|
451
451
|
return CENTRALDIRINVALID;
|
|
452
452
|
|
|
453
|
-
/* number of the disk with the start of the zip64 end of
|
|
453
|
+
/* number of the disk with the start of the zip64 end of central directory */
|
|
454
454
|
if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
|
|
455
455
|
return CENTRALDIRINVALID;
|
|
456
456
|
if (uL != 0)
|
|
@@ -497,9 +497,9 @@ local unzFile unzOpenInternal(const void *path,
|
|
|
497
497
|
ZPOS64_T central_pos;
|
|
498
498
|
uLong uL;
|
|
499
499
|
|
|
500
|
-
uLong number_disk; /* number of the current
|
|
500
|
+
uLong number_disk; /* number of the current disk, used for
|
|
501
501
|
spanning ZIP, unsupported, always 0*/
|
|
502
|
-
uLong number_disk_with_CD; /* number the
|
|
502
|
+
uLong number_disk_with_CD; /* number the disk with central dir, used
|
|
503
503
|
for spanning ZIP, unsupported, always 0*/
|
|
504
504
|
ZPOS64_T number_entry_CD; /* total number of entries in
|
|
505
505
|
the central dir
|
|
@@ -306,7 +306,7 @@ extern int ZEXPORT unzGetCurrentFileInfo(unzFile file,
|
|
|
306
306
|
Get Info about the current file
|
|
307
307
|
if pfile_info!=NULL, the *pfile_info structure will contain some info about
|
|
308
308
|
the current file
|
|
309
|
-
if szFileName!=NULL, the
|
|
309
|
+
if szFileName!=NULL, the filename string will be copied in szFileName
|
|
310
310
|
(fileNameBufferSize is the size of the buffer)
|
|
311
311
|
if extraField!=NULL, the extra field information will be copied in extraField
|
|
312
312
|
(extraFieldBufferSize is the size of the buffer).
|
|
@@ -575,7 +575,7 @@ local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
|
|
|
575
575
|
if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
|
|
576
576
|
return 0;
|
|
577
577
|
|
|
578
|
-
/* number of the disk with the start of the zip64 end of
|
|
578
|
+
/* number of the disk with the start of the zip64 end of central directory */
|
|
579
579
|
if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
|
|
580
580
|
return 0;
|
|
581
581
|
if (uL != 0)
|
|
@@ -614,9 +614,9 @@ local int LoadCentralDirectoryRecord(zip64_internal* pziinit) {
|
|
|
614
614
|
ZPOS64_T central_pos;
|
|
615
615
|
uLong uL;
|
|
616
616
|
|
|
617
|
-
uLong number_disk; /* number of the current
|
|
617
|
+
uLong number_disk; /* number of the current disk, used for
|
|
618
618
|
spanning ZIP, unsupported, always 0*/
|
|
619
|
-
uLong number_disk_with_CD; /* number
|
|
619
|
+
uLong number_disk_with_CD; /* number of the disk with central dir, used
|
|
620
620
|
for spanning ZIP, unsupported, always 0*/
|
|
621
621
|
ZPOS64_T number_entry;
|
|
622
622
|
ZPOS64_T number_entry_CD; /* total number of entries in
|
|
@@ -1608,7 +1608,7 @@ extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_si
|
|
|
1608
1608
|
|
|
1609
1609
|
if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree)
|
|
1610
1610
|
{
|
|
1611
|
-
// we
|
|
1611
|
+
// we cannot write more data to the buffer that we have room for.
|
|
1612
1612
|
return ZIP_BADZIPFILE;
|
|
1613
1613
|
}
|
|
1614
1614
|
|
|
@@ -1872,7 +1872,7 @@ extern int ZEXPORT zipClose(zipFile file, const char* global_comment) {
|
|
|
1872
1872
|
free_linkedlist(&(zi->central_dir));
|
|
1873
1873
|
|
|
1874
1874
|
pos = centraldir_pos_inzip - zi->add_position_when_writing_offset;
|
|
1875
|
-
if(pos >= 0xffffffff || zi->number_entry
|
|
1875
|
+
if(pos >= 0xffffffff || zi->number_entry >= 0xFFFF)
|
|
1876
1876
|
{
|
|
1877
1877
|
ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream);
|
|
1878
1878
|
Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
extern "C" {
|
|
50
50
|
#endif
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
/* #define HAVE_BZIP2 */
|
|
53
53
|
|
|
54
54
|
#ifndef _ZLIB_H
|
|
55
55
|
#include "zlib.h"
|
|
@@ -190,9 +190,9 @@ extern int ZEXPORT zipOpenNewFileInZip64(zipFile file,
|
|
|
190
190
|
filename : the filename in zip (if NULL, '-' without quote will be used
|
|
191
191
|
*zipfi contain supplemental information
|
|
192
192
|
if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
|
|
193
|
-
contains the extrafield data
|
|
193
|
+
contains the extrafield data for the local header
|
|
194
194
|
if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
|
|
195
|
-
contains the extrafield data
|
|
195
|
+
contains the extrafield data for the global header
|
|
196
196
|
if comment != NULL, comment contain the comment string
|
|
197
197
|
method contain the compression method (0 for store, Z_DEFLATED for deflate)
|
|
198
198
|
level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
|
data/libxlsxwriter/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
2026-10-19 01:47:16 +0400 db95245
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require_relative 'test_helper'
|
|
2
|
+
|
|
3
|
+
describe "FastExcel.color_to_hex" do
|
|
4
|
+
it "should convert hex number color to hex" do
|
|
5
|
+
assert_equal(FastExcel.color_to_hex(0xFF0000), 0xFF0000)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "should convert color name to hex" do
|
|
9
|
+
assert_equal(FastExcel.color_to_hex("color_lime"), 0x00FF00)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should convert color name (extra colors) to hex" do
|
|
13
|
+
assert_equal(FastExcel.color_to_hex("steel_blue"), 0x4682B4)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require_relative 'test_helper'
|
|
2
|
+
|
|
3
|
+
describe 'FastExcel::Worksheet write_comment_opt' do
|
|
4
|
+
let(:workbook) { FastExcel.open(constant_memory: true) }
|
|
5
|
+
let(:worksheet) { workbook.add_worksheet }
|
|
6
|
+
let(:options) do
|
|
7
|
+
Libxlsxwriter::CommentOptions.new.tap do |opts|
|
|
8
|
+
opts.author = 'Lolo'
|
|
9
|
+
opts.visible = 1
|
|
10
|
+
opts.width = 200
|
|
11
|
+
opts.height = 100
|
|
12
|
+
opts.x_scale = 1.5
|
|
13
|
+
opts.y_scale = 1.5
|
|
14
|
+
opts.color = '0xFFFF00'
|
|
15
|
+
opts.font_name = 'Arial'
|
|
16
|
+
opts.font_size = 12.0
|
|
17
|
+
opts.font_family = 2
|
|
18
|
+
opts.start_row = 0
|
|
19
|
+
opts.start_col = 1
|
|
20
|
+
opts.x_offset = 10
|
|
21
|
+
opts.y_offset = 10
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should write a comment with options struct' do
|
|
26
|
+
assert_equal(:no_error, worksheet.write_comment_opt(0, 0, 'Hello with options', options))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'should write a comment with hash options' do
|
|
30
|
+
assert_equal(:no_error, worksheet.write_comment_opt(1, 0, 'Comment via hash', author: 'Author1', visible: 1, color: '#FF0000'))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'should write a comment using write_comment with optional options' do
|
|
34
|
+
assert_equal(:no_error, worksheet.write_comment(2, 0, 'Simple comment'))
|
|
35
|
+
assert_equal(:no_error, worksheet.write_comment(3, 0, 'Comment with hash', author: 'Alice', color: 'lime'))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'handles nil author and font_name safely' do
|
|
39
|
+
opts = Libxlsxwriter::CommentOptions.new
|
|
40
|
+
opts.author = nil
|
|
41
|
+
opts.font_name = nil
|
|
42
|
+
assert_nil opts.author
|
|
43
|
+
assert_nil opts.font_name
|
|
44
|
+
|
|
45
|
+
opts.author = 'Bob'
|
|
46
|
+
assert_equal 'Bob', opts.author
|
|
47
|
+
opts.author = nil
|
|
48
|
+
assert_nil opts.author
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'preserves string pointers across garbage collection' do
|
|
52
|
+
opts = Libxlsxwriter::CommentOptions.new(author: "Temporary #{rand} Author", font_name: 'Courier New')
|
|
53
|
+
# Run full GC cycles to ensure MemoryPointer is not collected prematurely
|
|
54
|
+
10.times { GC.start }
|
|
55
|
+
|
|
56
|
+
assert opts.author.start_with?('Temporary')
|
|
57
|
+
assert_equal 'Courier New', opts.font_name
|
|
58
|
+
assert_equal :no_error, worksheet.write_comment_opt(4, 0, 'GC test comment', opts)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'generates a valid excel file with styled comments' do
|
|
62
|
+
temp_file = File.join(Dir.tmpdir, "test_comments_#{Time.now.to_i}.xlsx")
|
|
63
|
+
begin
|
|
64
|
+
wb = FastExcel.open(temp_file)
|
|
65
|
+
ws = wb.add_worksheet
|
|
66
|
+
ws.write_value(0, 0, 'Data')
|
|
67
|
+
ws.write_comment(0, 0, 'Styled comment', author: 'Tester', visible: 1, color: 'yellow', font_name: 'Arial')
|
|
68
|
+
wb.close
|
|
69
|
+
|
|
70
|
+
assert File.exist?(temp_file)
|
|
71
|
+
assert File.size(temp_file) > 0
|
|
72
|
+
ensure
|
|
73
|
+
File.delete(temp_file) if File.exist?(temp_file)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
data/test/date_test.rb
CHANGED
|
@@ -54,3 +54,17 @@ describe "FastExcel.write_value" do
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
end
|
|
57
|
+
|
|
58
|
+
describe "FastExcel.lxw_time" do
|
|
59
|
+
it "should make Libxlsxwriter::Datetime" do
|
|
60
|
+
time = Time.at(610421163).utc
|
|
61
|
+
lxw_time = FastExcel.lxw_time(time)
|
|
62
|
+
|
|
63
|
+
assert_equal(lxw_time[:year], 1989)
|
|
64
|
+
assert_equal(lxw_time[:month], 5)
|
|
65
|
+
assert_equal(lxw_time[:day], 6)
|
|
66
|
+
assert_equal(lxw_time[:hour], 1)
|
|
67
|
+
assert_equal(lxw_time[:min], 26)
|
|
68
|
+
assert_equal(lxw_time[:sec], 3.0)
|
|
69
|
+
end
|
|
70
|
+
end
|
data/test/format_test.rb
CHANGED
|
@@ -112,7 +112,11 @@ describe "FastExcel::FormatExt colors" do
|
|
|
112
112
|
@format.font_color = {aaa: 1}
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
if error.message =~ /=>/
|
|
116
|
+
assert_equal(error.message, "Can not use Hash ({:aaa=>1}) for color value, expected String or Hex Number")
|
|
117
|
+
else
|
|
118
|
+
assert_equal(error.message, "Can not use Hash ({aaa: 1}) for color value, expected String or Hex Number")
|
|
119
|
+
end
|
|
116
120
|
end
|
|
117
121
|
|
|
118
122
|
it "should raise for unexpected color" do
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require_relative 'test_helper'
|
|
2
|
+
|
|
3
|
+
describe "FastExcel::Worksheet" do
|
|
4
|
+
before do
|
|
5
|
+
@workbook = FastExcel.open(constant_memory: true)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe "#get_worksheet_by_name" do
|
|
9
|
+
it "should return nil if worksheet does not exist" do
|
|
10
|
+
ws = @workbook.get_worksheet_by_name("Page1")
|
|
11
|
+
assert_nil(ws)
|
|
12
|
+
|
|
13
|
+
assert_nil(@workbook.get_worksheet_by_name(nil))
|
|
14
|
+
assert_nil(@workbook.get_worksheet_by_name(:Page1))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should return worksheet if worksheet does exist" do
|
|
18
|
+
@workbook.add_worksheet("Page1")
|
|
19
|
+
|
|
20
|
+
ws = @workbook.get_worksheet_by_name("Page1")
|
|
21
|
+
ws.write_row(0, ['1'])
|
|
22
|
+
assert_kind_of(Libxlsxwriter::Worksheet, ws)
|
|
23
|
+
|
|
24
|
+
ws_by_sym = @workbook.get_worksheet_by_name(:Page1)
|
|
25
|
+
assert_kind_of(Libxlsxwriter::Worksheet, ws_by_sym)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/test/test_helper.rb
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
require "simplecov"
|
|
2
|
+
|
|
3
|
+
SimpleCov.start do
|
|
4
|
+
add_filter 'test'
|
|
5
|
+
end
|
|
6
|
+
|
|
1
7
|
require 'bundler/setup'
|
|
2
8
|
require 'minitest/autorun'
|
|
3
9
|
require "minitest/reporters"
|
|
4
10
|
require 'pp'
|
|
5
|
-
|
|
6
|
-
##Encoding.default_external = Encoding::UTF_8
|
|
7
|
-
##Encoding.default_internal = Encoding::UTF_8
|
|
8
|
-
|
|
9
11
|
require 'date'
|
|
10
12
|
|
|
13
|
+
|
|
11
14
|
Minitest::Reporters.use!(
|
|
12
15
|
Minitest::Reporters::DefaultReporter.new(color: true)
|
|
13
16
|
)
|
data/test/tmpdir_test.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require_relative 'test_helper'
|
|
2
|
+
require 'tmpdir'
|
|
3
|
+
|
|
4
|
+
describe "FastExcel tmpdir option" do
|
|
5
|
+
it "uses system Dir.tmpdir by default without creating extra temp directories" do
|
|
6
|
+
temp_file = File.join(Dir.tmpdir, "test_default_tmpdir_#{Time.now.to_i}.xlsx")
|
|
7
|
+
begin
|
|
8
|
+
wb = FastExcel.open(temp_file, constant_memory: true)
|
|
9
|
+
ws = wb.add_worksheet
|
|
10
|
+
ws.append_row(["test", 123])
|
|
11
|
+
wb.close
|
|
12
|
+
|
|
13
|
+
assert File.exist?(temp_file)
|
|
14
|
+
assert File.size(temp_file) > 0
|
|
15
|
+
ensure
|
|
16
|
+
File.delete(temp_file) if File.exist?(temp_file)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "accepts custom tmpdir option" do
|
|
21
|
+
Dir.mktmpdir do |custom_tmp|
|
|
22
|
+
temp_file = File.join(custom_tmp, "test_custom_tmpdir.xlsx")
|
|
23
|
+
wb = FastExcel.open(temp_file, constant_memory: true, tmpdir: custom_tmp)
|
|
24
|
+
ws = wb.add_worksheet
|
|
25
|
+
ws.append_row(["hello", "world"])
|
|
26
|
+
wb.close
|
|
27
|
+
|
|
28
|
+
assert File.exist?(temp_file)
|
|
29
|
+
assert File.size(temp_file) > 0
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/test/validations_test.rb
CHANGED
|
@@ -2,23 +2,23 @@ require_relative 'test_helper'
|
|
|
2
2
|
|
|
3
3
|
describe "FastExcel validations" do
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
workbook = FastExcel.open(constant_memory: true)
|
|
5
|
+
before do
|
|
6
|
+
@workbook = FastExcel.open(constant_memory: true)
|
|
7
|
+
end
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
it "should raise error when duplicate sheet name" do
|
|
10
|
+
@workbook.add_worksheet("Payments Report")
|
|
9
11
|
error = assert_raises do
|
|
10
|
-
workbook.add_worksheet("Payments Report")
|
|
12
|
+
@workbook.add_worksheet("Payments Report")
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
assert_equal(ArgumentError, error.class)
|
|
14
|
-
assert_equal("Invalid worksheet name 'Payments Report': (
|
|
16
|
+
assert_equal("Invalid worksheet name 'Payments Report': (19 - error_sheetname_already_used) Worksheet name is already in use.", error.message)
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
it "should not raise error when worksheet name is null" do
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
ws1 = workbook.add_worksheet()
|
|
21
|
-
ws2 = workbook.add_worksheet()
|
|
20
|
+
ws1 = @workbook.add_worksheet()
|
|
21
|
+
ws2 = @workbook.add_worksheet()
|
|
22
22
|
ws2.write_value(0, 2, "aaa")
|
|
23
23
|
|
|
24
24
|
assert_equal("Sheet1", ws1[:name])
|
|
@@ -26,33 +26,39 @@ describe "FastExcel validations" do
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
it "should raise error when the sheet name exceeds maximum length" do
|
|
29
|
-
workbook = FastExcel.open(constant_memory: true)
|
|
30
|
-
|
|
31
29
|
error = assert_raises do
|
|
32
|
-
workbook.add_worksheet("ABCDEFGHIJKLMNOPQRSTUVWXYZ012345")
|
|
30
|
+
@workbook.add_worksheet("ABCDEFGHIJKLMNOPQRSTUVWXYZ012345")
|
|
33
31
|
end
|
|
34
32
|
|
|
35
33
|
assert_equal(ArgumentError, error.class)
|
|
36
|
-
assert_equal("Invalid worksheet name 'ABCDEFGHIJKLMNOPQRSTUVWXYZ012345': (
|
|
34
|
+
assert_equal("Invalid worksheet name 'ABCDEFGHIJKLMNOPQRSTUVWXYZ012345': (16 - error_sheetname_length_exceeded) Worksheet name exceeds Excel's limit of 31 characters.", error.message)
|
|
37
35
|
end
|
|
38
36
|
|
|
39
37
|
it "should not raise error when the sheet name is at maximum length" do
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
worksheet = workbook.add_worksheet("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234")
|
|
38
|
+
worksheet = @workbook.add_worksheet("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234")
|
|
43
39
|
worksheet.append_row(["aaa", "bbb", "ccc"])
|
|
44
40
|
|
|
45
41
|
assert_equal("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234", worksheet[:name])
|
|
46
42
|
end
|
|
47
43
|
|
|
48
44
|
it "should validate using Libxlsxwriter validation" do
|
|
49
|
-
workbook = FastExcel.open(constant_memory: true)
|
|
50
45
|
error = assert_raises do
|
|
51
|
-
worksheet = workbook.add_worksheet('a?')
|
|
46
|
+
worksheet = @workbook.add_worksheet('a?')
|
|
52
47
|
worksheet.write_value(1, 1, 'a') # without the validation, this method will crash the process
|
|
53
48
|
end
|
|
54
49
|
|
|
55
50
|
assert_equal(ArgumentError, error.class)
|
|
56
|
-
assert_equal("Invalid worksheet name 'a?': (
|
|
51
|
+
assert_equal("Invalid worksheet name 'a?': (17 - error_invalid_sheetname_character) Worksheet name cannot contain invalid characters: '[ ] : * ? / \\'", error.message)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should raise error when reopening workbook" do
|
|
55
|
+
@workbook.close
|
|
56
|
+
|
|
57
|
+
error = assert_raises do
|
|
58
|
+
FastExcel.open(@workbook.filename, constant_memory: true)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
assert_equal(error.class, ArgumentError)
|
|
62
|
+
assert_equal(error.message, "File '#{@workbook.filename}' already exists. FastExcel can not open existing files, only create new files")
|
|
57
63
|
end
|
|
58
64
|
end
|
data/test/worksheet_test.rb
CHANGED
|
@@ -87,10 +87,18 @@ describe "FastExcel::WorksheetExt append_row" do
|
|
|
87
87
|
it "should set name correctly" do
|
|
88
88
|
workbook = FastExcel.open(constant_memory: true)
|
|
89
89
|
ws1 = workbook.add_worksheet("foo")
|
|
90
|
-
ws2 = workbook.add_worksheet
|
|
90
|
+
ws2 = workbook.add_worksheet
|
|
91
91
|
|
|
92
92
|
assert_equal("foo", ws1[:name])
|
|
93
|
-
assert_equal("", ws2[:name])
|
|
93
|
+
assert_equal("Sheet2", ws2[:name])
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "should raise error when sheet name is empty string" do
|
|
97
|
+
workbook = FastExcel.open(constant_memory: true)
|
|
98
|
+
error = assert_raises(ArgumentError) do
|
|
99
|
+
workbook.add_worksheet("")
|
|
100
|
+
end
|
|
101
|
+
assert_match(/error_parameter_is_empty/, error.message)
|
|
94
102
|
end
|
|
95
103
|
|
|
96
104
|
it "should map fields correctly" do
|