libxlsxwriter/include/xlsxwriter/workbook.h in fast_excel-0.4.1 vs libxlsxwriter/include/xlsxwriter/workbook.h in fast_excel-0.5.0

- old
+ new

@@ -1,9 +1,9 @@ /* * libxlsxwriter * - * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt. + * Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt. */ /** * @page workbook_page The Workbook object * @@ -55,19 +55,20 @@ #define LXW_DEFINED_NAME_LENGTH 128 /* Define the tree.h RB structs for the red-black head types. */ RB_HEAD(lxw_worksheet_names, lxw_worksheet_name); RB_HEAD(lxw_chartsheet_names, lxw_chartsheet_name); +RB_HEAD(lxw_image_md5s, lxw_image_md5); /* Define the queue.h structs for the workbook lists. */ STAILQ_HEAD(lxw_sheets, lxw_sheet); STAILQ_HEAD(lxw_worksheets, lxw_worksheet); STAILQ_HEAD(lxw_chartsheets, lxw_chartsheet); STAILQ_HEAD(lxw_charts, lxw_chart); TAILQ_HEAD(lxw_defined_names, lxw_defined_name); -/* TODO */ +/* Struct to hold the 2 sheet types. */ typedef struct lxw_sheet { uint8_t is_chartsheet; union { lxw_worksheet *worksheet; @@ -91,10 +92,18 @@ lxw_chartsheet *chartsheet; RB_ENTRY (lxw_chartsheet_name) tree_pointers; } lxw_chartsheet_name; +/* Struct to represent an image MD5/ID pair. */ +typedef struct lxw_image_md5 { + uint32_t id; + char *md5; + + RB_ENTRY (lxw_image_md5) tree_pointers; +} lxw_image_md5; + /* Wrapper around RB_GENERATE_STATIC from tree.h to avoid unused function * warnings and to avoid portability issues with the _unused attribute. */ #define LXW_RB_GENERATE_WORKSHEET_NAMES(name, type, field, cmp) \ RB_GENERATE_INSERT_COLOR(name, type, field, static) \ RB_GENERATE_REMOVE_COLOR(name, type, field, static) \ @@ -115,10 +124,21 @@ RB_GENERATE_NEXT(name, type, field, static) \ RB_GENERATE_MINMAX(name, type, field, static) \ /* Add unused struct to allow adding a semicolon */ \ struct lxw_rb_generate_charsheet_names{int unused;} +#define LXW_RB_GENERATE_IMAGE_MD5S(name, type, field, cmp) \ + RB_GENERATE_INSERT_COLOR(name, type, field, static) \ + RB_GENERATE_REMOVE_COLOR(name, type, field, static) \ + RB_GENERATE_INSERT(name, type, field, cmp, static) \ + RB_GENERATE_REMOVE(name, type, field, static) \ + RB_GENERATE_FIND(name, type, field, cmp, static) \ + RB_GENERATE_NEXT(name, type, field, static) \ + RB_GENERATE_MINMAX(name, type, field, static) \ + /* Add unused struct to allow adding a semicolon */ \ + struct lxw_rb_generate_image_md5s{int unused;} + /** * @brief Macro to loop over all the worksheets in a workbook. * * This macro allows you to loop over all the worksheets that have been * added to a workbook. You must provide a lxw_worksheet pointer and @@ -156,43 +176,47 @@ /* List pointers for queue.h. */ TAILQ_ENTRY (lxw_defined_name) list_pointers; } lxw_defined_name; /** - * Workbook document properties. + * Workbook document properties. Set any unused fields to NULL or 0. */ typedef struct lxw_doc_properties { /** The title of the Excel Document. */ - char *title; + const char *title; /** The subject of the Excel Document. */ - char *subject; + const char *subject; /** The author of the Excel Document. */ - char *author; + const char *author; /** The manager field of the Excel Document. */ - char *manager; + const char *manager; /** The company field of the Excel Document. */ - char *company; + const char *company; /** The category of the Excel Document. */ - char *category; + const char *category; /** The keywords of the Excel Document. */ - char *keywords; + const char *keywords; /** The comment field of the Excel Document. */ - char *comments; + const char *comments; /** The status of the Excel Document. */ - char *status; + const char *status; - /** The hyperlink base url of the Excel Document. */ - char *hyperlink_base; + /** The hyperlink base URL of the Excel Document. */ + const char *hyperlink_base; + /** The file creation date/time shown in Excel. This defaults to the + * current time and date if set to 0. If you wish to create files that are + * binary equivalent (for the same input data) then you should set this + * creation date/time to a known value. */ time_t created; } lxw_doc_properties; /** @@ -203,11 +227,11 @@ * * The following properties are supported: * * - `constant_memory`: This option reduces the amount of data stored in * memory so that large files can be written efficiently. This option is off - * by default. See the note below for limitations when this mode is on. + * by default. See the notes below for limitations when this mode is on. * * - `tmpdir`: libxlsxwriter stores workbook data in temporary files prior to * assembling the final XLSX file. The temporary files are created in the * system's temp directory. If the default temporary directory isn't * accessible to your application, or doesn't contain enough space, you can @@ -217,28 +241,47 @@ * large xlsx files to allow the zip container, or individual XML files * within it, to be greater than 4 GB. See [ZIP64 on Wikipedia][zip64_wiki] * 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. * - * @note In `constant_memory` mode a row of data is written and then discarded - * when a cell in a new row is added via one of the `worksheet_write_*()` - * functions. Therefore, once this option is active, data should be written in - * sequential row order. For this reason the `worksheet_merge_range()` doesn't - * work in this mode. See also @ref ww_mem_constant. + * - `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 + * `worksheet_write_*()` functions. Therefore, once this option is active data + * should be written in sequential row by row order. For this reason + * `worksheet_merge_range()` and some other row based functionality doesn't + * work in this mode. See @ref ww_mem_constant for more details. + * + * @note Also, in `constant_memory` mode the library uses temp file storage + * for worksheet data. This can lead to an issue on OSes that map the `/tmp` + * directory into memory since it is possible to consume the "system" memory + * even though the "process" memory remains constant. In these cases you + * should use an alternative temp file location by using the `tmpdir` option + * shown above. See @ref ww_mem_temp for more details. */ typedef struct lxw_workbook_options { /** Optimize the workbook to use constant memory for worksheets. */ uint8_t constant_memory; /** Directory to use for the temporary files created by libxlsxwriter. */ - char *tmpdir; + const char *tmpdir; /** Allow ZIP64 extensions when creating the xlsx file zip container. */ uint8_t use_zip64; + /** Output buffer to use instead of writing to a file */ + const char **output_buffer; + + /** Used with output_buffer to get the size of the created buffer */ + size_t *output_buffer_size; } lxw_workbook_options; /** * @brief Struct to represent an Excel workbook. * @@ -252,10 +295,13 @@ struct lxw_sheets *sheets; struct lxw_worksheets *worksheets; struct lxw_chartsheets *chartsheets; struct lxw_worksheet_names *worksheet_names; struct lxw_chartsheet_names *chartsheet_names; + struct lxw_image_md5s *image_md5s; + struct lxw_image_md5s *header_image_md5s; + struct lxw_image_md5s *background_md5s; struct lxw_charts *charts; struct lxw_charts *ordered_charts; struct lxw_formats *formats; struct lxw_defined_names *defined_names; lxw_sst *sst; @@ -269,27 +315,39 @@ uint16_t num_worksheets; uint16_t num_chartsheets; uint16_t first_sheet; uint16_t active_sheet; uint16_t num_xf_formats; + uint16_t num_dxf_formats; uint16_t num_format_count; uint16_t drawing_count; + uint16_t comment_count; uint16_t font_count; uint16_t border_count; uint16_t fill_count; uint8_t optimize; + uint16_t max_url_length; + uint8_t read_only; uint8_t has_png; uint8_t has_jpeg; uint8_t has_bmp; + uint8_t has_gif; + uint8_t has_vml; + uint8_t has_comments; + uint8_t has_metadata; lxw_hash_table *used_xf_formats; + lxw_hash_table *used_dxf_formats; char *vba_project; + char *vba_project_signature; char *vba_codename; + lxw_format *default_url_format; + } lxw_workbook; /* *INDENT-OFF* */ #ifdef __cplusplus @@ -329,11 +387,13 @@ * additional options to be set. * * @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 * * The options that can be set via #lxw_workbook_options are: @@ -353,27 +413,34 @@ * within it, to be greater than 4 GB. See [ZIP64 on Wikipedia][zip64_wiki] * for more information. This option is off by default. * * [zip64_wiki]: https://en.wikipedia.org/wiki/Zip_(file_format)#ZIP64 * - * @note In `constant_memory` mode a row of data is written and then discarded - * when a cell in a new row is added via one of the `worksheet_write_*()` - * functions. Therefore, once this option is active, data should be written in - * sequential row order. For this reason the `worksheet_merge_range()` doesn't - * work in this mode. See also @ref ww_mem_constant. + * - `output_buffer`: Output to a memory 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 + * `worksheet_write_*()` functions. Therefore, once this option is active data + * should be written in sequential row by row order. For this reason + * `worksheet_merge_range()` and some other row based functionality doesn't + * work in this mode. See @ref ww_mem_constant for more details. + * + * @note Also, in `constant_memory` mode the library uses temp file storage + * for worksheet data. This can lead to an issue on OSes that map the `/tmp` + * directory into memory since it is possible to consume the "system" memory + * even though the "process" memory remains constant. In these cases you + * should use an alternative temp file location by using the `tmpdir` option + * shown above. See @ref ww_mem_temp for more details. */ lxw_workbook *workbook_new_opt(const char *filename, lxw_workbook_options *options); -/* Deprecated function name for backwards compatibility. */ -lxw_workbook *new_workbook(const char *filename); - -/* Deprecated function name for backwards compatibility. */ -lxw_workbook *new_workbook_opt(const char *filename, - lxw_workbook_options *options); - /** * @brief Add a new worksheet to a workbook. * * @param workbook Pointer to a lxw_workbook instance. * @param sheetname Optional worksheet name, defaults to Sheet1, etc. @@ -402,16 +469,19 @@ * The worksheet name must be a valid Excel worksheet name, i.e: * * - The name is less than or equal to 31 UTF-8 characters. * - The name doesn't contain any of the characters: ` [ ] : * ? / \ ` * - The name doesn't start or end with an apostrophe. - * - The name isn't "History", which is reserved by Excel. (Case insensitive). * - The name isn't already in use. (Case insensitive). * * If any of these errors are encountered the function will return NULL. * You can check for valid name using the `workbook_validate_sheet_name()` * function. + * + * @note You should also avoid using the worksheet name "History" (case + * insensitive) which is reserved in English language versions of + * Excel. Non-English versions may have restrictions on the equivalent word. */ lxw_worksheet *workbook_add_worksheet(lxw_workbook *workbook, const char *sheetname); /** @@ -441,17 +511,20 @@ * The chartsheet name must be a valid Excel worksheet name, i.e.: * * - The name is less than or equal to 31 UTF-8 characters. * - The name doesn't contain any of the characters: ` [ ] : * ? / \ ` * - The name doesn't start or end with an apostrophe. - * - The name isn't "History", which is reserved by Excel. (Case insensitive). * - The name isn't already in use. (Case insensitive). * * If any of these errors are encountered the function will return NULL. * You can check for valid name using the `workbook_validate_sheet_name()` * function. * + * @note You should also avoid using the worksheet name "History" (case + * insensitive) which is reserved in English language versions of + * Excel. Non-English versions may have restrictions on the equivalent word. + * * At least one worksheet should be added to a new workbook when creating a * chartsheet in order to provide data for the chart. The @ref worksheet.h * "Worksheet" object is used to write data and configure a worksheet in the * workbook. */ @@ -531,10 +604,12 @@ * | #LXW_CHART_COLUMN | Column chart. | * | #LXW_CHART_COLUMN_STACKED | Column chart - stacked. | * | #LXW_CHART_COLUMN_STACKED_PERCENT | Column chart - percentage stacked. | * | #LXW_CHART_DOUGHNUT | Doughnut chart. | * | #LXW_CHART_LINE | Line chart. | + * | #LXW_CHART_LINE_STACKED | Line chart - stacked. | + * | #LXW_CHART_LINE_STACKED_PERCENT | Line chart - percentage stacked. | * | #LXW_CHART_PIE | Pie chart. | * | #LXW_CHART_SCATTER | Scatter chart. | * | #LXW_CHART_SCATTER_STRAIGHT | Scatter chart - straight. | * | #LXW_CHART_SCATTER_STRAIGHT_WITH_MARKERS | Scatter chart - straight with markers. | * | #LXW_CHART_SCATTER_SMOOTH | Scatter chart - smooth. | @@ -598,14 +673,15 @@ * - `company` * - `category` * - `keywords` * - `comments` * - `hyperlink_base` + * - `created` * * The properties are specified via a `lxw_doc_properties` struct. All the - * members are `char *` and they are all optional. An example of how to create - * and pass the properties is: + * fields are all optional. An example of how to create and pass the + * properties is: * * @code * // Create a properties structure and set some of the fields. * lxw_doc_properties properties = { * .title = "This is an example spreadsheet", @@ -623,10 +699,16 @@ * workbook_set_properties(workbook, &properties); * @endcode * * @image html doc_properties.png * + * The `created` parameter sets the file creation date/time shown in + * Excel. This defaults to the current time and date if set to 0. If you wish + * to create files that are binary equivalent (for the same input data) then + * you should set this creation date/time to a known value using a `time_t` + * value. + * */ lxw_error workbook_set_properties(lxw_workbook *workbook, lxw_doc_properties *properties); /** @@ -775,18 +857,37 @@ * @code * workbook_define_name(workbook, "'New Data'!Sales", "=Sheet2!$G$1:$G$10"); * @endcode * * The rules for names in Excel are explained in the - * [Microsoft Office -documentation](http://office.microsoft.com/en-001/excel-help/define-and-use-names-in-formulas-HA010147120.aspx). + * [Microsoft Office documentation](http://office.microsoft.com/en-001/excel-help/define-and-use-names-in-formulas-HA010147120.aspx). * */ lxw_error workbook_define_name(lxw_workbook *workbook, const char *name, const char *formula); /** + * @brief Get the default URL format used with `worksheet_write_url()`. + * + * @param workbook Pointer to a lxw_workbook instance. + * @return A lxw_format instance that has hyperlink properties set. + * + * This function returns a lxw_format instance that is used for the default + * blue underline hyperlink in the `worksheet_write_url()` function when a + * format isn't specified: + * + * @code + * lxw_format *url_format = workbook_get_default_url_format(workbook); + * @endcode + * + * The format is the hyperlink style defined by Excel for the default theme. + * This format is only ever required when overwriting a string URL with + * data of a different type. See the example below. + */ +lxw_format *workbook_get_default_url_format(lxw_workbook *workbook); + +/** * @brief Get a worksheet object from its name. * * @param workbook Pointer to a lxw_workbook instance. * @param name Worksheet name. * @@ -832,21 +933,24 @@ * to the rules used by Excel: * * - The name is less than or equal to 31 UTF-8 characters. * - The name doesn't contain any of the characters: ` [ ] : * ? / \ ` * - The name doesn't start or end with an apostrophe. - * - The name isn't "History", which is reserved by Excel. (Case insensitive). * - The name isn't already in use. (Case insensitive, see the note below). * * @code * lxw_error err = workbook_validate_sheet_name(workbook, "Foglio"); * @endcode * * This function is called by `workbook_add_worksheet()` and * `workbook_add_chartsheet()` but it can be explicitly called by the user * beforehand to ensure that the sheet name is valid. * + * @note You should also avoid using the worksheet name "History" (case + * insensitive) which is reserved in English language versions of + * Excel. Non-English versions may have restrictions on the equivalent word. + * * @note This function does an ASCII lowercase string comparison to determine * if the sheet name is already in use. It doesn't take UTF-8 characters into * account. Thus it would flag "Café" and "café" as a duplicate (just like * Excel) but it wouldn't catch "CAFÉ". If you need a full UTF-8 case * insensitive check you should use a third party library to implement it. @@ -867,39 +971,106 @@ * * @code * workbook_add_vba_project(workbook, "vbaProject.bin"); * @endcode * - * Only one `vbaProject.bin file` can be added per workbook. + * Only one `vbaProject.bin` file can be added per workbook. The name doesn't + * have to be `vbaProject.bin`. Any suitable path/name for an existing VBA bin + * file will do. * + * Once you add a VBA project had been add to an libxlsxwriter workbook you + * should ensure that the file extension is `.xlsm` to prevent Excel from + * giving a warning when it opens the file: + * + * @code + * lxw_workbook *workbook = new_workbook("macro.xlsm"); + * @endcode + * + * See also @ref working_with_macros + * * @return A #lxw_error. */ lxw_error workbook_add_vba_project(lxw_workbook *workbook, const char *filename); /** + * @brief Add a vbaProject binary and a vbaProjectSignature binary to the Excel + * workbook. + * + * @param workbook Pointer to a lxw_workbook instance. + * @param vba_project The path/filename of the vbaProject.bin file. + * @param signature The path/filename of the vbaProjectSignature.bin file. + * + * The `%workbook_add_signed_vba_project()` function can be used to add digitally + * signed macros or functions to a workbook. The function adds a binary VBA project + * file and a binary VBA project signature file that have been extracted from an + * existing Excel xlsm file with digitally signed macros: + * + * @code + * workbook_add_signed_vba_project(workbook, "vbaProject.bin", "vbaProjectSignature.bin"); + * @endcode + * + * Only one `vbaProject.bin` file can be added per workbook. The name doesn't + * have to be `vbaProject.bin`. Any suitable path/name for an existing VBA bin + * file will do. The same applies for `vbaProjectSignature.bin`. + * + * See also @ref working_with_macros + * + * @return A #lxw_error. + */ +lxw_error workbook_add_signed_vba_project(lxw_workbook *workbook, + const char *vba_project, + const char *signature); + +/** * @brief Set the VBA name for the workbook. * * @param workbook Pointer to a lxw_workbook instance. * @param name Name of the workbook used by VBA. * * The `workbook_set_vba_name()` function can be used to set the VBA name for * the workbook. This is sometimes required when a vbaProject macro included - * via `workbook_add_vba_project()` refers to the workbook. + * via `workbook_add_vba_project()` refers to the workbook by a name other + * than `ThisWorkbook`. * * @code * workbook_set_vba_name(workbook, "MyWorkbook"); * @endcode * - * The most common Excel VBA name for a workbook is `ThisWorkbook`. + * If an Excel VBA name for the workbook isn't specified then libxlsxwriter + * will use `ThisWorkbook`. * + * See also @ref working_with_macros + * * @return A #lxw_error. */ lxw_error workbook_set_vba_name(lxw_workbook *workbook, const char *name); +/** + * @brief Add a recommendation to open the file in "read-only" mode. + * + * @param workbook Pointer to a lxw_workbook instance. + * + * This function can be used to set the Excel "Read-only Recommended" option + * that is available when saving a file. This presents the user of the file + * with an option to open it in "read-only" mode. This means that any changes + * to the file can't be saved back to the same file and must be saved to a new + * file. It can be set as follows: + * + * @code + * workbook_read_only_recommended(workbook); + * @endcode + * + * Which will raise a dialog like the following when opening the file: + * + * @image html read_only.png + */ +void workbook_read_only_recommended(lxw_workbook *workbook); + void lxw_workbook_free(lxw_workbook *workbook); void lxw_workbook_assemble_xml_file(lxw_workbook *workbook); void lxw_workbook_set_default_xf_indices(lxw_workbook *workbook); +void workbook_unset_default_url_format(lxw_workbook *workbook); /* Declarations required for unit testing. */ #ifdef TESTING STATIC void _workbook_xml_declaration(lxw_workbook *self);