From 5da747ff564cdcfeff90c5f5cfcfac03bc48332b Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Fri, 6 Jul 2007 14:32:44 +0000 Subject: Import DOM library. This is mainly stub functions atm (and is missing a number of key interfaces). svn path=/trunk/dom/; revision=3384 --- src/core/Makefile | 53 +++ src/core/attr.c | 173 +++++++++ src/core/document.c | 356 +++++++++++++++++ src/core/document.h | 19 + src/core/node.c | 1069 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/core/node.h | 60 +++ src/core/string.c | 222 +++++++++++ 7 files changed, 1952 insertions(+) create mode 100644 src/core/Makefile create mode 100644 src/core/attr.c create mode 100644 src/core/document.c create mode 100644 src/core/document.h create mode 100644 src/core/node.c create mode 100644 src/core/node.h create mode 100644 src/core/string.c (limited to 'src/core') diff --git a/src/core/Makefile b/src/core/Makefile new file mode 100644 index 0000000..3924ebb --- /dev/null +++ b/src/core/Makefile @@ -0,0 +1,53 @@ +# Makefile for libdom +# +# Toolchain is exported by top-level makefile +# +# Top-level makefile also exports the following variables: +# +# COMPONENT Name of component +# EXPORT Absolute path of export directory +# TOP Absolute path of source tree root +# +# The top-level makefile requires the following targets to exist: +# +# clean Clean source tree +# debug Create a debug binary +# distclean Fully clean source tree, back to pristine condition +# export Export distributable components to ${EXPORT} +# release Create a release binary +# setup Perform any setup required prior to compilation +# test Execute any test cases + +# Manipulate include paths +CFLAGS += -I$(CURDIR) + +# Objects +OBJS = attr document node string + +.PHONY: clean debug distclean export release setup test + +# Targets +release: $(addprefix ../Release/, $(addsuffix .o, $(OBJS))) + +debug: $(addprefix ../Debug/, $(addsuffix .o, $(OBJS))) + +clean: + -@${RM} ${RMFLAGS} $(addprefix ../Release/, $(addsuffix .o, ${OBJS})) + -@${RM} ${RMFLAGS} $(addprefix ../Debug/, $(addsuffix .o, ${OBJS})) + +distclean: + +setup: + +export: + +test: + +# Pattern rules +../Release/%.o: %.c + @${ECHO} ${ECHOFLAGS} "==> $<" + @${CC} -c ${CFLAGS} -DNDEBUG -o $@ $< + +../Debug/%.o: %.c + @${ECHO} ${ECHOFLAGS} "==> $<" + @${CC} -c -g ${CFLAGS} -o $@ $< diff --git a/src/core/attr.c b/src/core/attr.c new file mode 100644 index 0000000..32fa66f --- /dev/null +++ b/src/core/attr.c @@ -0,0 +1,173 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#include + +#include "core/node.h" +#include "utils/utils.h" + +struct dom_element; +struct dom_typeinfo; + +/** + * DOM node attribute + */ +struct dom_attr { + struct dom_node base; /**< Base node */ + + bool specified; /**< Whether attribute was specified + * or defaulted */ + + struct dom_element *owner; /**< Owning element */ + + struct dom_typeinfo *schema_type_info; /**< Type information */ + + bool is_id; /**< Attribute is of type ID */ +}; + +/** + * Retrieve an attribute's name + * + * \param ctx The context in which the attribute resides + * \param attr Attribute to retrieve name from + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + */ +dom_exception dom_attr_get_name(struct dom_ctx *ctx, + struct dom_attr *attr, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(attr); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Determine if attribute was specified or defaulted + * + * \param ctx The context in which the attribute resides + * \param attr Attribute to inspect + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_attr_get_specified(struct dom_ctx *ctx, + struct dom_attr *attr, bool *result) +{ + UNUSED(ctx); + + *result = attr->specified; + + return DOM_NO_ERR; +} + +/** + * Retrieve an attribute's value + * + * \param ctx The context in which the attribute resides + * \param attr Attribute to retrieve value from + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + */ +dom_exception dom_attr_get_value(struct dom_ctx *ctx, + struct dom_attr *attr, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(attr); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Set an attribute's value + * + * \param ctx The context in which the attribute resides + * \param attr Attribute to retrieve value from + * \param value New value for attribute + * \return DOM_NO_ERR on success, + * DOM_NO_MODIFICATION_ALLOWED_ERR if attribute is readonly. + */ +dom_exception dom_attr_set_value(struct dom_ctx *ctx, + struct dom_attr *attr, struct dom_string *value) +{ + UNUSED(ctx); + UNUSED(attr); + UNUSED(value); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieve the owning element of an attribute + * + * \param ctx The context in which the attribute resides + * \param attr The attribute to extract owning element from + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + * + * The returned node will have its reference count increased. The caller + * should unref it once it has finished with it. + */ +dom_exception dom_attr_get_owner(struct dom_ctx *ctx, + struct dom_attr *attr, struct dom_element **result) +{ + /* If there is an owning element, increase its reference count */ + if (attr->owner != NULL) + dom_node_ref(ctx, (struct dom_node *) attr->owner); + + *result = attr->owner; + + return DOM_NO_ERR; +} + +/** + * Retrieve an attribute's type information + * + * \param ctx The context in which the attribute resides + * \param attr The attribute to extract type information from + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + * + * The returned typeinfo will have its reference count increased. The caller + * should unref it once it has finished with it. + */ +dom_exception dom_attr_get_typeinfo(struct dom_ctx *ctx, + struct dom_attr *attr, struct dom_typeinfo **result) +{ + UNUSED(ctx); + UNUSED(attr); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Determine if an attribute if of type ID + * + * \param ctx The context in which the attribute resides + * \param attr The attribute to inspect + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_attr_is_id(struct dom_ctx *ctx, + struct dom_attr *attr, bool *result) +{ + UNUSED(ctx); + + *result = attr->is_id; + + return DOM_NO_ERR; +} diff --git a/src/core/document.c b/src/core/document.c new file mode 100644 index 0000000..1d54dfd --- /dev/null +++ b/src/core/document.c @@ -0,0 +1,356 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#include + +#include "core/node.h" +#include "utils/utils.h" + +/** + * DOM document + */ +struct dom_document { + struct dom_node base; /**< Base node */ +}; + + +dom_exception dom_document_get_doctype(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_document_type **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_implementation(struct dom_ctx *ctx, + struct dom_document *doc, + struct dom_implementation **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_element(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_element **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_create_element(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *tag_name, + struct dom_element **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(tag_name); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_create_document_fragment(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_create_text_node(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *data, + struct dom_text **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(data); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_create_cdata_section(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *data, + struct dom_text **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(data); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_create_processing_instruction(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *target, + struct dom_string *data, + struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(target); + UNUSED(data); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_create_attribute(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *name, + struct dom_attr **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(name); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_create_entity_reference(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *name, + struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(name); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_elements_by_tag_name(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *tagname, + struct dom_nodelist **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(tagname); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_import_node(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_node *node, + bool deep, struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(node); + UNUSED(deep); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_create_element_ns(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *namespace, + struct dom_string *qname, struct dom_element **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(namespace); + UNUSED(qname); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_create_attribute_ns(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *namespace, + struct dom_string *qname, struct dom_attr **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(namespace); + UNUSED(qname); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_elements_by_tag_name_ns(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *namespace, + struct dom_string *localname, struct dom_nodelist **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(namespace); + UNUSED(localname); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_element_by_id(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *id, + struct dom_element **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(id); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_input_encoding(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_xml_encoding(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_xml_standalone(struct dom_ctx *ctx, + struct dom_document *doc, bool *result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_set_xml_standalone(struct dom_ctx *ctx, + struct dom_document *doc, bool standalone) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(standalone); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_xml_version(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_set_xml_version(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *version) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(version); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_strict_error_checking(struct dom_ctx *ctx, + struct dom_document *doc, bool *result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_set_strict_error_checking(struct dom_ctx *ctx, + struct dom_document *doc, bool strict) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(strict); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_uri(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_set_uri(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_string *uri) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(uri); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_adopt_node(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_node *node, + struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(node); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_get_dom_config(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_configuration **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_normalize(struct dom_ctx *ctx, + struct dom_document *doc) +{ + UNUSED(ctx); + UNUSED(doc); + + return DOM_NOT_SUPPORTED_ERR; +} + +dom_exception dom_document_rename_node(struct dom_ctx *ctx, + struct dom_document *doc, struct dom_node *node, + struct dom_string *namespace, struct dom_string *qname, + struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(doc); + UNUSED(node); + UNUSED(namespace); + UNUSED(qname); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} diff --git a/src/core/document.h b/src/core/document.h new file mode 100644 index 0000000..399b2c8 --- /dev/null +++ b/src/core/document.h @@ -0,0 +1,19 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#ifndef dom_internal_document_h_ +#define dom_internal_document_h_ + +#include + +struct dom_ctx; +struct dom_document; + +const uint8_t *dom_document_get_base(struct dom_ctx *ctx, + struct dom_document *doc); + +#endif diff --git a/src/core/node.c b/src/core/node.c new file mode 100644 index 0000000..4c2af88 --- /dev/null +++ b/src/core/node.c @@ -0,0 +1,1069 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#include + +#include "core/node.h" +#include "utils/utils.h" + +/** + * Create a DOM node + * + * \param ctx The context in which the node resides + * \param doc The document which owns the node + * \param type The node type required + * \param name The node name, or NULL + * \param value The node value, or NULL + * \param node Pointer to location to receive created node + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * + * The returned node will be referenced, so there is no need for the caller + * to explicitly reference it. + */ +dom_exception dom_node_create(struct dom_ctx *ctx, + struct dom_document *doc, dom_node_type type, + struct dom_string *name, struct dom_string *value, + struct dom_node **node) +{ + struct dom_node *n; + + n = ctx->alloc(NULL, sizeof(struct dom_node), ctx->pw); + if (n == NULL) + return DOM_NO_MEM_ERR; + + if (name != NULL) + dom_string_ref(ctx, name); + n->name = name; + + if (value != NULL) + dom_string_ref(ctx, value); + n->value = value; + + n->type = type; + + n->parent = NULL; + n->first_child = NULL; + n->last_child = NULL; + n->previous = NULL; + n->next = NULL; + n->attributes = NULL; + + dom_node_ref(ctx, (struct dom_node *) doc); + n->owner = doc; + + /** \todo Namespace handling */ + n->namespace = NULL; + n->prefix = NULL; + n->localname = NULL; + + n->user_data = NULL; + + n->refcnt = 1; + + *node = n; + + return DOM_NO_ERR; +} + +/** + * Claim a reference on a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to claim a reference on + */ +void dom_node_ref(struct dom_ctx *ctx, struct dom_node *node) +{ + UNUSED(ctx); + + node->refcnt++; +} + +/** + * Release a reference on a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to release the reference from + * + * If the reference count reaches zero, any memory claimed by the + * node will be released + */ +void dom_node_unref(struct dom_ctx *ctx, struct dom_node *node) +{ + UNUSED(ctx); + + if (--node->refcnt == 0) { + /** \todo implement */ + } +} + +/** + * Retrieve the name of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the name of + * \param result Pointer to location to receive node name + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + */ +dom_exception dom_node_get_name(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieve the value of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the value of + * \param result Pointer to location to receive node value + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + * + * DOM3Core states that this can raise DOMSTRING_SIZE_ERR. It will not in + * this implementation; dom_strings are unbounded. + */ +dom_exception dom_node_get_value(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Set the value of a DOM node + * + * \param ctx The context in which the node resides + * \param node Node to set the value of + * \param value New value for node + * \return DOM_NO_ERR on success, + * DOM_NO_MODIFICATION_ALLOWED_ERR if the node is readonly and the + * value is not defined to be null. + * + * The new value will have its reference count increased, so the caller + * should unref it after the call (as the caller should have already claimed + * a reference on the string). The node's existing value will be unrefed. + */ +dom_exception dom_node_set_value(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *value) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(value); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieve the type of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the type of + * \param result Pointer to location to receive node type + * \return DOM_NO_ERR. + */ +dom_exception dom_node_get_type(struct dom_ctx *ctx, + struct dom_node *node, dom_node_type *result) +{ + UNUSED(ctx); + + *result = node->type; + + return DOM_NO_ERR; +} + +/** + * Retrieve the parent of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the parent of + * \param result Pointer to location to receive node parent + * \return DOM_NO_ERR. + * + * The returned node will have its reference count increased. It is + * the responsibility of the caller to unref the node once it has + * finished with it. + */ +dom_exception dom_node_get_parent(struct dom_ctx *ctx, + struct dom_node *node, struct dom_node **result) +{ + /* If there is a parent node, then increase its reference count */ + if (node->parent != NULL) + dom_node_ref(ctx, node->parent); + + *result = node->parent; + + return DOM_NO_ERR; +} + +/** + * Retrieve a list of children of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the children of + * \param result Pointer to location to receive child list + * \return DOM_NO_ERR. + * + * \todo Work out reference counting semantics of dom_node_list + */ +dom_exception dom_node_get_children(struct dom_ctx *ctx, + struct dom_node *node, struct dom_node_list **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieve the first child of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the first child of + * \param result Pointer to location to receive node's first child + * \return DOM_NO_ERR. + * + * The returned node will have its reference count increased. It is + * the responsibility of the caller to unref the node once it has + * finished with it. + */ +dom_exception dom_node_get_first_child(struct dom_ctx *ctx, + struct dom_node *node, struct dom_node **result) +{ + /* If there is a first child, increase its reference count */ + if (node->first_child != NULL) + dom_node_ref(ctx, node->first_child); + + *result = node->first_child; + + return DOM_NO_ERR; +} + +/** + * Retrieve the last child of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the last child of + * \param result Pointer to location to receive node's last child + * \return DOM_NO_ERR. + * + * The returned node will have its reference count increased. It is + * the responsibility of the caller to unref the node once it has + * finished with it. + */ +dom_exception dom_node_get_last_child(struct dom_ctx *ctx, + struct dom_node *node, struct dom_node **result) +{ + /* If there is a last child, increase its reference count */ + if (node->last_child != NULL) + dom_node_ref(ctx, node->last_child); + + *result = node->last_child; + + return DOM_NO_ERR; +} + +/** + * Retrieve the previous sibling of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the previous sibling of + * \param result Pointer to location to receive node's previous sibling + * \return DOM_NO_ERR. + * + * The returned node will have its reference count increased. It is + * the responsibility of the caller to unref the node once it has + * finished with it. + */ +dom_exception dom_node_get_previous(struct dom_ctx *ctx, + struct dom_node *node, struct dom_node **result) +{ + /* If there is a previous sibling, increase its reference count */ + if (node->previous != NULL) + dom_node_ref(ctx, node->previous); + + *result = node->previous; + + return DOM_NO_ERR; +} + +/** + * Retrieve the subsequent sibling of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the subsequent sibling of + * \param result Pointer to location to receive node's subsequent sibling + * \return DOM_NO_ERR. + * + * The returned node will have its reference count increased. It is + * the responsibility of the caller to unref the node once it has + * finished with it. + */ +dom_exception dom_node_get_next(struct dom_ctx *ctx, + struct dom_node *node, struct dom_node **result) +{ + /* If there is a subsequent sibling, increase its reference count */ + if (node->next != NULL) + dom_node_ref(ctx, node->next); + + *result = node->next; + + return DOM_NO_ERR; +} + +/** + * Retrieve a map of attributes associated with a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the attributes of + * \param result Pointer to location to receive attribute map + * \return DOM_NO_ERR. + * + * \todo Work out reference counting semantics of dom_named_node_map + */ +dom_exception dom_node_get_attributes(struct dom_ctx *ctx, + struct dom_node *node, struct dom_named_node_map **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieve the owning document of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the owner of + * \param result Pointer to location to receive node's owner + * \return DOM_NO_ERR. + * + * The returned node will have its reference count increased. It is + * the responsibility of the caller to unref the node once it has + * finished with it. + */ +dom_exception dom_node_get_owner(struct dom_ctx *ctx, + struct dom_node *node, struct dom_document **result) +{ + /* If there is an owner, increase its reference count */ + if (node->owner != NULL) + dom_node_ref(ctx, (struct dom_node *) node->owner); + + *result = node->owner; + + return DOM_NO_ERR; +} + +/** + * Insert a child into a node + * + * \param ctx The context in which the nodes reside + * \param node Node to insert into + * \param new_child Node to insert + * \param ref_child Node to insert before, or NULL to insert as last child + * \param result Pointer to location to receive node being inserted + * \return DOM_NO_ERR on success, + * DOM_HIERARCHY_REQUEST_ERR if ::new_child's type is not + * permitted as a child of ::node, + * or ::new_child is an ancestor of + * ::node (or is ::node itself), or + * ::node is of type Document and a + * second DocumentType or Element is + * being inserted, + * DOM_WRONG_DOCUMENT_ERR if ::new_child was created from a + * different document than ::node, + * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or + * ::new_child's parent is readonly, + * DOM_NOT_FOUND_ERR if ::ref_child is not a child of + * ::node, + * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and + * ::new_child is of type + * DocumentType or Element. + * + * If ::new_child is a DocumentFragment, all of its children are inserted. + * If ::new_child is already in the tree, it is first removed. + * + * ::new_child's reference count will be increased. The caller should unref + * it (as they should already have held a reference on the node) + */ +dom_exception dom_node_insert_before(struct dom_ctx *ctx, + struct dom_node *node, + struct dom_node *new_child, struct dom_node *ref_child, + struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(new_child); + UNUSED(ref_child); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Replace a node's child with a new one + * + * \param ctx The context in which the nodes reside + * \param node Node whose child to replace + * \param new_child Replacement node + * \param old_child Child to replace + * \param result Pointer to location to receive replaced node + * \return DOM_NO_ERR on success, + * DOM_HIERARCHY_REQUEST_ERR if ::new_child's type is not + * permitted as a child of ::node, + * or ::new_child is an ancestor of + * ::node (or is ::node itself), or + * ::node is of type Document and a + * second DocumentType or Element is + * being inserted, + * DOM_WRONG_DOCUMENT_ERR if ::new_child was created from a + * different document than ::node, + * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or + * ::new_child's parent is readonly, + * DOM_NOT_FOUND_ERR if ::old_child is not a child of + * ::node, + * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and + * ::new_child is of type + * DocumentType or Element. + * + * If ::new_child is a DocumentFragment, ::old_child is replaced by all of + * ::new_child's children. + * If ::new_child is already in the tree, it is first removed. + * + * ::new_child's reference count will be increased. The caller should unref + * it (as they should already have held a reference on the node) + * + * ::old_child's reference count remains unmodified (::node's reference is + * transferred to the caller). The caller should unref ::old_child once it + * is finished with it. + */ +dom_exception dom_node_replace_child(struct dom_ctx *ctx, + struct dom_node *node, + struct dom_node *new_child, struct dom_node *old_child, + struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(new_child); + UNUSED(old_child); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Remove a child from a node + * + * \param ctx The context in which the nodes reside + * \param node Node whose child to replace + * \param old_child Child to remove + * \param result Pointer to location to receive removed node + * \return DOM_NO_ERR on success, + * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly + * DOM_NOT_FOUND_ERR if ::old_child is not a child of + * ::node, + * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and + * ::new_child is of type + * DocumentType or Element. + * + * ::old_child's reference count remains unmodified (::node's reference is + * transferred to the caller). The caller should unref ::old_child once it + * is finished with it. + */ +dom_exception dom_node_remove_child(struct dom_ctx *ctx, + struct dom_node *node, + struct dom_node *old_child, + struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(old_child); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Append a child to the end of a node's child list + * + * \param ctx The context in which the nodes reside + * \param node Node to insert into + * \param new_child Node to append + * \param result Pointer to location to receive node being inserted + * \return DOM_NO_ERR on success, + * DOM_HIERARCHY_REQUEST_ERR if ::new_child's type is not + * permitted as a child of ::node, + * or ::new_child is an ancestor of + * ::node (or is ::node itself), or + * ::node is of type Document and a + * second DocumentType or Element is + * being inserted, + * DOM_WRONG_DOCUMENT_ERR if ::new_child was created from a + * different document than ::node, + * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or + * ::new_child's parent is readonly, + * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and + * ::new_child is of type + * DocumentType or Element. + * + * If ::new_child is a DocumentFragment, all of its children are inserted. + * If ::new_child is already in the tree, it is first removed. + * + * ::new_child's reference count will be increased. The caller should unref + * it (as they should already have held a reference on the node) + */ +dom_exception dom_node_append_child(struct dom_ctx *ctx, + struct dom_node *node, + struct dom_node *new_child, + struct dom_node **result) +{ + /* This is just a veneer over insert_before */ + return dom_node_insert_before(ctx, node, new_child, NULL, result); +} + +/** + * Determine if a node has any children + * + * \param ctx The context in which the node resides + * \param node Node to inspect + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_node_has_children(struct dom_ctx *ctx, + struct dom_node *node, bool *result) +{ + UNUSED(ctx); + + *result = node->first_child != NULL; + + return DOM_NO_ERR; +} + +/** + * Clone a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to clone + * \param deep True to deep-clone the node's sub-tree + * \param result Pointer to location to receive result + * \return DOM_NO_ERR on success, + * DOM_NO_MEMORY_ERR on memory exhaustion. + * + * The returned node will already be referenced. + * + * The duplicate node will have no parent and no user data. + * + * If ::node has registered user_data_handlers, then they will be called. + * + * Cloning an Element copies all attributes & their values (including those + * generated by the XML processor to represent defaulted attributes). It + * does not copy any child nodes unless it is a deep copy (this includes + * text contained within the Element, as the text is contained in a child + * Text node). + * + * Cloning an Attr directly, as opposed to cloning as part of an Element, + * returns a specified attribute. Cloning an Attr always clones its children, + * since they represent its value, no matter whether this is a deep clone or + * not. + * + * Cloning an EntityReference automatically constructs its subtree if a + * corresponding Entity is available, no matter whether this is a deep clone + * or not. + * + * Cloning any other type of node simply returns a copy. + * + * Note that cloning an immutable subtree results in a mutable copy, but + * the children of an EntityReference clone are readonly. In addition, clones + * of unspecified Attr nodes are specified. + * + * \todo work out what happens when cloning Document, DocumentType, Entity + * and Notation nodes. + */ +dom_exception dom_node_clone(struct dom_ctx *ctx, + struct dom_node *node, bool deep, + struct dom_node **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(deep); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Normalize a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to normalize + * \return DOM_NO_ERR. + * + * Puts all Text nodes in the full depth of the sub-tree beneath ::node, + * including Attr nodes into "normal" form, where only structure separates + * Text nodes. + */ +dom_exception dom_node_normalize(struct dom_ctx *ctx, + struct dom_node *node) +{ + UNUSED(ctx); + UNUSED(node); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Test whether the DOM implementation implements a specific feature and + * that feature is supported by the node. + * + * \param ctx The context in which the node resides + * \param node The node to test + * \param feature The name of the feature to test + * \param version The version number of the feature to test + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_node_is_supported(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *feature, + struct dom_node *version, bool *result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(feature); + UNUSED(version); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieve the namespace of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the namespace of + * \param result Pointer to location to receive node's namespace + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + */ +dom_exception dom_node_get_namespace(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string **result) +{ + /* If there is a namespace, increase its reference count */ + if (node->namespace != NULL) + dom_string_ref(ctx, node->namespace); + + *result = node->namespace; + + return DOM_NO_ERR; +} + +/** + * Retrieve the prefix of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the prefix of + * \param result Pointer to location to receive node's prefix + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + */ +dom_exception dom_node_get_prefix(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string **result) +{ + /* If there is a prefix, increase its reference count */ + if (node->prefix != NULL) + dom_string_ref(ctx, node->prefix); + + *result = node->prefix; + + return DOM_NO_ERR; +} + +/** + * Set the prefix of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to set the prefix of + * \param prefix Pointer to prefix string + * \return DOM_NO_ERR on success, + * DOM_INVALID_CHARACTER_ERR if the specified prefix contains + * an illegal character, + * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, + * DOM_NAMESPACE_ERR if the specified prefix is + * malformed, if the namespaceURI of + * ::node is null, if the specified + * prefix is "xml" and the + * namespaceURI is different from + * "http://www.w3.org/XML/1998/namespace", + * if ::node is an attribute and the + * specified prefix is "xmlns" and + * the namespaceURI is different from + * "http://www.w3.org/2000/xmlns", + * or if this node is an attribute + * and the qualifiedName of ::node + * is "xmlns". + */ +dom_exception dom_node_set_prefix(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *prefix) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(prefix); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieve the local part of a node's qualified name + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the local name of + * \param result Pointer to location to receive local name + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + */ +dom_exception dom_node_get_local_name(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string **result) +{ + /* If there is a local name, increase its reference count */ + if (node->localname != NULL) + dom_string_ref(ctx, node->localname); + + *result = node->localname; + + return DOM_NO_ERR; +} + +/** + * Determine if a node has any attributes + * + * \param ctx The context in which the node resides + * \param node Node to inspect + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_node_has_attributes(struct dom_ctx *ctx, + struct dom_node *node, bool *result) +{ + UNUSED(ctx); + + *result = node->attributes != NULL; + + return DOM_NO_ERR; +} + +/** + * Retrieve the base URI of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the base URI of + * \param result Pointer to location to receive base URI + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + */ +dom_exception dom_node_get_base(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Compare the positions of two nodes in a DOM tree + * + * \param ctx The context in which the nodes reside + * \param node The reference node + * \param other The node to compare + * \param result Pointer to location to receive result + * \return DOM_NO_ERR on success, + * DOM_NOT_SUPPORTED_ERR when the nodes are from different DOM + * implementations. + * + * The result is a bitfield of dom_document_position values. + */ +dom_exception dom_node_compare_document_position(struct dom_ctx *ctx, + struct dom_node *node, struct dom_node *other, + uint16_t *result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(other); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieve the text content of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve the text content of + * \param result Pointer to location to receive text content + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + * + * DOM3Core states that this can raise DOMSTRING_SIZE_ERR. It will not in + * this implementation; dom_strings are unbounded. + */ +dom_exception dom_node_get_text_content(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Set the text content of a DOM node + * + * \param ctx The context in which the node resides + * \param node The node to set the text content of + * \param content New text content for node + * \return DOM_NO_ERR on success, + * DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly. + * + * Any child nodes ::node may have are removed and replaced with a single + * Text node containing the new content. + */ +dom_exception dom_node_set_text_content(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *content) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(content); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Determine if two DOM nodes are the same + * + * \param ctx The context in which the nodes reside + * \param node The node to compare + * \param other The node to compare against + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + * + * This tests if the two nodes reference the same object. + */ +dom_exception dom_node_is_same(struct dom_ctx *ctx, + struct dom_node *node, struct dom_node *other, + bool *result) +{ + UNUSED(ctx); + + *result = (node == other); + + return DOM_NO_ERR; +} + +/** + * Lookup the prefix associated with the given namespace URI + * + * \param ctx The context in which the node resides + * \param node The node to start prefix search from + * \param namespace The namespace URI + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + */ +dom_exception dom_node_lookup_prefix(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *namespace, + struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(namespace); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Determine if the specified namespace is the default namespace + * + * \param ctx The context in which the node resides + * \param node The node to query + * \param namespace The namespace URI to test + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_node_is_default_namespace(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *namespace, + bool *result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(namespace); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Lookup the namespace URI associated with the given prefix + * + * \param ctx The context in which the node resides + * \param node The node to start namespace search from + * \param prefix The prefix to look for, or NULL to find default. + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + * + * The returned string will have its reference count increased. It is + * the responsibility of the caller to unref the string once it has + * finished with it. + */ +dom_exception dom_node_lookup_namespace(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *prefix, + struct dom_string **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(prefix); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Determine if two DOM nodes are equal + * + * \param ctx The context in which the nodes reside + * \param node The node to compare + * \param other The node to compare against + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + * + * Two nodes are equal iff: + * + They are of the same type + * + nodeName, localName, namespaceURI, prefix, nodeValue are equal + * + The node attributes are equal + * + The child nodes are equal + * + * Two DocumentType nodes are equal iff: + * + publicId, systemId, internalSubset are equal + * + The node entities are equal + * + The node notations are equal + */ +dom_exception dom_node_is_equal(struct dom_ctx *ctx, + struct dom_node *node, struct dom_node *other, + bool *result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(other); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieve an object which implements the specialized APIs of the specified + * feature and version. + * + * \param ctx The context in which the node resides + * \param node The node to query + * \param feature The requested feature + * \param version The version number of the feature + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_node_get_feature(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *feature, + struct dom_string *version, void **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(feature); + UNUSED(version); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Associate an object to a key on this node + * + * \param ctx The context in which the node resides + * \param node The node to insert object into + * \param key The key associated with the object + * \param data The object to associate with key, or NULL to remove + * \param handler User handler function, or NULL if none + * \param result Pointer to location to receive previously associated object + * \return DOM_NO_ERR. + */ +dom_exception dom_node_set_user_data(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *key, + void *data, dom_user_data_handler handler, + void **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(key); + UNUSED(data); + UNUSED(handler); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Retrieves the object associated to a key on this node + * + * \param ctx The context in which the node resides + * \param node The node to retrieve object from + * \param key The key to search for + * \param result Pointer to location to receive result + * \return DOM_NO_ERR. + */ +dom_exception dom_node_get_user_data(struct dom_ctx *ctx, + struct dom_node *node, struct dom_string *key, + void **result) +{ + UNUSED(ctx); + UNUSED(node); + UNUSED(key); + UNUSED(result); + + return DOM_NOT_SUPPORTED_ERR; +} diff --git a/src/core/node.h b/src/core/node.h new file mode 100644 index 0000000..b39ac40 --- /dev/null +++ b/src/core/node.h @@ -0,0 +1,60 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#ifndef dom_internal_core_node_h_ +#define dom_internal_core_node_h_ + +#include +#include + +struct dom_attr; + +/** + * User data context attached to a DOM node + */ +struct dom_user_data { + struct dom_string *key; /**< Key for data */ + void *data; /**< Client-specific data */ + dom_user_data_handler handler; /**< Callback function */ + + struct dom_user_data *next; /**< Next in list */ + struct dom_user_data *prev; /**< Previous in list */ +}; + +/** + * DOM node object + * + * DOM nodes are reference counted + */ +struct dom_node { + struct dom_string *name; /**< Node name */ + struct dom_string *value; /**< Node value */ + dom_node_type type; /**< Node type */ + struct dom_node *parent; /**< Parent node */ + struct dom_node *first_child; /**< First child node */ + struct dom_node *last_child; /**< Last child node */ + struct dom_node *previous; /**< Previous sibling */ + struct dom_node *next; /**< Next sibling */ + struct dom_attr *attributes; /**< Node attributes */ + + struct dom_document *owner; /**< Owning document */ + + struct dom_string *namespace; /**< Namespace URI */ + struct dom_string *prefix; /**< Namespace prefix */ + struct dom_string *localname; /**< Local part of qualified name */ + + struct dom_user_data *user_data; /**< User data list */ + + uint32_t refcnt; /**< Reference count */ +}; + +dom_exception dom_node_create(struct dom_ctx *ctx, + struct dom_document *doc, dom_node_type type, + struct dom_string *name, struct dom_string *value, + struct dom_node **node); + +#endif diff --git a/src/core/string.c b/src/core/string.c new file mode 100644 index 0000000..070af75 --- /dev/null +++ b/src/core/string.c @@ -0,0 +1,222 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#include +#include + +#include +#include + +#include "core/document.h" +#include "utils/utils.h" + +/** + * A DOM string + * + * DOM strings store either a pointer to allocated data, a pointer + * to constant data or an offset into a document buffer. + * + * They are reference counted so freeing is performed correctly. + */ +struct dom_string { + enum { DOM_STRING_PTR, + DOM_STRING_CONST_PTR, + DOM_STRING_OFFSET + } type; + union { + uint8_t *ptr; + const uint8_t *cptr; + struct { + struct dom_document *doc; + uint32_t off; + } offset; + } data; + + size_t len; + + uint32_t refcnt; +}; + +/** + * Claim a reference on a DOM string + * + * \param ctx The context in which the string resides + * \param str The string to claim a reference on + */ +void dom_string_ref(struct dom_ctx *ctx, struct dom_string *str) +{ + UNUSED(ctx); + + str->refcnt++; +} + +/** + * Release a reference on a DOM string + * + * \param ctx The context in which the string resides + * \param str The string to release the reference from + * + * If the reference count reaches zero, any memory claimed by the + * string will be released + */ +void dom_string_unref(struct dom_ctx *ctx, struct dom_string *str) +{ + if (--str->refcnt == 0) { + if (str->type == DOM_STRING_PTR) + ctx->alloc(str->data.ptr, 0, ctx->pw); + + ctx->alloc(str, 0, ctx->pw); + } +} + +/** + * Create a DOM string from an offset into the document buffer + * + * \param ctx The context in which the string resides + * \param doc The document in which the string resides + * \param off Offset from start of document buffer + * \param len Length, in bytes, of string + * \param str Pointer to location to receive pointer to new string + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * + * The returned string will already be referenced, so there is no need + * to explicitly reference it. + */ +dom_exception dom_string_create_from_off(struct dom_ctx *ctx, + struct dom_document *doc, uint32_t off, size_t len, + struct dom_string **str) +{ + struct dom_string *ret; + + ret = ctx->alloc(NULL, sizeof(struct dom_string), ctx->pw); + if (ret == NULL) + return DOM_NO_MEM_ERR; + + ret->type = DOM_STRING_OFFSET; + ret->data.offset.doc = doc; + ret->data.offset.off = off; + ret->len = len; + + ret->refcnt = 1; + + *str = ret; + + return DOM_NO_ERR; +} + +/** + * Create a DOM string from a string of characters + * + * \param ctx The context in which the string resides + * \param ptr Pointer to string of characters + * \param len Length, in bytes, of string of characters + * \param str Pointer to location to receive pointer to new string + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * + * The returned string will already be referenced, so there is no need + * to explicitly reference it. + * + * The string of characters passed in will be copied for use by the + * returned DOM string. + */ +dom_exception dom_string_create_from_ptr(struct dom_ctx *ctx, + const uint8_t *ptr, size_t len, struct dom_string **str) +{ + struct dom_string *ret; + + ret = ctx->alloc(NULL, sizeof(struct dom_string), ctx->pw); + if (ret == NULL) + return DOM_NO_MEM_ERR; + + ret->data.ptr = ctx->alloc(NULL, len, ctx->pw); + if (ret->data.ptr == NULL) { + ctx->alloc(ret, 0, ctx->pw); + return DOM_NO_MEM_ERR; + } + + ret->type = DOM_STRING_PTR; + + memcpy(ret->data.ptr, ptr, len); + + ret->len = len; + + ret->refcnt = 1; + + *str = ret; + + return DOM_NO_ERR; +} + +/** + * Create a DOM string from a constant string of characters + * + * \param ctx The context in which the string resides + * \param ptr Pointer to string of characters + * \param len Length, in bytes, of string of characters + * \param str Pointer to location to receive pointer to new string + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * + * The returned string will already be referenced, so there is no need + * to explicitly reference it. + * + * The string of characters passed in will _not_ be copied for use by the + * returned DOM string. + */ +dom_exception dom_string_create_from_const_ptr(struct dom_ctx *ctx, + const uint8_t *ptr, size_t len, struct dom_string **str) +{ + struct dom_string *ret; + + ret = ctx->alloc(NULL, sizeof(struct dom_string), ctx->pw); + if (ret == NULL) + return DOM_NO_MEM_ERR; + + ret->data.cptr = ptr; + + ret->type = DOM_STRING_CONST_PTR; + + ret->len = len; + + ret->refcnt = 1; + + *str = ret; + + return DOM_NO_ERR; +} + +/** + * Get a pointer to the string of characters within a DOM string + * + * \param ctx The context in which the string resides + * \param str Pointer to DOM string to retrieve pointer from + * \param data Pointer to location to receive data + * \param len Pointer to location to receive byte length of data + * \return DOM_NO_ERR on success + * + * The caller must have previously claimed a reference on the DOM string. + * The returned pointer must not be freed. + */ +dom_exception dom_string_get_data(struct dom_ctx *ctx, + struct dom_string *str, const uint8_t **data, size_t *len) +{ + switch (str->type) { + case DOM_STRING_PTR: + *data = str->data.ptr; + break; + case DOM_STRING_CONST_PTR: + *data = str->data.cptr; + break; + case DOM_STRING_OFFSET: + *data = dom_document_get_base(ctx, str->data.offset.doc) + + str->data.offset.off; + break; + } + + *len = str->len; + + return DOM_NO_ERR; +} -- cgit v1.2.3