libxlsxwriter/src/relationships.c
2019-02-10 21:11:46 +00:00

245 lines
6.2 KiB
C

/*****************************************************************************
* relationships - A library for creating Excel XLSX relationships files.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include <string.h>
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/relationships.h"
#include "xlsxwriter/utility.h"
/*
* Forward declarations.
*/
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/*
* Create a new relationships object.
*/
lxw_relationships *
lxw_relationships_new(void)
{
lxw_relationships *rels = calloc(1, sizeof(lxw_relationships));
GOTO_LABEL_ON_MEM_ERROR(rels, mem_error);
rels->relationships = calloc(1, sizeof(struct lxw_rel_tuples));
GOTO_LABEL_ON_MEM_ERROR(rels->relationships, mem_error);
STAILQ_INIT(rels->relationships);
return rels;
mem_error:
lxw_free_relationships(rels);
return NULL;
}
/*
* Free a relationships object.
*/
void
lxw_free_relationships(lxw_relationships *rels)
{
lxw_rel_tuple *relationship;
if (!rels)
return;
if (rels->relationships) {
while (!STAILQ_EMPTY(rels->relationships)) {
relationship = STAILQ_FIRST(rels->relationships);
STAILQ_REMOVE_HEAD(rels->relationships, list_pointers);
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
free(rels->relationships);
}
free(rels);
}
/*****************************************************************************
*
* XML functions.
*
****************************************************************************/
/*
* Write the XML declaration.
*/
STATIC void
_relationships_xml_declaration(lxw_relationships *self)
{
lxw_xml_declaration(self->file);
}
/*
* Write the <Relationship> element.
*/
STATIC void
_write_relationship(lxw_relationships *self, const char *type,
const char *target, const char *target_mode)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char r_id[LXW_MAX_ATTRIBUTE_LENGTH] = { 0 };
self->rel_id++;
lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", self->rel_id);
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("Id", r_id);
LXW_PUSH_ATTRIBUTES_STR("Type", type);
LXW_PUSH_ATTRIBUTES_STR("Target", target);
if (target_mode)
LXW_PUSH_ATTRIBUTES_STR("TargetMode", target_mode);
lxw_xml_empty_tag(self->file, "Relationship", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the <Relationships> element.
*/
STATIC void
_write_relationships(lxw_relationships *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_rel_tuple *rel;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns", LXW_SCHEMA_PACKAGE);
lxw_xml_start_tag(self->file, "Relationships", &attributes);
STAILQ_FOREACH(rel, self->relationships, list_pointers) {
_write_relationship(self, rel->type, rel->target, rel->target_mode);
}
LXW_FREE_ATTRIBUTES();
}
/*****************************************************************************
*
* XML file assembly functions.
*
****************************************************************************/
/*
* Assemble and write the XML file.
*/
void
lxw_relationships_assemble_xml_file(lxw_relationships *self)
{
/* Write the XML declaration. */
_relationships_xml_declaration(self);
_write_relationships(self);
/* Close the relationships tag. */
lxw_xml_end_tag(self->file, "Relationships");
}
/*
* Add a generic container relationship to XLSX .rels xml files.
*/
STATIC void
_add_relationship(lxw_relationships *self, const char *schema,
const char *type, const char *target,
const char *target_mode)
{
lxw_rel_tuple *relationship;
if (!schema || !type || !target)
return;
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = calloc(1, LXW_MAX_ATTRIBUTE_LENGTH);
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
/* Add the schema to the relationship type. */
lxw_snprintf(relationship->type, LXW_MAX_ATTRIBUTE_LENGTH, "%s%s",
schema, type);
relationship->target = lxw_strdup(target);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
if (target_mode) {
relationship->target_mode = lxw_strdup(target_mode);
GOTO_LABEL_ON_MEM_ERROR(relationship->target_mode, mem_error);
}
STAILQ_INSERT_TAIL(self->relationships, relationship, list_pointers);
return;
mem_error:
if (relationship) {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
}
/*****************************************************************************
*
* Public functions.
*
****************************************************************************/
/*
* Add a document relationship to XLSX .rels xml files.
*/
void
lxw_add_document_relationship(lxw_relationships *self, const char *type,
const char *target)
{
_add_relationship(self, LXW_SCHEMA_DOCUMENT, type, target, NULL);
}
/*
* Add a package relationship to XLSX .rels xml files.
*/
void
lxw_add_package_relationship(lxw_relationships *self, const char *type,
const char *target)
{
_add_relationship(self, LXW_SCHEMA_PACKAGE, type, target, NULL);
}
/*
* Add a MS schema package relationship to XLSX .rels xml files.
*/
void
lxw_add_ms_package_relationship(lxw_relationships *self, const char *type,
const char *target)
{
_add_relationship(self, LXW_SCHEMA_MS, type, target, NULL);
}
/*
* Add a worksheet relationship to sheet .rels xml files.
*/
void
lxw_add_worksheet_relationship(lxw_relationships *self, const char *type,
const char *target, const char *target_mode)
{
_add_relationship(self, LXW_SCHEMA_DOCUMENT, type, target, target_mode);
}