mirror of
https://github.com/jmcnamara/libxlsxwriter
synced 2025-03-28 21:13:14 +00:00
Add memory buffer support
* Avoid using temporary files when possible * Add support for writing to a buffer PR #382
This commit is contained in:
parent
07c67b504c
commit
5097c0e41f
2
.github/workflows/cmake_actions.yml
vendored
2
.github/workflows/cmake_actions.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
cmake_flags: ["",
|
||||
"-DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON",
|
||||
"-DUSE_DTOA_LIBRARY=ON -DBUILD_TESTS=ON",
|
||||
"-DUSE_FMEMOPEN=ON -DBUILD_TESTS=ON",
|
||||
"-DUSE_MEM_FILE=ON -DBUILD_TESTS=ON",
|
||||
"-DUSE_NO_MD5=ON -DBUILD_TESTS=ON",
|
||||
"-DUSE_OPENSSL_MD5=ON -DBUILD_TESTS=ON",
|
||||
"-DUSE_STANDARD_TMPFILE=ON -DBUILD_TESTS=ON",
|
||||
|
2
.github/workflows/make_actions.yml
vendored
2
.github/workflows/make_actions.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
"USE_DTOA_LIBRARY=1",
|
||||
"USE_NO_MD5=1",
|
||||
"USE_OPENSSL_MD5=1",
|
||||
"USE_FMEMOPEN=1"]
|
||||
"USE_MEM_FILE=1"]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CC: ${{ matrix.cc }}
|
||||
|
@ -131,7 +131,7 @@ option(USE_SYSTEM_MINIZIP "Use system minizip installation" OFF)
|
||||
option(USE_STANDARD_TMPFILE "Use the C standard library's tmpfile()" OFF)
|
||||
option(USE_NO_MD5 "Build libxlsxwriter without third party MD5 lib" OFF)
|
||||
option(USE_OPENSSL_MD5 "Build libxlsxwriter with the OpenSSL MD5 lib" OFF)
|
||||
option(USE_FMEMOPEN "Use fmemopen() in place of some temporary files" OFF)
|
||||
option(USE_MEM_FILE "Use fmemopen()/open_memstream() in place of temporary files" OFF)
|
||||
option(IOAPI_NO_64 "Disable 64-bit filesystem support" OFF)
|
||||
option(USE_DTOA_LIBRARY "Use the locale independent third party Milo Yip DTOA library" OFF)
|
||||
|
||||
@ -165,7 +165,7 @@ if(USE_OPENSSL_MD5)
|
||||
list(APPEND LXW_PRIVATE_COMPILE_DEFINITIONS USE_OPENSSL_MD5)
|
||||
endif()
|
||||
|
||||
if(USE_FMEMOPEN)
|
||||
if(USE_MEM_FILE OR USE_FMEMOPEN)
|
||||
list(APPEND LXW_PRIVATE_COMPILE_DEFINITIONS USE_FMEMOPEN)
|
||||
endif()
|
||||
|
||||
|
@ -165,7 +165,7 @@ have to provide explicit `include` and `lib` paths:
|
||||
cc myexcel.c -o myexcel -I/usr/local/include -L/usr/local/lib -lxlsxwriter
|
||||
|
||||
You can also use
|
||||
[pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/)
|
||||
[pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/)
|
||||
(after installation of the library) to automatically determine the required
|
||||
arguments and paths:
|
||||
|
||||
@ -536,21 +536,21 @@ with larger CMake builds. In particular it enables building on Windows.
|
||||
|
||||
The following are various compilation targets and options for both build systems:
|
||||
|
||||
| Make | CMake | Description |
|
||||
| :----------------------- | :----------------------------------------- | :---------------------------------- |
|
||||
| `examples` | `-DBUILD_EXAMPLES=ON` | Build the example |
|
||||
| `test` | `-DBUILD_TESTS=ON` | Build the tests |
|
||||
| `USE_DTOA_LIBRARY=1` | `-DUSE_DTOA_LIBRARY=ON` | Use alternative double in sprintf |
|
||||
| `USE_FMEMOPEN=1` | `-DUSE_FMEMOPEN=ON` | Use fmemopen() for temp image files |
|
||||
| `USE_OPENSSL_MD5=1` | `-DUSE_OPENSSL_MD5=ON` | Use OpenSSL for MD5 digest |
|
||||
| `USE_NO_MD5=1` | `-DUSE_NO_MD5=ON` | Don't use a MD5 digest |
|
||||
| `USE_SYSTEM_MINIZIP=1` | `-DUSE_SYSTEM_MINIZIP=ON` | Use system minzip library |
|
||||
| `USE_STANDARD_TMPFILE=1` | `-DUSE_STANDARD_TMPFILE=ON` | Use system tmpfile() function |
|
||||
| `USE_BIG_ENDIAN=1` | `-DUSE_BIG_ENDIAN=ON` | Build on big endian systems |
|
||||
| `universal_binary` | `-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"` | Create a macOS "Universal Binary" |
|
||||
| | `-DBUILD_SHARED_LIBS=ON` | Build shared library (default on) |
|
||||
| | `-DUSE_STATIC_MSVC_RUNTIME=ON` | Use static msvc runtime library |
|
||||
| | `-DCMAKE_BUILD_TYPE=Release` | Set the build type. |
|
||||
| Make | CMake | Description |
|
||||
| :----------------------- | :----------------------------------------- | :---------------------------------------------------- |
|
||||
| `examples` | `-DBUILD_EXAMPLES=ON` | Build the example |
|
||||
| `test` | `-DBUILD_TESTS=ON` | Build the tests |
|
||||
| `USE_DTOA_LIBRARY=1` | `-DUSE_DTOA_LIBRARY=ON` | Use alternative double in sprintf |
|
||||
| `USE_MEM_FILE=1` | `-DUSE_MEM_FILE=ON` | Use fmemopen()/open_memstream() instead of temp files |
|
||||
| `USE_OPENSSL_MD5=1` | `-DUSE_OPENSSL_MD5=ON` | Use OpenSSL for MD5 digest |
|
||||
| `USE_NO_MD5=1` | `-DUSE_NO_MD5=ON` | Don't use a MD5 digest |
|
||||
| `USE_SYSTEM_MINIZIP=1` | `-DUSE_SYSTEM_MINIZIP=ON` | Use system minzip library |
|
||||
| `USE_STANDARD_TMPFILE=1` | `-DUSE_STANDARD_TMPFILE=ON` | Use system tmpfile() function |
|
||||
| `USE_BIG_ENDIAN=1` | `-DUSE_BIG_ENDIAN=ON` | Build on big endian systems |
|
||||
| `universal_binary` | `-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"` | Create a macOS "Universal Binary" |
|
||||
| | `-DBUILD_SHARED_LIBS=ON` | Build shared library (default on) |
|
||||
| | `-DUSE_STATIC_MSVC_RUNTIME=ON` | Use static msvc runtime library |
|
||||
| | `-DCMAKE_BUILD_TYPE=Release` | Set the build type. |
|
||||
|
||||
|
||||
The compilation options would be used as follows:
|
||||
@ -573,11 +573,8 @@ Each of the options are explained below:
|
||||
|
||||
- `USE_DTOA_LIBRARY`: See @ref gsg_dtoa "using a double formatting library".
|
||||
|
||||
- `USE_FMEMOPEN`: When inserting an image from a buffer using
|
||||
`worksheet_insert_image_buffer()` libxlsxwriter writes the buffer to a
|
||||
temporary file before processing it. In order to avoid this small overhead
|
||||
you can use this option to invoke `fmemopen()` instead. This option isn't on
|
||||
by default since it isn't supported on Windows.
|
||||
- `USE_MEM_FILE`: Use fmemopen()/open_memstream() instead of temporary files.
|
||||
This option isn't on by default since it isn't supported on Windows.
|
||||
|
||||
- `USE_OPENSSL_MD5`: Uses OpenSSL to provide a MD5 digest of image files in
|
||||
order to avoid storing duplicates. See @ref gsg_md5.
|
||||
|
@ -18,7 +18,9 @@ int main() {
|
||||
/* Set the worksheet options. */
|
||||
lxw_workbook_options options = {.constant_memory = LXW_TRUE,
|
||||
.tmpdir = NULL,
|
||||
.use_zip64 = LXW_FALSE};
|
||||
.use_zip64 = LXW_FALSE,
|
||||
.output_buffer = NULL,
|
||||
.output_buffer_size = NULL};
|
||||
|
||||
/* Create a new workbook with options. */
|
||||
lxw_workbook *workbook = workbook_new_opt("constant_memory.xlsx", &options);
|
||||
|
42
examples/output_buffer.c
Normal file
42
examples/output_buffer.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Example of using libxlsxwriter for writing a workbook file to a buffer.
|
||||
*
|
||||
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
char *output_buffer;
|
||||
size_t output_buffer_size;
|
||||
|
||||
/* Set the worksheet options. */
|
||||
lxw_workbook_options options = {.output_buffer = &output_buffer,
|
||||
.output_buffer_size = &output_buffer_size,
|
||||
.constant_memory = LXW_FALSE,
|
||||
.tmpdir = NULL,
|
||||
.use_zip64 = LXW_FALSE};
|
||||
|
||||
/* Create a new workbook with options. */
|
||||
lxw_workbook *workbook = workbook_new_opt(NULL, &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_write_string(worksheet, 0, 0, "Hello", NULL);
|
||||
worksheet_write_number(worksheet, 1, 0, 123, NULL);
|
||||
|
||||
lxw_error error = workbook_close(workbook);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Do something with the XLSX data in the output buffer. */
|
||||
FILE *file = fopen("output_buffer.xlsx", "wb");
|
||||
fwrite(output_buffer, output_buffer_size, 1, file);
|
||||
fclose(file);
|
||||
free(output_buffer);
|
||||
|
||||
return ferror(stdout);
|
||||
}
|
@ -62,10 +62,12 @@ typedef struct lxw_packager {
|
||||
lxw_workbook *workbook;
|
||||
|
||||
size_t buffer_size;
|
||||
size_t output_buffer_size;
|
||||
zipFile zipfile;
|
||||
zip_fileinfo zipfile_info;
|
||||
char *filename;
|
||||
char *buffer;
|
||||
char *output_buffer;
|
||||
char *tmpdir;
|
||||
uint8_t use_zip64;
|
||||
|
||||
|
@ -233,6 +233,7 @@ void lxw_str_tolower(char *str);
|
||||
#endif
|
||||
|
||||
FILE *lxw_tmpfile(char *tmpdir);
|
||||
FILE *lxw_get_filehandle(char **buf, size_t *size, char *tmpdir);
|
||||
FILE *lxw_fopen(const char *filename, const char *mode);
|
||||
|
||||
/* Use the third party dtoa function to avoid locale issues with sprintf
|
||||
|
@ -243,6 +243,13 @@ typedef struct lxw_doc_properties {
|
||||
* for more information. This option is off by default.
|
||||
*
|
||||
* [zip64_wiki]: https://en.wikipedia.org/wiki/Zip_(file_format)#ZIP64
|
||||
|
||||
* - `output_buffer`: Output to a buffer instead of a file. The buffer must be
|
||||
* freed manually by calling free(). This option can only be used if filename
|
||||
* is NULL.
|
||||
*
|
||||
* - `output_buffer_size`: Used with output_buffer to get the size of the
|
||||
* created buffer. This option can only be used if filename is NULL.
|
||||
*
|
||||
* @note In `constant_memory` mode each row of in-memory data is written to
|
||||
* disk and then freed when a new row is started via one of the
|
||||
@ -268,6 +275,11 @@ typedef struct lxw_workbook_options {
|
||||
/** Allow ZIP64 extensions when creating the xlsx file zip container. */
|
||||
uint8_t use_zip64;
|
||||
|
||||
/** Output buffer to use instead of writing to a file */
|
||||
char **output_buffer;
|
||||
|
||||
/** Used with output_buffer to get the size of the created buffer */
|
||||
size_t *output_buffer_size;
|
||||
} lxw_workbook_options;
|
||||
|
||||
/**
|
||||
@ -376,7 +388,9 @@ lxw_workbook *workbook_new(const char *filename);
|
||||
* @code
|
||||
* lxw_workbook_options options = {.constant_memory = LXW_TRUE,
|
||||
* .tmpdir = "C:\\Temp",
|
||||
* .use_zip64 = LXW_FALSE};
|
||||
* .use_zip64 = LXW_FALSE,
|
||||
* .output_buffer = NULL,
|
||||
* .output_buffer_size = NULL};
|
||||
*
|
||||
* lxw_workbook *workbook = workbook_new_opt("filename.xlsx", &options);
|
||||
* @endcode
|
||||
|
@ -2108,6 +2108,7 @@ typedef struct lxw_worksheet {
|
||||
|
||||
FILE *file;
|
||||
FILE *optimize_tmpfile;
|
||||
char *optimize_buffer;
|
||||
struct lxw_table_rows *table;
|
||||
struct lxw_table_rows *hyperlinks;
|
||||
struct lxw_table_rows *comments;
|
||||
|
@ -72,7 +72,11 @@ DTOA_LIB_OBJ = $(DTOA_LIB_DIR)/emyg_dtoa.o
|
||||
DTOA_LIB_SO = $(DTOA_LIB_DIR)/emyg_dtoa.so
|
||||
endif
|
||||
|
||||
# Use fmemopen() to avoid creating certain temporary files
|
||||
# Use fmemopen()/open_memstream() to avoid creating temporary files
|
||||
ifdef USE_MEM_FILE
|
||||
USE_FMEMOPEN = 1
|
||||
endif
|
||||
|
||||
ifdef USE_FMEMOPEN
|
||||
CFLAGS += -DUSE_FMEMOPEN
|
||||
endif
|
||||
|
169
src/packager.c
169
src/packager.c
@ -113,21 +113,75 @@ _open_zipfile_win32(const char *filename)
|
||||
|
||||
#endif
|
||||
|
||||
STATIC voidpf ZCALLBACK
|
||||
_fopen_memstream(voidpf opaque, const char *filename, int mode)
|
||||
{
|
||||
lxw_packager *packager = (lxw_packager *) opaque;
|
||||
(void) filename;
|
||||
(void) mode;
|
||||
return lxw_get_filehandle(&packager->output_buffer,
|
||||
&packager->output_buffer_size,
|
||||
packager->tmpdir);
|
||||
}
|
||||
|
||||
STATIC int ZCALLBACK
|
||||
_fclose_memstream(voidpf opaque, voidpf stream)
|
||||
{
|
||||
lxw_packager *packager = (lxw_packager *) opaque;
|
||||
FILE *file = (FILE *) stream;
|
||||
long size;
|
||||
|
||||
/* Ensure memstream buffer is updated */
|
||||
if (fflush(file))
|
||||
goto mem_error;
|
||||
|
||||
/* If the memstream is backed by a temporary file, no buffer is created,
|
||||
so create it manually. */
|
||||
if (!packager->output_buffer) {
|
||||
if (fseek(file, 0L, SEEK_END))
|
||||
goto mem_error;
|
||||
|
||||
size = ftell(file);
|
||||
if (size == -1)
|
||||
goto mem_error;
|
||||
|
||||
packager->output_buffer = malloc(size);
|
||||
GOTO_LABEL_ON_MEM_ERROR(packager->output_buffer, mem_error);
|
||||
|
||||
rewind(file);
|
||||
if (fread(packager->output_buffer, size, 1, file) < 1)
|
||||
goto mem_error;
|
||||
|
||||
packager->output_buffer_size = size;
|
||||
}
|
||||
|
||||
return fclose(file);
|
||||
|
||||
mem_error:
|
||||
fclose(file);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new packager object.
|
||||
*/
|
||||
lxw_packager *
|
||||
lxw_packager_new(const char *filename, char *tmpdir, uint8_t use_zip64)
|
||||
{
|
||||
zlib_filefunc_def filefunc;
|
||||
lxw_packager *packager = calloc(1, sizeof(lxw_packager));
|
||||
GOTO_LABEL_ON_MEM_ERROR(packager, mem_error);
|
||||
|
||||
packager->buffer = calloc(1, LXW_ZIP_BUFFER_SIZE);
|
||||
GOTO_LABEL_ON_MEM_ERROR(packager->buffer, mem_error);
|
||||
|
||||
packager->filename = lxw_strdup(filename);
|
||||
packager->filename = NULL;
|
||||
packager->tmpdir = tmpdir;
|
||||
GOTO_LABEL_ON_MEM_ERROR(packager->filename, mem_error);
|
||||
|
||||
if (filename) {
|
||||
packager->filename = lxw_strdup(filename);
|
||||
GOTO_LABEL_ON_MEM_ERROR(packager->filename, mem_error);
|
||||
}
|
||||
|
||||
packager->buffer_size = LXW_ZIP_BUFFER_SIZE;
|
||||
packager->use_zip64 = use_zip64;
|
||||
@ -143,12 +197,24 @@ lxw_packager_new(const char *filename, char *tmpdir, uint8_t use_zip64)
|
||||
packager->zipfile_info.internal_fa = 0;
|
||||
packager->zipfile_info.external_fa = 0;
|
||||
|
||||
packager->output_buffer = NULL;
|
||||
packager->output_buffer_size = 0;
|
||||
|
||||
/* Create a zip container for the xlsx file. */
|
||||
if (packager->filename) {
|
||||
#ifdef _WIN32
|
||||
packager->zipfile = _open_zipfile_win32(packager->filename);
|
||||
packager->zipfile = _open_zipfile_win32(packager->filename);
|
||||
#else
|
||||
packager->zipfile = zipOpen(packager->filename, 0);
|
||||
packager->zipfile = zipOpen(packager->filename, 0);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
fill_fopen_filefunc(&filefunc);
|
||||
filefunc.opaque = packager;
|
||||
filefunc.zopen_file = _fopen_memstream;
|
||||
filefunc.zclose_file = _fclose_memstream;
|
||||
packager->zipfile = zipOpen2(packager->filename, 0, NULL, &filefunc);
|
||||
}
|
||||
|
||||
if (packager->zipfile == NULL)
|
||||
goto mem_error;
|
||||
@ -188,7 +254,8 @@ _write_workbook_file(lxw_packager *self)
|
||||
lxw_workbook *workbook = self->workbook;
|
||||
lxw_error err;
|
||||
|
||||
workbook->file = lxw_tmpfile(self->tmpdir);
|
||||
char *buffer = NULL;
|
||||
workbook->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!workbook->file)
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
|
||||
@ -196,6 +263,7 @@ _write_workbook_file(lxw_packager *self)
|
||||
|
||||
err = _add_file_to_zip(self, workbook->file, "xl/workbook.xml");
|
||||
fclose(workbook->file);
|
||||
free(buffer);
|
||||
RETURN_ON_ERROR(err);
|
||||
|
||||
return LXW_NO_ERROR;
|
||||
@ -211,6 +279,7 @@ _write_worksheet_files(lxw_packager *self)
|
||||
lxw_sheet *sheet;
|
||||
lxw_worksheet *worksheet;
|
||||
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
|
||||
char *buffer = NULL;
|
||||
uint32_t index = 1;
|
||||
lxw_error err;
|
||||
|
||||
@ -226,7 +295,7 @@ _write_worksheet_files(lxw_packager *self)
|
||||
if (worksheet->optimize_row)
|
||||
lxw_worksheet_write_single_row(worksheet);
|
||||
|
||||
worksheet->file = lxw_tmpfile(self->tmpdir);
|
||||
worksheet->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!worksheet->file)
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
|
||||
@ -234,6 +303,7 @@ _write_worksheet_files(lxw_packager *self)
|
||||
|
||||
err = _add_file_to_zip(self, worksheet->file, sheetname);
|
||||
fclose(worksheet->file);
|
||||
free(buffer);
|
||||
RETURN_ON_ERROR(err);
|
||||
}
|
||||
|
||||
@ -250,6 +320,7 @@ _write_chartsheet_files(lxw_packager *self)
|
||||
lxw_sheet *sheet;
|
||||
lxw_chartsheet *chartsheet;
|
||||
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
|
||||
char *buffer = NULL;
|
||||
uint32_t index = 1;
|
||||
lxw_error err;
|
||||
|
||||
@ -262,7 +333,7 @@ _write_chartsheet_files(lxw_packager *self)
|
||||
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
|
||||
"xl/chartsheets/sheet%d.xml", index++);
|
||||
|
||||
chartsheet->file = lxw_tmpfile(self->tmpdir);
|
||||
chartsheet->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!chartsheet->file)
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
|
||||
@ -270,6 +341,7 @@ _write_chartsheet_files(lxw_packager *self)
|
||||
|
||||
err = _add_file_to_zip(self, chartsheet->file, sheetname);
|
||||
fclose(chartsheet->file);
|
||||
free(buffer);
|
||||
RETURN_ON_ERROR(err);
|
||||
}
|
||||
|
||||
@ -375,6 +447,7 @@ _write_chart_files(lxw_packager *self)
|
||||
lxw_workbook *workbook = self->workbook;
|
||||
lxw_chart *chart;
|
||||
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
|
||||
char *buffer = NULL;
|
||||
uint32_t index = 1;
|
||||
lxw_error err;
|
||||
|
||||
@ -383,7 +456,7 @@ _write_chart_files(lxw_packager *self)
|
||||
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
|
||||
"xl/charts/chart%d.xml", index++);
|
||||
|
||||
chart->file = lxw_tmpfile(self->tmpdir);
|
||||
chart->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!chart->file)
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
|
||||
@ -391,6 +464,7 @@ _write_chart_files(lxw_packager *self)
|
||||
|
||||
err = _add_file_to_zip(self, chart->file, sheetname);
|
||||
fclose(chart->file);
|
||||
free(buffer);
|
||||
RETURN_ON_ERROR(err);
|
||||
}
|
||||
|
||||
@ -425,6 +499,7 @@ _write_drawing_files(lxw_packager *self)
|
||||
lxw_worksheet *worksheet;
|
||||
lxw_drawing *drawing;
|
||||
char filename[LXW_FILENAME_LENGTH] = { 0 };
|
||||
char *buffer = NULL;
|
||||
uint32_t index = 1;
|
||||
lxw_error err;
|
||||
|
||||
@ -440,7 +515,7 @@ _write_drawing_files(lxw_packager *self)
|
||||
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
|
||||
"xl/drawings/drawing%d.xml", index++);
|
||||
|
||||
drawing->file = lxw_tmpfile(self->tmpdir);
|
||||
drawing->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!drawing->file)
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
|
||||
@ -448,6 +523,7 @@ _write_drawing_files(lxw_packager *self)
|
||||
|
||||
err = _add_file_to_zip(self, drawing->file, filename);
|
||||
fclose(drawing->file);
|
||||
free(buffer);
|
||||
RETURN_ON_ERROR(err);
|
||||
}
|
||||
}
|
||||
@ -496,6 +572,7 @@ _write_table_files(lxw_packager *self)
|
||||
lxw_error err;
|
||||
|
||||
char filename[LXW_FILENAME_LENGTH] = { 0 };
|
||||
char *buffer = NULL;
|
||||
uint32_t index = 1;
|
||||
|
||||
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
|
||||
@ -518,7 +595,7 @@ _write_table_files(lxw_packager *self)
|
||||
RETURN_ON_ERROR(err);
|
||||
}
|
||||
|
||||
table->file = lxw_tmpfile(self->tmpdir);
|
||||
table->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!table->file) {
|
||||
lxw_table_free(table);
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
@ -530,6 +607,7 @@ _write_table_files(lxw_packager *self)
|
||||
|
||||
err = _add_file_to_zip(self, table->file, filename);
|
||||
fclose(table->file);
|
||||
free(buffer);
|
||||
lxw_table_free(table);
|
||||
RETURN_ON_ERROR(err);
|
||||
}
|
||||
@ -572,6 +650,7 @@ _write_vml_files(lxw_packager *self)
|
||||
lxw_worksheet *worksheet;
|
||||
lxw_vml *vml;
|
||||
char filename[LXW_FILENAME_LENGTH] = { 0 };
|
||||
char *buffer = NULL;
|
||||
uint32_t index = 1;
|
||||
lxw_error err;
|
||||
|
||||
@ -593,7 +672,7 @@ _write_vml_files(lxw_packager *self)
|
||||
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
|
||||
"xl/drawings/vmlDrawing%d.vml", index++);
|
||||
|
||||
vml->file = lxw_tmpfile(self->tmpdir);
|
||||
vml->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!vml->file) {
|
||||
lxw_vml_free(vml);
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
@ -609,6 +688,7 @@ _write_vml_files(lxw_packager *self)
|
||||
}
|
||||
else {
|
||||
fclose(vml->file);
|
||||
free(buffer);
|
||||
lxw_vml_free(vml);
|
||||
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
}
|
||||
@ -618,6 +698,7 @@ _write_vml_files(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, vml->file, filename);
|
||||
|
||||
fclose(vml->file);
|
||||
free(buffer);
|
||||
lxw_vml_free(vml);
|
||||
|
||||
RETURN_ON_ERROR(err);
|
||||
@ -635,7 +716,7 @@ _write_vml_files(lxw_packager *self)
|
||||
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
|
||||
"xl/drawings/vmlDrawing%d.vml", index++);
|
||||
|
||||
vml->file = lxw_tmpfile(self->tmpdir);
|
||||
vml->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!vml->file) {
|
||||
lxw_vml_free(vml);
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
@ -649,6 +730,7 @@ _write_vml_files(lxw_packager *self)
|
||||
}
|
||||
else {
|
||||
fclose(vml->file);
|
||||
free(buffer);
|
||||
lxw_vml_free(vml);
|
||||
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
}
|
||||
@ -658,6 +740,7 @@ _write_vml_files(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, vml->file, filename);
|
||||
|
||||
fclose(vml->file);
|
||||
free(buffer);
|
||||
lxw_vml_free(vml);
|
||||
|
||||
RETURN_ON_ERROR(err);
|
||||
@ -678,6 +761,7 @@ _write_comment_files(lxw_packager *self)
|
||||
lxw_worksheet *worksheet;
|
||||
lxw_comment *comment;
|
||||
char filename[LXW_FILENAME_LENGTH] = { 0 };
|
||||
char *buffer = NULL;
|
||||
uint32_t index = 1;
|
||||
lxw_error err;
|
||||
|
||||
@ -697,7 +781,7 @@ _write_comment_files(lxw_packager *self)
|
||||
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
|
||||
"xl/comments%d.xml", index++);
|
||||
|
||||
comment->file = lxw_tmpfile(self->tmpdir);
|
||||
comment->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!comment->file) {
|
||||
lxw_comment_free(comment);
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
@ -711,6 +795,7 @@ _write_comment_files(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, comment->file, filename);
|
||||
|
||||
fclose(comment->file);
|
||||
free(buffer);
|
||||
lxw_comment_free(comment);
|
||||
|
||||
RETURN_ON_ERROR(err);
|
||||
@ -726,13 +811,14 @@ STATIC lxw_error
|
||||
_write_shared_strings_file(lxw_packager *self)
|
||||
{
|
||||
lxw_sst *sst = self->workbook->sst;
|
||||
char *buffer = NULL;
|
||||
lxw_error err;
|
||||
|
||||
/* Skip the sharedStrings file if there are no shared strings. */
|
||||
if (!sst->string_count)
|
||||
return LXW_NO_ERROR;
|
||||
|
||||
sst->file = lxw_tmpfile(self->tmpdir);
|
||||
sst->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!sst->file)
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
|
||||
@ -740,6 +826,7 @@ _write_shared_strings_file(lxw_packager *self)
|
||||
|
||||
err = _add_file_to_zip(self, sst->file, "xl/sharedStrings.xml");
|
||||
fclose(sst->file);
|
||||
free(buffer);
|
||||
RETURN_ON_ERROR(err);
|
||||
|
||||
return LXW_NO_ERROR;
|
||||
@ -757,6 +844,7 @@ _write_app_file(lxw_packager *self)
|
||||
lxw_chartsheet *chartsheet;
|
||||
lxw_defined_name *defined_name;
|
||||
lxw_app *app;
|
||||
char *buffer = NULL;
|
||||
uint32_t named_range_count = 0;
|
||||
char *autofilter;
|
||||
char *has_range;
|
||||
@ -769,7 +857,7 @@ _write_app_file(lxw_packager *self)
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
app->file = lxw_tmpfile(self->tmpdir);
|
||||
app->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!app->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
@ -830,6 +918,7 @@ _write_app_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, app->file, "docProps/app.xml");
|
||||
|
||||
fclose(app->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_app_free(app);
|
||||
@ -845,13 +934,14 @@ _write_core_file(lxw_packager *self)
|
||||
{
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
lxw_core *core = lxw_core_new();
|
||||
char *buffer = NULL;
|
||||
|
||||
if (!core) {
|
||||
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
core->file = lxw_tmpfile(self->tmpdir);
|
||||
core->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!core->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
@ -864,6 +954,7 @@ _write_core_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, core->file, "docProps/core.xml");
|
||||
|
||||
fclose(core->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_core_free(core);
|
||||
@ -879,6 +970,7 @@ _write_metadata_file(lxw_packager *self)
|
||||
{
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
lxw_metadata *metadata;
|
||||
char *buffer = NULL;
|
||||
|
||||
if (!self->workbook->has_metadata)
|
||||
return LXW_NO_ERROR;
|
||||
@ -890,7 +982,7 @@ _write_metadata_file(lxw_packager *self)
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
metadata->file = lxw_tmpfile(self->tmpdir);
|
||||
metadata->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!metadata->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
@ -901,6 +993,7 @@ _write_metadata_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, metadata->file, "xl/metadata.xml");
|
||||
|
||||
fclose(metadata->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_metadata_free(metadata);
|
||||
@ -915,6 +1008,7 @@ STATIC lxw_error
|
||||
_write_custom_file(lxw_packager *self)
|
||||
{
|
||||
lxw_custom *custom;
|
||||
char *buffer = NULL;
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
|
||||
if (STAILQ_EMPTY(self->workbook->custom_properties))
|
||||
@ -926,7 +1020,7 @@ _write_custom_file(lxw_packager *self)
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
custom->file = lxw_tmpfile(self->tmpdir);
|
||||
custom->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!custom->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
@ -939,6 +1033,7 @@ _write_custom_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, custom->file, "docProps/custom.xml");
|
||||
|
||||
fclose(custom->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_custom_free(custom);
|
||||
@ -953,13 +1048,14 @@ _write_theme_file(lxw_packager *self)
|
||||
{
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
lxw_theme *theme = lxw_theme_new();
|
||||
char *buffer = NULL;
|
||||
|
||||
if (!theme) {
|
||||
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
theme->file = lxw_tmpfile(self->tmpdir);
|
||||
theme->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!theme->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
@ -970,6 +1066,7 @@ _write_theme_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, theme->file, "xl/theme/theme1.xml");
|
||||
|
||||
fclose(theme->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_theme_free(theme);
|
||||
@ -984,6 +1081,7 @@ STATIC lxw_error
|
||||
_write_styles_file(lxw_packager *self)
|
||||
{
|
||||
lxw_styles *styles = lxw_styles_new();
|
||||
char *buffer = NULL;
|
||||
lxw_hash_element *hash_element;
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
|
||||
@ -1030,7 +1128,7 @@ _write_styles_file(lxw_packager *self)
|
||||
styles->dxf_count = self->workbook->used_dxf_formats->unique_count;
|
||||
styles->has_comments = self->workbook->has_comments;
|
||||
|
||||
styles->file = lxw_tmpfile(self->tmpdir);
|
||||
styles->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!styles->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
@ -1041,6 +1139,7 @@ _write_styles_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, styles->file, "xl/styles.xml");
|
||||
|
||||
fclose(styles->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_styles_free(styles);
|
||||
@ -1055,6 +1154,7 @@ STATIC lxw_error
|
||||
_write_content_types_file(lxw_packager *self)
|
||||
{
|
||||
lxw_content_types *content_types = lxw_content_types_new();
|
||||
char *buffer = NULL;
|
||||
lxw_workbook *workbook = self->workbook;
|
||||
lxw_sheet *sheet;
|
||||
char filename[LXW_MAX_ATTRIBUTE_LENGTH] = { 0 };
|
||||
@ -1071,7 +1171,7 @@ _write_content_types_file(lxw_packager *self)
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
content_types->file = lxw_tmpfile(self->tmpdir);
|
||||
content_types->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!content_types->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
@ -1154,6 +1254,7 @@ _write_content_types_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, content_types->file, "[Content_Types].xml");
|
||||
|
||||
fclose(content_types->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_content_types_free(content_types);
|
||||
@ -1168,6 +1269,7 @@ STATIC lxw_error
|
||||
_write_workbook_rels_file(lxw_packager *self)
|
||||
{
|
||||
lxw_relationships *rels = lxw_relationships_new();
|
||||
char *buffer = NULL;
|
||||
lxw_workbook *workbook = self->workbook;
|
||||
lxw_sheet *sheet;
|
||||
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
|
||||
@ -1180,7 +1282,7 @@ _write_workbook_rels_file(lxw_packager *self)
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
rels->file = lxw_tmpfile(self->tmpdir);
|
||||
rels->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!rels->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
@ -1220,6 +1322,7 @@ _write_workbook_rels_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, rels->file, "xl/_rels/workbook.xml.rels");
|
||||
|
||||
fclose(rels->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_free_relationships(rels);
|
||||
@ -1235,6 +1338,7 @@ STATIC lxw_error
|
||||
_write_worksheet_rels_file(lxw_packager *self)
|
||||
{
|
||||
lxw_relationships *rels;
|
||||
char *buffer = NULL;
|
||||
lxw_rel_tuple *rel;
|
||||
lxw_workbook *workbook = self->workbook;
|
||||
lxw_sheet *sheet;
|
||||
@ -1262,7 +1366,7 @@ _write_worksheet_rels_file(lxw_packager *self)
|
||||
|
||||
rels = lxw_relationships_new();
|
||||
|
||||
rels->file = lxw_tmpfile(self->tmpdir);
|
||||
rels->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!rels->file) {
|
||||
lxw_free_relationships(rels);
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
@ -1311,6 +1415,7 @@ _write_worksheet_rels_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, rels->file, sheetname);
|
||||
|
||||
fclose(rels->file);
|
||||
free(buffer);
|
||||
lxw_free_relationships(rels);
|
||||
|
||||
RETURN_ON_ERROR(err);
|
||||
@ -1327,6 +1432,7 @@ STATIC lxw_error
|
||||
_write_chartsheet_rels_file(lxw_packager *self)
|
||||
{
|
||||
lxw_relationships *rels;
|
||||
char *buffer = NULL;
|
||||
lxw_rel_tuple *rel;
|
||||
lxw_workbook *workbook = self->workbook;
|
||||
lxw_sheet *sheet;
|
||||
@ -1348,7 +1454,7 @@ _write_chartsheet_rels_file(lxw_packager *self)
|
||||
|
||||
rels = lxw_relationships_new();
|
||||
|
||||
rels->file = lxw_tmpfile(self->tmpdir);
|
||||
rels->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!rels->file) {
|
||||
lxw_free_relationships(rels);
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
@ -1372,6 +1478,7 @@ _write_chartsheet_rels_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, rels->file, sheetname);
|
||||
|
||||
fclose(rels->file);
|
||||
free(buffer);
|
||||
lxw_free_relationships(rels);
|
||||
|
||||
RETURN_ON_ERROR(err);
|
||||
@ -1388,6 +1495,7 @@ STATIC lxw_error
|
||||
_write_drawing_rels_file(lxw_packager *self)
|
||||
{
|
||||
lxw_relationships *rels;
|
||||
char *buffer = NULL;
|
||||
lxw_rel_tuple *rel;
|
||||
lxw_workbook *workbook = self->workbook;
|
||||
lxw_sheet *sheet;
|
||||
@ -1407,7 +1515,7 @@ _write_drawing_rels_file(lxw_packager *self)
|
||||
|
||||
rels = lxw_relationships_new();
|
||||
|
||||
rels->file = lxw_tmpfile(self->tmpdir);
|
||||
rels->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!rels->file) {
|
||||
lxw_free_relationships(rels);
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
@ -1427,6 +1535,7 @@ _write_drawing_rels_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, rels->file, sheetname);
|
||||
|
||||
fclose(rels->file);
|
||||
free(buffer);
|
||||
lxw_free_relationships(rels);
|
||||
|
||||
RETURN_ON_ERROR(err);
|
||||
@ -1444,13 +1553,14 @@ _write_vml_drawing_rels_file(lxw_packager *self, lxw_worksheet *worksheet,
|
||||
uint32_t index)
|
||||
{
|
||||
lxw_relationships *rels;
|
||||
char *buffer = NULL;
|
||||
lxw_rel_tuple *rel;
|
||||
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
|
||||
rels = lxw_relationships_new();
|
||||
|
||||
rels->file = lxw_tmpfile(self->tmpdir);
|
||||
rels->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!rels->file) {
|
||||
lxw_free_relationships(rels);
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
@ -1470,6 +1580,7 @@ _write_vml_drawing_rels_file(lxw_packager *self, lxw_worksheet *worksheet,
|
||||
err = _add_file_to_zip(self, rels->file, sheetname);
|
||||
|
||||
fclose(rels->file);
|
||||
free(buffer);
|
||||
lxw_free_relationships(rels);
|
||||
|
||||
return err;
|
||||
@ -1482,6 +1593,7 @@ STATIC lxw_error
|
||||
_write_root_rels_file(lxw_packager *self)
|
||||
{
|
||||
lxw_relationships *rels = lxw_relationships_new();
|
||||
char *buffer = NULL;
|
||||
lxw_error err = LXW_NO_ERROR;
|
||||
|
||||
if (!rels) {
|
||||
@ -1489,7 +1601,7 @@ _write_root_rels_file(lxw_packager *self)
|
||||
goto mem_error;
|
||||
}
|
||||
|
||||
rels->file = lxw_tmpfile(self->tmpdir);
|
||||
rels->file = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!rels->file) {
|
||||
err = LXW_ERROR_CREATING_TMPFILE;
|
||||
goto mem_error;
|
||||
@ -1514,6 +1626,7 @@ _write_root_rels_file(lxw_packager *self)
|
||||
err = _add_file_to_zip(self, rels->file, "_rels/.rels");
|
||||
|
||||
fclose(rels->file);
|
||||
free(buffer);
|
||||
|
||||
mem_error:
|
||||
lxw_free_relationships(rels);
|
||||
@ -1555,7 +1668,7 @@ _add_file_to_zip(lxw_packager *self, FILE * file, const char *filename)
|
||||
while (size_read) {
|
||||
|
||||
if (size_read < self->buffer_size) {
|
||||
if (feof(file) == 0) {
|
||||
if (ferror(file)) {
|
||||
LXW_ERROR("Error reading member file data");
|
||||
RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
|
||||
}
|
||||
|
@ -7,6 +7,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef USE_FMEMOPEN
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -578,6 +582,25 @@ lxw_tmpfile(char *tmpdir)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a memory-backed file if supported, otherwise a temporary one
|
||||
*/
|
||||
FILE *
|
||||
lxw_get_filehandle(char **buf, size_t *size, char *tmpdir)
|
||||
{
|
||||
static size_t s;
|
||||
if (!size)
|
||||
size = &s;
|
||||
*buf = NULL;
|
||||
*size = 0;
|
||||
#ifdef USE_FMEMOPEN
|
||||
(void) tmpdir;
|
||||
return open_memstream(buf, size);
|
||||
#else
|
||||
return lxw_tmpfile(tmpdir);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Use third party function to handle sprintf of doubles for locale portable
|
||||
* code.
|
||||
|
@ -1880,6 +1880,8 @@ workbook_new_opt(const char *filename, lxw_workbook_options *options)
|
||||
workbook->options.constant_memory = options->constant_memory;
|
||||
workbook->options.tmpdir = lxw_strdup(options->tmpdir);
|
||||
workbook->options.use_zip64 = options->use_zip64;
|
||||
workbook->options.output_buffer = options->output_buffer;
|
||||
workbook->options.output_buffer_size = options->output_buffer_size;
|
||||
}
|
||||
|
||||
workbook->max_url_length = 2079;
|
||||
@ -2192,6 +2194,11 @@ workbook_close(lxw_workbook *self)
|
||||
/* Assemble all the sub-files in the xlsx package. */
|
||||
error = lxw_create_package(packager);
|
||||
|
||||
if (!self->filename) {
|
||||
*self->options.output_buffer = packager->output_buffer;
|
||||
*self->options.output_buffer_size = packager->output_buffer_size;
|
||||
}
|
||||
|
||||
/* Error and non-error conditions fall through to the cleanup code. */
|
||||
if (error == LXW_ERROR_CREATING_TMPFILE) {
|
||||
LXW_PRINTF(LXW_STDERR "[ERROR] workbook_close(): "
|
||||
|
@ -195,7 +195,9 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
||||
if (init_data && init_data->optimize) {
|
||||
FILE *tmpfile;
|
||||
|
||||
tmpfile = lxw_tmpfile(init_data->tmpdir);
|
||||
worksheet->optimize_buffer = NULL;
|
||||
tmpfile = lxw_get_filehandle(&worksheet->optimize_buffer,
|
||||
NULL, init_data->tmpdir);
|
||||
if (!tmpfile) {
|
||||
LXW_ERROR("Error creating tmpfile() for worksheet in "
|
||||
"'constant_memory' mode.");
|
||||
@ -2536,6 +2538,7 @@ _worksheet_write_optimized_sheet_data(lxw_worksheet *self)
|
||||
}
|
||||
|
||||
fclose(self->optimize_tmpfile);
|
||||
free(self->optimize_buffer);
|
||||
|
||||
lxw_xml_end_tag(self->file, "sheetData");
|
||||
}
|
||||
@ -8415,6 +8418,7 @@ worksheet_write_rich_string(lxw_worksheet *self,
|
||||
lxw_format *default_format = NULL;
|
||||
lxw_rich_string_tuple *rich_string_tuple = NULL;
|
||||
FILE *tmpfile;
|
||||
char *buffer = NULL;
|
||||
|
||||
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
||||
if (err)
|
||||
@ -8439,7 +8443,7 @@ worksheet_write_rich_string(lxw_worksheet *self,
|
||||
return err;
|
||||
|
||||
/* Create a tmp file for the styles object. */
|
||||
tmpfile = lxw_tmpfile(self->tmpdir);
|
||||
tmpfile = lxw_get_filehandle(&buffer, NULL, self->tmpdir);
|
||||
if (!tmpfile)
|
||||
return LXW_ERROR_CREATING_TMPFILE;
|
||||
|
||||
@ -8487,12 +8491,14 @@ worksheet_write_rich_string(lxw_worksheet *self,
|
||||
rewind(tmpfile);
|
||||
if (fread(rich_string, file_size, 1, tmpfile) < 1) {
|
||||
fclose(tmpfile);
|
||||
free(buffer);
|
||||
free(rich_string);
|
||||
return LXW_ERROR_READING_TMPFILE;
|
||||
}
|
||||
|
||||
/* Close the temp file. */
|
||||
fclose(tmpfile);
|
||||
free(buffer);
|
||||
|
||||
if (lxw_utf8_strlen(rich_string) > LXW_STR_MAX) {
|
||||
free(rich_string);
|
||||
@ -8532,6 +8538,7 @@ mem_error:
|
||||
lxw_styles_free(styles);
|
||||
lxw_format_free(default_format);
|
||||
fclose(tmpfile);
|
||||
free(buffer);
|
||||
|
||||
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize01.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize02.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize04.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize05.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize06.xlsx", &options);
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize08.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize21.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize22.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize23.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize24.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize25.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, NULL, LXW_FALSE, NULL, NULL};
|
||||
|
||||
/* Use deprecated constructor for testing. */
|
||||
lxw_workbook *workbook = workbook_new_opt("test_optimize26.xlsx", &options);
|
||||
|
37
test/functional/src/test_output_buffer01.c
Normal file
37
test/functional/src/test_output_buffer01.c
Normal file
@ -0,0 +1,37 @@
|
||||
/*****************************************************************************
|
||||
* Test cases for libxlsxwriter.
|
||||
*
|
||||
* Simple test case to test data writing.
|
||||
*
|
||||
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
int main() {
|
||||
char *output_buffer;
|
||||
size_t output_buffer_size;
|
||||
lxw_workbook_options options = {LXW_FALSE,
|
||||
".",
|
||||
LXW_FALSE,
|
||||
&output_buffer,
|
||||
&output_buffer_size};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt(NULL, &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
||||
worksheet_write_string(worksheet, 0, 0, "Hello", NULL);
|
||||
worksheet_write_number(worksheet, 1, 0, 123, NULL);
|
||||
|
||||
int error = workbook_close(workbook);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
FILE *file = fopen("test_output_buffer01.xlsx", "wb");
|
||||
fwrite(output_buffer, output_buffer_size, 1, file);
|
||||
fclose(file);
|
||||
free(output_buffer);
|
||||
|
||||
return 0;
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_FALSE, ".", LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_FALSE, ".", LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_tmpdir01.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
int main() {
|
||||
|
||||
lxw_workbook_options options = {LXW_TRUE, ".", LXW_FALSE};
|
||||
lxw_workbook_options options = {LXW_TRUE, ".", LXW_FALSE, NULL, NULL};
|
||||
|
||||
lxw_workbook *workbook = workbook_new_opt("test_tmpdir02.xlsx", &options);
|
||||
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||
|
17
test/functional/test_output_buffer.py
Normal file
17
test/functional/test_output_buffer.py
Normal file
@ -0,0 +1,17 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Tests for libxlsxwriter.
|
||||
#
|
||||
# Copyright 2014-2022, John McNamara, jmcnamara@cpan.org
|
||||
#
|
||||
|
||||
import base_test_class
|
||||
|
||||
class TestCompareXLSXFiles(base_test_class.XLSXBaseTest):
|
||||
"""
|
||||
Test file created with libxlsxwriter against a file created by Excel.
|
||||
|
||||
"""
|
||||
|
||||
def test_output_buffer01(self):
|
||||
self.run_exe_test('test_output_buffer01', 'simple01.xlsx')
|
Loading…
x
Reference in New Issue
Block a user