Files
php-ext-xlswriter/library/libxlsxwriter/src/comment.c
2024-03-05 10:01:08 +08:00

444 lines
10 KiB
C

/*****************************************************************************
* comment - A library for creating Excel XLSX comment files.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/comment.h"
#include "xlsxwriter/utility.h"
/*
* Forward declarations.
*/
STATIC int _author_id_cmp(lxw_author_id *tuple1, lxw_author_id *tuple2);
#ifndef __clang_analyzer__
LXW_RB_GENERATE_AUTHOR_IDS(lxw_author_ids, lxw_author_id,
tree_pointers, _author_id_cmp);
#endif
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/*
* Comparator for the author ids.
*/
STATIC int
_author_id_cmp(lxw_author_id *author_id1, lxw_author_id *author_id2)
{
return strcmp(author_id1->author, author_id2->author);
}
/*
* Check if an author already existing in the author/id table.
*/
STATIC uint8_t
_check_author(lxw_comment *self, char *author)
{
lxw_author_id tmp_author_id;
lxw_author_id *existing_author = NULL;
if (!author)
return LXW_TRUE;
tmp_author_id.author = author;
existing_author = RB_FIND(lxw_author_ids,
self->author_ids, &tmp_author_id);
if (existing_author)
return LXW_TRUE;
else
return LXW_FALSE;
}
/*
* Get the index used for an author name.
*/
STATIC uint32_t
_get_author_index(lxw_comment *self, char *author)
{
lxw_author_id tmp_author_id;
lxw_author_id *existing_author = NULL;
lxw_author_id *new_author_id = NULL;
if (!author)
return 0;
tmp_author_id.author = author;
existing_author = RB_FIND(lxw_author_ids,
self->author_ids, &tmp_author_id);
if (existing_author) {
return existing_author->id;
}
else {
new_author_id = calloc(1, sizeof(lxw_author_id));
if (new_author_id) {
new_author_id->id = self->author_id;
new_author_id->author = lxw_strdup(author);
self->author_id++;
RB_INSERT(lxw_author_ids, self->author_ids, new_author_id);
return new_author_id->id;
}
else {
return 0;
}
}
}
/*
* Create a new comment object.
*/
lxw_comment *
lxw_comment_new(void)
{
lxw_comment *comment = calloc(1, sizeof(lxw_comment));
GOTO_LABEL_ON_MEM_ERROR(comment, mem_error);
comment->author_ids = calloc(1, sizeof(struct lxw_author_ids));
GOTO_LABEL_ON_MEM_ERROR(comment->author_ids, mem_error);
RB_INIT(comment->author_ids);
return comment;
mem_error:
lxw_comment_free(comment);
return NULL;
}
/*
* Free a comment object.
*/
void
lxw_comment_free(lxw_comment *comment)
{
struct lxw_author_id *author_id;
struct lxw_author_id *next_author_id;
if (!comment)
return;
if (comment->author_ids) {
for (author_id =
RB_MIN(lxw_author_ids, comment->author_ids);
author_id; author_id = next_author_id) {
next_author_id =
RB_NEXT(lxw_author_ids, worksheet->author_id, author_id);
RB_REMOVE(lxw_author_ids, comment->author_ids, author_id);
free(author_id->author);
free(author_id);
}
free(comment->author_ids);
}
free(comment);
}
/*****************************************************************************
*
* XML functions.
*
****************************************************************************/
/*
* Write the XML declaration.
*/
STATIC void
_comment_xml_declaration(lxw_comment *self)
{
lxw_xml_declaration(self->file);
}
/*****************************************************************************
*
* XML file assembly functions.
*
****************************************************************************/
/*
* Write the <t> element.
*/
STATIC void
_comment_write_text_t(lxw_comment *self, lxw_vml_obj *comment_obj)
{
lxw_xml_data_element(self->file, "t", comment_obj->text, NULL);
}
/*
* Write the <family> element.
*/
STATIC void
_comment_write_family(lxw_comment *self, lxw_vml_obj *comment_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("val", comment_obj->font_family);
lxw_xml_empty_tag(self->file, "family", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the <rFont> element.
*/
STATIC void
_comment_write_r_font(lxw_comment *self, lxw_vml_obj *comment_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char font_name[LXW_ATTR_32];
if (comment_obj->font_name)
lxw_snprintf(font_name, LXW_ATTR_32, "%s", comment_obj->font_name);
else
lxw_snprintf(font_name, LXW_ATTR_32, "Tahoma");
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("val", font_name);
lxw_xml_empty_tag(self->file, "rFont", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the <color> element.
*/
STATIC void
_comment_write_color(lxw_comment *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char indexed[] = "81";
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("indexed", indexed);
lxw_xml_empty_tag(self->file, "color", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the <sz> element.
*/
STATIC void
_comment_write_sz(lxw_comment *self, lxw_vml_obj *comment_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_DBL("val", comment_obj->font_size);
lxw_xml_empty_tag(self->file, "sz", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the <rPr> element.
*/
STATIC void
_comment_write_r_pr(lxw_comment *self, lxw_vml_obj *comment_obj)
{
lxw_xml_start_tag(self->file, "rPr", NULL);
/* Write the sz element. */
_comment_write_sz(self, comment_obj);
/* Write the color element. */
_comment_write_color(self);
/* Write the rFont element. */
_comment_write_r_font(self, comment_obj);
/* Write the family element. */
_comment_write_family(self, comment_obj);
lxw_xml_end_tag(self->file, "rPr");
}
/*
* Write the <r> element.
*/
STATIC void
_comment_write_r(lxw_comment *self, lxw_vml_obj *comment_obj)
{
lxw_xml_start_tag(self->file, "r", NULL);
/* Write the rPr element. */
_comment_write_r_pr(self, comment_obj);
/* Write the t element. */
_comment_write_text_t(self, comment_obj);
lxw_xml_end_tag(self->file, "r");
}
/*
* Write the <text> element.
*/
STATIC void
_comment_write_text(lxw_comment *self, lxw_vml_obj *comment_obj)
{
lxw_xml_start_tag(self->file, "text", NULL);
/* Write the r element. */
_comment_write_r(self, comment_obj);
lxw_xml_end_tag(self->file, "text");
}
/*
* Write the <comment> element.
*/
STATIC void
_comment_write_comment(lxw_comment *self, lxw_vml_obj *comment_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char ref[LXW_MAX_CELL_NAME_LENGTH];
lxw_rowcol_to_cell(ref, comment_obj->row, comment_obj->col);
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("ref", ref);
LXW_PUSH_ATTRIBUTES_INT("authorId", comment_obj->author_id);
lxw_xml_start_tag(self->file, "comment", &attributes);
/* Write the text element. */
_comment_write_text(self, comment_obj);
lxw_xml_end_tag(self->file, "comment");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the <commentList> element.
*/
STATIC void
_comment_write_comment_list(lxw_comment *self)
{
lxw_vml_obj *comment_obj;
lxw_xml_start_tag(self->file, "commentList", NULL);
STAILQ_FOREACH(comment_obj, self->comment_objs, list_pointers) {
/* Write the comment element. */
_comment_write_comment(self, comment_obj);
}
lxw_xml_end_tag(self->file, "commentList");
}
/*
* Write the <author> element.
*/
STATIC void
_comment_write_author(lxw_comment *self, char *author)
{
lxw_xml_data_element(self->file, "author", author, NULL);
}
/*
* Write the <authors> element.
*/
STATIC void
_comment_write_authors(lxw_comment *self)
{
lxw_vml_obj *comment_obj;
char *author;
lxw_xml_start_tag(self->file, "authors", NULL);
/* Set the default author (from worksheet_set_comments_author()). */
if (self->comment_author) {
_get_author_index(self, self->comment_author);
_comment_write_author(self, self->comment_author);
}
else {
_get_author_index(self, "");
_comment_write_author(self, "");
}
STAILQ_FOREACH(comment_obj, self->comment_objs, list_pointers) {
author = comment_obj->author;
if (author) {
if (!_check_author(self, author))
_comment_write_author(self, author);
comment_obj->author_id = _get_author_index(self, author);
}
}
lxw_xml_end_tag(self->file, "authors");
}
/*
* Write the <comments> element.
*/
STATIC void
_comment_write_comments(lxw_comment *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char xmlns[] =
"http://schemas.openxmlformats.org/spreadsheetml/2006/main";
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
lxw_xml_start_tag(self->file, "comments", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Assemble and write the XML file.
*/
void
lxw_comment_assemble_xml_file(lxw_comment *self)
{
/* Write the XML declaration. */
_comment_xml_declaration(self);
/* Write the comments element. */
_comment_write_comments(self);
/* Write the authors element. */
_comment_write_authors(self);
/* Write the commentList element. */
_comment_write_comment_list(self);
lxw_xml_end_tag(self->file, "comments");
}
/*****************************************************************************
*
* Public functions.
*
****************************************************************************/