libxlsxwriter/src/worksheet.c in fast_excel-0.2.6 vs libxlsxwriter/src/worksheet.c in fast_excel-0.3.0
- old
+ new
@@ -1,11 +1,11 @@
/*****************************************************************************
* worksheet - A library for creating Excel XLSX worksheet files.
*
* Used in conjunction with the libxlsxwriter library.
*
- * Copyright 2014-2018, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
+ * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include <ctype.h>
@@ -15,12 +15,10 @@
#include "xlsxwriter/utility.h"
#include "xlsxwriter/relationships.h"
#define LXW_STR_MAX 32767
#define LXW_BUFFER_SIZE 4096
-#define LXW_PORTRAIT 1
-#define LXW_LANDSCAPE 0
#define LXW_PRINT_ACROSS 1
#define LXW_VALIDATION_MAX_TITLE_LENGTH 32
#define LXW_VALIDATION_MAX_STRING_LENGTH 255
/*
@@ -269,14 +267,15 @@
{
if (!image)
return;
free(image->filename);
- free(image->short_name);
+ free(image->description);
free(image->extension);
free(image->url);
free(image->tip);
+ free(image->image_buffer);
free(image);
}
/*
* Free a worksheet data_validation.
@@ -447,10 +446,11 @@
free(worksheet->hbreaks);
free(worksheet->vbreaks);
free(worksheet->name);
free(worksheet->quoted_name);
+ free(worksheet->vba_codename);
free(worksheet);
worksheet = NULL;
}
@@ -537,10 +537,30 @@
return cell;
}
/*
+ * Create a new worksheet inline_string cell object for rich strings.
+ */
+STATIC lxw_cell *
+_new_inline_rich_string_cell(lxw_row_t row_num,
+ lxw_col_t col_num, char *string,
+ lxw_format *format)
+{
+ lxw_cell *cell = calloc(1, sizeof(lxw_cell));
+ RETURN_ON_MEM_ERROR(cell, cell);
+
+ cell->row_num = row_num;
+ cell->col_num = col_num;
+ cell->type = INLINE_RICH_STRING_CELL;
+ cell->format = format;
+ cell->u.string = string;
+
+ return cell;
+}
+
+/*
* Create a new worksheet formula cell object.
*/
STATIC lxw_cell *
_new_formula_cell(lxw_row_t row_num,
lxw_col_t col_num, char *formula, lxw_format *format)
@@ -840,42 +860,10 @@
return -1;
return 0;
}
/*
- * Hash a worksheet password. Based on the algorithm provided by Daniel Rentz
- * of OpenOffice.
- */
-STATIC uint16_t
-_hash_password(const char *password)
-{
- size_t count;
- uint8_t i;
- uint16_t hash = 0x0000;
-
- count = strlen(password);
-
- for (i = 0; i < count; i++) {
- uint32_t low_15;
- uint32_t high_15;
- uint32_t letter = password[i] << (i + 1);
-
- low_15 = letter & 0x7fff;
- high_15 = letter & (0x7fff << 15);
- high_15 = high_15 >> 15;
- letter = low_15 | high_15;
-
- hash ^= letter;
- }
-
- hash ^= count;
- hash ^= 0xCE4B;
-
- return hash;
-}
-
-/*
* Simple replacement for libgen.h basename() for compatibility with MSVC. It
* handles forward and back slashes. It doesn't copy exactly the return
* format of basename().
*/
char *
@@ -1751,10 +1739,13 @@
col_opt = NULL;
}
}
if (col_opt) {
+ if (col_opt->hidden)
+ return 0;
+
width = col_opt->width;
/* Convert to pixels. */
if (width == 0) {
pixels = 0;
@@ -1786,10 +1777,13 @@
double height;
row = lxw_worksheet_find_row(self, row_num);
if (row) {
+ if (row->hidden)
+ return 0;
+
height = row->height;
if (height == 0)
pixels = 0;
else
@@ -1912,27 +1906,34 @@
}
y_abs += y1;
/* Adjust start col for offsets that are greater than the col width. */
- while (x1 >= _worksheet_size_col(self, col_start)) {
- x1 -= _worksheet_size_col(self, col_start);
- col_start++;
+ if (_worksheet_size_col(self, col_start) > 0) {
+ while (x1 >= _worksheet_size_col(self, col_start)) {
+ x1 -= _worksheet_size_col(self, col_start);
+ col_start++;
+ }
}
/* Adjust start row for offsets that are greater than the row height. */
- while (y1 >= _worksheet_size_row(self, row_start)) {
- y1 -= _worksheet_size_row(self, row_start);
- row_start++;
+ if (_worksheet_size_row(self, row_start) > 0) {
+ while (y1 >= _worksheet_size_row(self, row_start)) {
+ y1 -= _worksheet_size_row(self, row_start);
+ row_start++;
+ }
}
/* Initialize end cell to the same as the start cell. */
col_end = col_start;
row_end = row_start;
- width = width + x1;
- height = height + y1;
+ /* Only offset the image in the cell if the row/col isn't hidden. */
+ if (_worksheet_size_col(self, col_start) > 0)
+ width = width + x1;
+ if (_worksheet_size_row(self, row_start) > 0)
+ height = height + y1;
/* Subtract the underlying cell widths to find the end cell. */
while (width >= _worksheet_size_col(self, col_end)) {
width -= _worksheet_size_col(self, col_end);
col_end++;
@@ -1990,11 +1991,11 @@
/*
* Set up image/drawings.
*/
void
lxw_worksheet_prepare_image(lxw_worksheet *self,
- uint16_t image_ref_id, uint16_t drawing_id,
+ uint32_t image_ref_id, uint32_t drawing_id,
lxw_image_options *image_data)
{
lxw_drawing_object *drawing_object;
lxw_rel_tuple *relationship;
double width;
@@ -2025,11 +2026,11 @@
drawing_object = calloc(1, sizeof(lxw_drawing_object));
RETURN_VOID_ON_MEM_ERROR(drawing_object);
drawing_object->anchor_type = LXW_ANCHOR_TYPE_IMAGE;
drawing_object->edit_as = LXW_ANCHOR_EDIT_AS_ONE_CELL;
- drawing_object->description = lxw_strdup(image_data->short_name);
+ drawing_object->description = lxw_strdup(image_data->description);
/* Scale to user scale. */
width = image_data->width * image_data->x_scale;
height = image_data->height * image_data->y_scale;
@@ -2077,24 +2078,33 @@
/*
* Set up chart/drawings.
*/
void
lxw_worksheet_prepare_chart(lxw_worksheet *self,
- uint16_t chart_ref_id, uint16_t drawing_id,
- lxw_image_options *image_data)
+ uint32_t chart_ref_id,
+ uint32_t drawing_id,
+ lxw_image_options *image_data,
+ uint8_t is_chartsheet)
{
lxw_drawing_object *drawing_object;
lxw_rel_tuple *relationship;
double width;
double height;
char filename[LXW_FILENAME_LENGTH];
if (!self->drawing) {
self->drawing = lxw_drawing_new();
- self->drawing->embedded = LXW_TRUE;
RETURN_VOID_ON_MEM_ERROR(self->drawing);
+ if (is_chartsheet) {
+ self->drawing->embedded = LXW_FALSE;
+ self->drawing->orientation = self->orientation;
+ }
+ else {
+ self->drawing->embedded = LXW_TRUE;
+ }
+
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/drawing");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
@@ -2257,12 +2267,11 @@
return LXW_NO_ERROR;
file_error:
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
- "no size data found in file: %s.",
- image_options->filename);
+ "no size data found in: %s.", image_options->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
/*
@@ -2384,12 +2393,11 @@
return LXW_NO_ERROR;
file_error:
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
- "no size data found in file: %s.",
- image_options->filename);
+ "no size data found in: %s.", image_options->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
/*
@@ -2434,12 +2442,11 @@
return LXW_NO_ERROR;
file_error:
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
- "no size data found in file: %s.",
- image_options->filename);
+ "no size data found in: %s.", image_options->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
/*
@@ -2452,11 +2459,11 @@
unsigned char signature[4];
/* Read 4 bytes to look for the file header/signature. */
if (fread(signature, 1, 4, image_options->stream) < 4) {
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
- "couldn't read file type for file: %s.",
+ "couldn't read image type for: %s.",
image_options->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
if (memcmp(&signature[1], "PNG", 3) == 0) {
@@ -2471,11 +2478,11 @@
if (_process_bmp(image_options) != LXW_NO_ERROR)
return LXW_ERROR_IMAGE_DIMENSIONS;
}
else {
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
- "unsupported image format for file: %s.",
+ "unsupported image format for: %s.",
image_options->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
return LXW_NO_ERROR;
@@ -2575,10 +2582,45 @@
free(string);
}
/*
+ * Write out an inline rich string. Doesn't use the xml functions as an
+ * optimization in the inner cell writing loop.
+ */
+STATIC void
+_write_inline_rich_string_cell(lxw_worksheet *self, char *range,
+ int32_t style_index, lxw_cell *cell)
+{
+ char *string = cell->u.string;
+
+ /* Add attribute to preserve leading or trailing whitespace. */
+ if (isspace((unsigned char) string[0])
+ || isspace((unsigned char) string[strlen(string) - 1])) {
+
+ if (style_index)
+ fprintf(self->file,
+ "<c r=\"%s\" s=\"%d\" t=\"inlineStr\"><is>%s</is></c>",
+ range, style_index, string);
+ else
+ fprintf(self->file,
+ "<c r=\"%s\" t=\"inlineStr\"><is>%s</is></c>",
+ range, string);
+ }
+ else {
+ if (style_index)
+ fprintf(self->file,
+ "<c r=\"%s\" s=\"%d\" t=\"inlineStr\">"
+ "<is>%s</is></c>", range, style_index, string);
+ else
+ fprintf(self->file,
+ "<c r=\"%s\" t=\"inlineStr\">"
+ "<is>%s</is></c>", range, string);
+ }
+}
+
+/*
* Write out a formula worksheet cell with a numeric result.
*/
STATIC void
_write_formula_num_cell(lxw_worksheet *self, lxw_cell *cell)
{
@@ -2710,10 +2752,15 @@
if (cell->type == INLINE_STRING_CELL) {
_write_inline_string_cell(self, range, style_index, cell);
return;
}
+ if (cell->type == INLINE_RICH_STRING_CELL) {
+ _write_inline_rich_string_cell(self, range, style_index, cell);
+ return;
+ }
+
/* For other cell types use the general functions. */
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("r", range);
if (style_index)
@@ -3091,18 +3138,19 @@
struct xml_attribute *attribute;
if (!self->fit_page
&& !self->filter_on
&& self->tab_color == LXW_COLOR_UNSET
- && !self->outline_changed && !self->vba_codename) {
+ && !self->outline_changed
+ && !self->vba_codename && !self->is_chartsheet) {
return;
}
LXW_INIT_ATTRIBUTES();
if (self->vba_codename)
- LXW_PUSH_ATTRIBUTES_INT("codeName", self->vba_codename);
+ LXW_PUSH_ATTRIBUTES_STR("codeName", self->vba_codename);
if (self->filter_on)
LXW_PUSH_ATTRIBUTES_STR("filterMode", "1");
if (self->fit_page || self->tab_color != LXW_COLOR_UNSET
@@ -3362,17 +3410,16 @@
/*
* Write the <sheetProtection> element.
*/
STATIC void
-_worksheet_write_sheet_protection(lxw_worksheet *self)
+_worksheet_write_sheet_protection(lxw_worksheet *self,
+ lxw_protection *protect)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
- struct lxw_protection *protect = &self->protection;
-
if (!protect->is_configured)
return;
LXW_INIT_ATTRIBUTES();
@@ -3380,11 +3427,11 @@
LXW_PUSH_ATTRIBUTES_STR("password", protect->hash);
if (!protect->no_sheet)
LXW_PUSH_ATTRIBUTES_INT("sheet", 1);
- if (protect->content)
+ if (!protect->no_content)
LXW_PUSH_ATTRIBUTES_INT("content", 1);
if (!protect->objects)
LXW_PUSH_ATTRIBUTES_INT("objects", 1);
@@ -3437,11 +3484,11 @@
/*
* Write the <drawing> element.
*/
STATIC void
-_write_drawing(lxw_worksheet *self, uint16_t id)
+_worksheet_write_drawing(lxw_worksheet *self, uint16_t id)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
@@ -3459,18 +3506,18 @@
/*
* Write the <drawing> elements.
*/
STATIC void
-_write_drawings(lxw_worksheet *self)
+_worksheet_write_drawings(lxw_worksheet *self)
{
if (!self->drawing)
return;
self->rel_count++;
- _write_drawing(self, self->rel_count);
+ _worksheet_write_drawing(self, self->rel_count);
}
/*
* Write the <formula1> element for numbers.
*/
@@ -3688,10 +3735,56 @@
LXW_FREE_ATTRIBUTES();
}
/*
+ * External functions to call intern XML methods shared with chartsheet.
+ */
+void
+lxw_worksheet_write_sheet_views(lxw_worksheet *self)
+{
+ _worksheet_write_sheet_views(self);
+}
+
+void
+lxw_worksheet_write_page_margins(lxw_worksheet *self)
+{
+ _worksheet_write_page_margins(self);
+}
+
+void
+lxw_worksheet_write_drawings(lxw_worksheet *self)
+{
+ _worksheet_write_drawings(self);
+}
+
+void
+lxw_worksheet_write_sheet_protection(lxw_worksheet *self,
+ lxw_protection *protect)
+{
+ _worksheet_write_sheet_protection(self, protect);
+}
+
+void
+lxw_worksheet_write_sheet_pr(lxw_worksheet *self)
+{
+ _worksheet_write_sheet_pr(self);
+}
+
+void
+lxw_worksheet_write_page_setup(lxw_worksheet *self)
+{
+ _worksheet_write_page_setup(self);
+}
+
+void
+lxw_worksheet_write_header_footer(lxw_worksheet *self)
+{
+ _worksheet_write_header_footer(self);
+}
+
+/*
* Assemble and write the XML file.
*/
void
lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
{
@@ -3721,11 +3814,11 @@
_worksheet_write_sheet_data(self);
else
_worksheet_write_optimized_sheet_data(self);
/* Write the sheetProtection element. */
- _worksheet_write_sheet_protection(self);
+ _worksheet_write_sheet_protection(self, &self->protection);
/* Write the autoFilter element. */
_worksheet_write_auto_filter(self);
/* Write the mergeCells element. */
@@ -3754,11 +3847,11 @@
/* Write the colBreaks element. */
_worksheet_write_col_breaks(self);
/* Write the drawing element. */
- _write_drawings(self);
+ _worksheet_write_drawings(self);
/* Close the worksheet tag. */
lxw_xml_end_tag(self->file, "worksheet");
}
@@ -3821,11 +3914,11 @@
if (lxw_utf8_strlen(string) > LXW_STR_MAX)
return LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED;
if (!self->optimize) {
/* Get the SST element and string id. */
- sst_element = lxw_get_sst_index(self->sst, string);
+ sst_element = lxw_get_sst_index(self->sst, string, LXW_FALSE);
if (!sst_element)
return LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND;
string_id = sst_element->index;
@@ -4297,10 +4390,160 @@
return worksheet_write_url_opt(self, row_num, col_num, url, format, NULL,
NULL);
}
/*
+ * Write a rich string to an Excel file.
+ *
+ * Rather than duplicate several of the styles.c font xml methods of styles.c
+ * and write the data to a memory buffer this function creates a temporary
+ * styles object and uses it to write the data to a file. It then reads that
+ * data back into memory and closes the file.
+ */
+lxw_error
+worksheet_write_rich_string(lxw_worksheet *self,
+ lxw_row_t row_num,
+ lxw_col_t col_num,
+ lxw_rich_string_tuple *rich_strings[],
+ lxw_format *format)
+{
+ lxw_cell *cell;
+ int32_t string_id;
+ struct sst_element *sst_element;
+ lxw_error err;
+ uint8_t i;
+ long file_size;
+ char *rich_string = NULL;
+ char *string_copy = NULL;
+ lxw_styles *styles = NULL;
+ lxw_format *default_format = NULL;
+ lxw_rich_string_tuple *rich_string_tuple = NULL;
+ FILE *tmpfile;
+
+ err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
+ if (err)
+ return err;
+
+ /* Iterate through rich string fragments to check for input errors. */
+ i = 0;
+ err = LXW_NO_ERROR;
+ while ((rich_string_tuple = rich_strings[i++]) != NULL) {
+
+ /* Check for NULL or empty strings. */
+ if (!rich_string_tuple->string || !*rich_string_tuple->string) {
+ err = LXW_ERROR_PARAMETER_VALIDATION;
+ }
+ }
+
+ /* If there are less than 2 fragments it isn't a rich string. */
+ if (i <= 2)
+ err = LXW_ERROR_PARAMETER_VALIDATION;
+
+ if (err)
+ return err;
+
+ /* Create a tmp file for the styles object. */
+ tmpfile = lxw_tmpfile(self->tmpdir);
+ if (!tmpfile)
+ return LXW_ERROR_CREATING_TMPFILE;
+
+ /* Create a temp styles object for writing the font data. */
+ styles = lxw_styles_new();
+ GOTO_LABEL_ON_MEM_ERROR(styles, mem_error);
+ styles->file = tmpfile;
+
+ /* Create a default format for non-formatted text. */
+ default_format = lxw_format_new();
+ GOTO_LABEL_ON_MEM_ERROR(default_format, mem_error);
+
+ /* Iterate through the rich string fragments and write each one out. */
+ i = 0;
+ while ((rich_string_tuple = rich_strings[i++]) != NULL) {
+ lxw_xml_start_tag(tmpfile, "r", NULL);
+
+ if (rich_string_tuple->format) {
+ /* Write the user defined font format. */
+ lxw_styles_write_rich_font(styles, rich_string_tuple->format);
+ }
+ else {
+ /* Write a default font format. Except for the first fragment. */
+ if (i > 1)
+ lxw_styles_write_rich_font(styles, default_format);
+ }
+
+ lxw_styles_write_string_fragment(styles, rich_string_tuple->string);
+ lxw_xml_end_tag(tmpfile, "r");
+ }
+
+ /* Free the temp objects. */
+ lxw_styles_free(styles);
+ lxw_format_free(default_format);
+
+ /* Flush the file and read the size to calculate the required memory. */
+ fflush(tmpfile);
+ file_size = ftell(tmpfile);
+
+ /* Allocate a buffer for the rich string xml data. */
+ rich_string = calloc(file_size + 1, 1);
+ GOTO_LABEL_ON_MEM_ERROR(rich_string, mem_error);
+
+ /* Rewind the file and read the data into the memory buffer. */
+ rewind(tmpfile);
+ if (fread(rich_string, file_size, 1, tmpfile) < 1) {
+ fclose(tmpfile);
+ free(rich_string);
+ return LXW_ERROR_READING_TMPFILE;
+ }
+
+ /* Close the temp file. */
+ fclose(tmpfile);
+
+ if (lxw_utf8_strlen(rich_string) > LXW_STR_MAX) {
+ free(rich_string);
+ return LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED;
+ }
+
+ if (!self->optimize) {
+ /* Get the SST element and string id. */
+ sst_element = lxw_get_sst_index(self->sst, rich_string, LXW_TRUE);
+ free(rich_string);
+
+ if (!sst_element)
+ return LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND;
+
+ string_id = sst_element->index;
+ cell = _new_string_cell(row_num, col_num, string_id,
+ sst_element->string, format);
+ }
+ else {
+ /* Look for and escape control chars in the string. */
+ if (strpbrk(rich_string, "\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C"
+ "\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16"
+ "\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")) {
+ string_copy = lxw_escape_control_characters(rich_string);
+ free(rich_string);
+ }
+ else {
+ string_copy = rich_string;
+ }
+ cell = _new_inline_rich_string_cell(row_num, col_num, string_copy,
+ format);
+ }
+
+ _insert_cell(self, row_num, col_num, cell);
+
+ return LXW_NO_ERROR;
+
+mem_error:
+ lxw_styles_free(styles);
+ lxw_format_free(default_format);
+ fclose(tmpfile);
+
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
+}
+
+/*
* Set the properties of a single column or a range of columns with options.
*/
lxw_error
worksheet_set_column_opt(lxw_worksheet *self,
lxw_col_t firstcol,
@@ -5232,14 +5475,15 @@
protect->scenarios = options->scenarios;
protect->objects = options->objects;
}
if (password) {
- uint16_t hash = _hash_password(password);
+ uint16_t hash = lxw_hash_password(password);
lxw_snprintf(protect->hash, 5, "%X", hash);
}
+ protect->no_content = LXW_TRUE;
protect->is_configured = LXW_TRUE;
}
/*
* Set the worksheet properties for outlines and grouping.
@@ -5287,11 +5531,11 @@
lxw_row_t row_num, lxw_col_t col_num,
const char *filename,
lxw_image_options *user_options)
{
FILE *image_stream;
- char *short_name;
+ char *description;
lxw_image_options *options;
if (!filename) {
LXW_WARN("worksheet_insert_image()/_opt(): "
"filename must be specified.");
@@ -5305,13 +5549,13 @@
"file doesn't exist or can't be opened: %s.",
filename);
return LXW_ERROR_PARAMETER_VALIDATION;
}
- /* Get the filename from the full path to add to the Drawing object. */
- short_name = lxw_basename(filename);
- if (!short_name) {
+ /* Use the filename as the default description, like Excel. */
+ description = lxw_basename(filename);
+ if (!description) {
LXW_WARN_FORMAT1("worksheet_insert_image()/_opt(): "
"couldn't get basename for file: %s.", filename);
fclose(image_stream);
return LXW_ERROR_PARAMETER_VALIDATION;
}
@@ -5330,11 +5574,11 @@
options->y_scale = user_options->y_scale;
}
/* Copy other options or set defaults. */
options->filename = lxw_strdup(filename);
- options->short_name = lxw_strdup(short_name);
+ options->description = lxw_strdup(description);
options->stream = image_stream;
options->row = row_num;
options->col = col_num;
if (!options->x_scale)
@@ -5347,11 +5591,11 @@
STAILQ_INSERT_TAIL(self->image_data, options, list_pointers);
fclose(image_stream);
return LXW_NO_ERROR;
}
else {
- free(options);
+ _free_image_options(options);
fclose(image_stream);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
}
@@ -5364,10 +5608,99 @@
const char *filename)
{
return worksheet_insert_image_opt(self, row_num, col_num, filename, NULL);
}
+lxw_error
+worksheet_insert_image_buffer_opt(lxw_worksheet *self,
+ lxw_row_t row_num,
+ lxw_col_t col_num,
+ const unsigned char *image_buffer,
+ size_t image_size,
+ lxw_image_options *user_options)
+{
+ FILE *image_stream;
+ lxw_image_options *options;
+
+ if (!image_size) {
+ LXW_WARN("worksheet_insert_image_buffer()/_opt(): "
+ "size must be non-zero.");
+ return LXW_ERROR_NULL_PARAMETER_IGNORED;
+ }
+
+ /* Write the image buffer to a temporary file so we can read the
+ * dimensions like an ordinary file. */
+ image_stream = lxw_tmpfile(self->tmpdir);
+ if (!image_stream)
+ return LXW_ERROR_CREATING_TMPFILE;
+
+ fwrite(image_buffer, 1, image_size, image_stream);
+ rewind(image_stream);
+
+ /* Create a new object to hold the image options. */
+ options = calloc(1, sizeof(lxw_image_options));
+ if (!options) {
+ fclose(image_stream);
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
+ }
+
+ /* Store the image data in the options structure. */
+ options->image_buffer = calloc(1, image_size);
+ if (!options->image_buffer) {
+ _free_image_options(options);
+ fclose(image_stream);
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
+ }
+ else {
+ memcpy(options->image_buffer, image_buffer, image_size);
+ options->image_buffer_size = image_size;
+ options->is_image_buffer = LXW_TRUE;
+ }
+
+ if (user_options) {
+ options->x_offset = user_options->x_offset;
+ options->y_offset = user_options->y_offset;
+ options->x_scale = user_options->x_scale;
+ options->y_scale = user_options->y_scale;
+ options->description = lxw_strdup(user_options->description);
+ }
+
+ /* Copy other options or set defaults. */
+ options->filename = lxw_strdup("image_buffer");
+ options->stream = image_stream;
+ options->row = row_num;
+ options->col = col_num;
+
+ if (!options->x_scale)
+ options->x_scale = 1;
+
+ if (!options->y_scale)
+ options->y_scale = 1;
+
+ if (_get_image_properties(options) == LXW_NO_ERROR) {
+ STAILQ_INSERT_TAIL(self->image_data, options, list_pointers);
+ fclose(image_stream);
+ return LXW_NO_ERROR;
+ }
+ else {
+ _free_image_options(options);
+ fclose(image_stream);
+ return LXW_ERROR_IMAGE_DIMENSIONS;
+ }
+}
+
+lxw_error
+worksheet_insert_image_buffer(lxw_worksheet *self,
+ lxw_row_t row_num,
+ lxw_col_t col_num,
+ const unsigned char *image_buffer,
+ size_t image_size)
+{
+ return worksheet_insert_image_buffer_opt(self, row_num, col_num,
+ image_buffer, image_size, NULL);
+}
+
/*
* Insert an chart into the worksheet.
*/
lxw_error
worksheet_insert_chart_opt(lxw_worksheet *self,
@@ -5734,6 +6067,22 @@
worksheet_data_validation_cell(lxw_worksheet *self, lxw_row_t row,
lxw_col_t col, lxw_data_validation *validation)
{
return worksheet_data_validation_range(self, row, col,
row, col, validation);
+}
+
+/*
+ * Set the VBA name for the worksheet.
+ */
+lxw_error
+worksheet_set_vba_name(lxw_worksheet *self, const char *name)
+{
+ if (!name) {
+ LXW_WARN("worksheet_set_vba_name(): " "name must be specified.");
+ return LXW_ERROR_NULL_PARAMETER_IGNORED;
+ }
+
+ self->vba_codename = lxw_strdup(name);
+
+ return LXW_NO_ERROR;
}