From 9fc8444f2c4aca8a551f1300d734742b7d99be00 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 18 Apr 2013 22:11:33 +0200 Subject: Make build work without libmba and domc --- src/Makefile.am | 13 +- src/dom.c | 3145 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dom.h | 526 +++++++++ src/domcxx.h | 1 - src/domhelpers.h | 2 +- src/usuals.h | 1 + src/xmlfixups.cpp | 2 +- 7 files changed, 3675 insertions(+), 15 deletions(-) create mode 100644 src/dom.c create mode 100644 src/dom.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index e729fb7..98542a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,21 +1,10 @@ -INCLUDES = \ - -I$(srcdir)/../libs/domc/src/ \ - -I$(srcdir)/../libs/libmba/src/ - bin_PROGRAMS = rtfx rtfx_SOURCES = rtfx.cpp levelhandler.cpp levelhandler.h \ reference.h xmlcomposer.cpp xmlcomposer.h xmlcomposehelpers.cpp rtfformatting.h \ xmlcomposehelpers.h rtfparser.cpp rtfparser.h domcxx.h usuals.h utf8.cpp internal.h \ - xmlfixups.h xmlfixups.cpp domhelpers.h domhelpers.cpp tags.h - -rtfx_LDADD = -ldomc -lmba - -rtfx_LDFLAGS = \ - -L/usr/local/lib \ - -L$(srcdir)/../libs/libmba/ \ - -L$(srcdir)/../libs/domc/ + xmlfixups.h xmlfixups.cpp domhelpers.h domhelpers.cpp tags.h dom.c domc.h dom.h man_MANS = rtfx.1 diff --git a/src/dom.c b/src/dom.c new file mode 100644 index 0000000..714d305 --- /dev/null +++ b/src/dom.c @@ -0,0 +1,3145 @@ +/* domc document object model library in c + * Copyright (c) 2001 Michael B. Allen + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* dom.c - document object model interface + */ + +#include +#include +#include +#include + +#include "dom.h" + +#if defined(__sparc__) + +#define NL "\n" +#define HAVE_ENCDEC 0 +#define HAVE_STRDUP 1 +#define HAVE_STRNLEN 0 +#define HAVE_EXPAT 195 +#define HAVE_MBSTATE 0 +#define HAVE_WCWIDTH 1 +#define HAVE_SNPRINTF 1 +#define HAVE_VARMACRO 1 +#define HAVE_LANGINFO 1 +#define HAVE_X11_KEYSYMS 0 + +#elif defined(_WIN32) + +#define NL "\r\n" +#define HAVE_ENCDEC 0 +#define HAVE_STRDUP 1 +#define HAVE_STRNLEN 0 +#define HAVE_EXPAT 195 +#define HAVE_MBSTATE 0 +#define HAVE_WCWIDTH 0 +#define HAVE_SNPRINTF 0 +#define HAVE_VARMACRO 0 +#define HAVE_LANGINFO 0 +#define HAVE_X11_KEYSYMS 0 + +#else + +#define NL "\n" +#define HAVE_ENCDEC 0 +#define HAVE_STRDUP 1 +#define HAVE_STRNLEN 1 +#define HAVE_EXPAT 195 +#define HAVE_MBSTATE 1 +#define HAVE_WCWIDTH 1 +#define HAVE_SNPRINTF 1 +#define HAVE_VARMACRO 1 +#define HAVE_LANGINFO 1 +#define HAVE_X11_KEYSYMS 0 + +#endif + +#if defined(__GNUC__) +#if defined(MSGNO) + +#if defined(__GNUC__) && (__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 95)) + +#define MSG(fmt, args...) _msgno_printf("%s:%u:%s: " fmt, \ + __FILE__, __LINE__, __FUNCTION__, ## args) +#define MNO(msgno) _msgno_printf("%s:%u:%s: %s", \ + __FILE__, __LINE__, __FUNCTION__, msgno_msg(msgno)) +#define MNF(msgno, fmt, args...) _msgno_printf("%s:%u:%s: %s" fmt, \ + __FILE__, __LINE__, __FUNCTION__, msgno_msg(msgno), ## args) + +#define PMSG(fmt, args...) (_msgno_buf_idx = sprintf(_msgno_buf, \ + "%s:%u:%s: " fmt "\n", \ + __FILE__, __LINE__, __FUNCTION__, ## args)) +#define PMNO(msgno) (_msgno_buf_idx = sprintf(_msgno_buf, \ + "%s:%u:%s: %s\n", \ + __FILE__, __LINE__, __FUNCTION__, msgno_msg(msgno))) +#define PMNF(msgno, fmt, args...) (_msgno_buf_idx = sprintf(_msgno_buf, \ + "%s:%u:%s: %s" fmt "\n", \ + __FILE__, __LINE__, __FUNCTION__, msgno_msg(msgno), ## args)) + +#define AMSG(fmt, args...) (_msgno_buf_idx += sprintf(_msgno_buf + _msgno_buf_idx, \ + " %s:%u:%s: " fmt "\n", \ + __FILE__, __LINE__, __FUNCTION__, ## args)) +#define AMNO(msgno) (_msgno_buf_idx += sprintf(_msgno_buf + _msgno_buf_idx, \ + " %s:%u:%s: %s\n", \ + __FILE__, __LINE__, __FUNCTION__, msgno_msg(msgno))) +#define AMNF(msgno, fmt, args...) (_msgno_buf_idx += sprintf(_msgno_buf + _msgno_buf_idx, \ + " %s:%u:%s: %s" fmt "\n", \ + __FILE__, __LINE__, __FUNCTION__, msgno_msg(msgno), ## args)) + +#else + +#define MSG(fmt, args...) _msgno_printf("%s:%u: " fmt "\n", \ + __FILE__, __LINE__ , ## args) +#define MNO(msgno) _msgno_printf("%s:%u: %s\n", \ + __FILE__, __LINE__, msgno_msg(msgno)) +#define MNF(msgno, fmt, args...) _msgno_printf("%s:%u: %s" fmt "\n", \ + __FILE__, __LINE__, msgno_msg(msgno) , ## args) + +#define PMSG(fmt, args...) (_msgno_buf_idx = sprintf(_msgno_buf, \ + "%s:%u: " fmt "\n", __FILE__, __LINE__ , ## args)) +#define PMNO(msgno) (_msgno_buf_idx = sprintf(_msgno_buf, \ + "%s:%u: %s\n", __FILE__, __LINE__, msgno_msg(msgno))) +#define PMNF(msgno, fmt, args...) (_msgno_buf_idx = sprintf(_msgno_buf, \ + "%s:%u: %s" fmt "\n", __FILE__, __LINE__, msgno_msg(msgno) , ## args)) + +#define AMSG(fmt, args...) (_msgno_buf_idx += sprintf(_msgno_buf + _msgno_buf_idx, \ + " %s:%u: "fmt"\n", __FILE__, __LINE__ , ## args)) +#define AMNO(msgno) (_msgno_buf_idx += sprintf(_msgno_buf + _msgno_buf_idx, \ + " %s:%u: %s\n", __FILE__, __LINE__, msgno_msg(msgno))) +#define AMNF(msgno, fmt, args...) (_msgno_buf_idx += sprintf(_msgno_buf + _msgno_buf_idx, \ + " %s:%u: %s" fmt "\n", __FILE__, __LINE__, msgno_msg(msgno) , ## args)) + +#endif +#else + +#define MSG(fmt, args...) +#define MNO(msgno) +#define MNF(msgno, fmt, args...) +#define PMSG(fmt, args...) +#define PMNO(msgno) +#define PMNF(msgno, fmt, args...) +#define AMSG(fmt, args...) +#define AMNO(msgno) +#define AMNF(msgno, fmt, args...) + +#endif +#else +#undef MSG +#if defined(MSGNO) + +#define MSG msgno_hdlr +#define MNO msgno_hdlr_mno +#define MNF msgno_hdlr_mnf +#define PMSG msgno_hdlr +#define PMNO msgno_hdlr_mno +#define PMNF msgno_hdlr_mnf +#define AMSG msgno_hdlr +#define AMNO msgno_hdlr_mno +#define AMNF msgno_hdlr_mnf + +#else + +#define MSG msgno_noop_msg +#define MNO msgno_noop_mno +#define MNF msgno_noop_mnf +#define PMSG msgno_noop_msg +#define PMNO msgno_noop_mno +#define PMNF msgno_noop_mnf +#define AMSG msgno_noop_msg +#define AMNO msgno_noop_mno +#define AMNF msgno_noop_mnf + +#endif +#endif + +#ifndef MSGNO_NUM_LISTS +#define MSGNO_NUM_LISTS 16 +#endif +#ifndef MSGNO_BUFSIZ +#define MSGNO_BUFSIZ 1024 +#endif + +#define NULL_POINTER_ERR _builtin_codes[0].msgno + +struct msgno_entry _builtin_codes[2] = { + { (1 << 16), "A parameter was NULL" }, + { 0, NULL } +}; + +static struct tbl_entry { + struct msgno_entry *list; + unsigned int num_msgs; +} list_tbl[MSGNO_NUM_LISTS] = { + { _builtin_codes, 1 } +}; + +static unsigned int next_tbl_idx = 1; + +const char * +msgno_msg(int msgno) +{ + struct tbl_entry *te; + unsigned int i; + + i = msgno >> 16; + if (i == 0) { + return strerror(msgno); + } else if (i >= MSGNO_NUM_LISTS || + (te = list_tbl + (i - 1)) == NULL) { + return "No such msgno list"; + } + + for (i = 0; i < te->num_msgs; i++) { + if (te->list[i].msgno == msgno) { + return te->list[i].msg; + } + } + + return "No such message in msgno list"; +} + +int +msgno_add_codes(struct msgno_entry *list) +{ + struct tbl_entry *te; + int next_msgno = 0, hi_bits; + + if (list == NULL || list->msg == NULL) { + errno = EINVAL; + return -1; + } + if (next_tbl_idx == MSGNO_NUM_LISTS) { + errno = ERANGE; + return -1; + } + + for (te = list_tbl + 1; te->list; te++) { + if (te->list == list) { + return 0; /* already in list_tbl */ + } + } + + hi_bits = (next_tbl_idx + 1) << 16; + te->list = list; + while (list->msg) { + if ((list->msgno & 0xFFFF0000)) { + te->list = NULL; + errno = ERANGE; + return -1; + } + if (list->msgno == 0) { + list->msgno = hi_bits | next_msgno++; + } else if (list->msgno >= next_msgno) { + next_msgno = list->msgno + 1; + list->msgno = hi_bits | list->msgno; + } else { + te->list = NULL; + errno = ERANGE; + return -1; + } + te->num_msgs++; + list++; + } + next_tbl_idx++; + + return 0; +} + + +int +mbslen(const char *src) +{ + return mbsnlen(src, -1, -1); +} +int +mbsnlen(const char *src, size_t sn, int cn) +{ + wchar_t ucs; + int count, w; + size_t n; +#if HAVE_MBSTATE > 0 + mbstate_t ps; +#endif + + ucs = 1; + count = 0; + + if (sn > INT_MAX) { + sn = INT_MAX; + } + if (cn < 0) { + cn = INT_MAX; + } + +#if HAVE_MBSTATE + memset(&ps, 0, sizeof(ps)); + while (ucs && (n = mbrtowc(&ucs, src, sn, &ps)) != (size_t)-2) { +#else + while (ucs && sn > 0) { + n = mbtowc(&ucs, src, sn); +#endif + if (n == (size_t)-1) { + PMNO(errno); + return -1; + } + if ((w = wcwidth(ucs)) == -1) { + w = 1; + } + if (w > cn) { + break; + } + cn -= w; + sn -= n; + src += n; + count += w; + } + + return count; +} + +size_t +mbsnsize(const char *src, size_t sn, int cn) +{ + wchar_t ucs; + int w; + size_t tot, n; +#if HAVE_MBSTATE > 0 + mbstate_t ps; +#endif + + tot = n = 0; + ucs = 1; + + if (sn > INT_MAX) { + sn = INT_MAX; + } + if (cn < 0) { + cn = INT_MAX; + } + +#if HAVE_MBSTATE + memset(&ps, 0, sizeof(ps)); + while (ucs && sn > 0 && (n = mbrtowc(&ucs, src, sn, &ps)) != (size_t)-2 && n) { +#else + while (ucs && sn > 0 && (n = mbtowc(&ucs, src, sn))) { +#endif + if (n == (size_t)-1) { + PMNO(errno); + return -1; + } + if ((w = wcwidth(ucs)) == -1) { + w = 1; + } + if (w > cn) { + break; + } + cn -= w; + sn -= n; + src += n; + tot += n; + } + + return tot; +} + +size_t +mbssize(const char *src) +{ + return mbsnsize(src, -1, -1); +} + +static char * +mbsnoff(char *src, int off, size_t sn) +{ + wchar_t ucs; + size_t n; + int w; +#if HAVE_MBSTATE > 0 + mbstate_t ps; +#endif + + if (off == 0) { + return src; + } + + if (sn > INT_MAX) { + sn = 0xFFFF; + } + if (off < 0) { + off = 0xFFFF; + } + +#if HAVE_MBSTATE > 0 + memset(&ps, 0, sizeof(ps)); + while (sn > 0 && (n = mbrtowc(&ucs, src, sn, &ps)) != (size_t)-2) { +#else + while (sn > 0) { + n = mbtowc(&ucs, src, sn); +#endif + if (n == (size_t)-1) { + PMNF(errno, "src=[%s]", mbstoax(src, sn, 1)); + return NULL; + } + if (n == 0 || (w = wcwidth(ucs)) != 0) { + w = 1; + } + if (w > off) { + break; + } + if (w) off--; + sn -= n; + src += n ? n : 1; + } + + return src; +} + + +static char * +mbsoff(char *src, int off) +{ + return mbsnoff(src, off, -1); +} + +static char * +mbsndup(const char *src, size_t sn, int cn) +{ + size_t n; + char *dst; + + if (src == NULL) { + errno = EINVAL; + PMNO(errno); + return NULL; + } + if ((n = mbsnsize(src, sn, cn)) == (size_t)-1) { + AMSG(""); + return NULL; + } + if ((dst = malloc(n + 1)) == NULL) { + PMNO(errno); + return NULL; + } + memcpy(dst, src, n); + dst[n] = '\0'; + + return dst; +} + +static char * +mbsdup(const char *src) +{ + return mbsndup(src, -1, -1); +} + +#if defined(_WIN32) +#include + +typedef unsigned __int64 uint64_t; + +uint64_t +timestamp(void) +{ + FILETIME ftime; + uint64_t ret; + + GetSystemTimeAsFileTime(&ftime); + + ret = ftime.dwHighDateTime; + ret <<= 32Ui64; + ret |= ftime.dwLowDateTime; + + return ret; +} + +#else +#include + +uint64_t +timestamp(void) +{ + struct timeval tval; + + if (gettimeofday(&tval, NULL) < 0) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return 1; + } + return tval.tv_sec * 1000LL + tval.tv_usec / 1000; +} + +#endif + +/* Forward references for node.c + */ + +DOM_Node *Document_createNode(DOM_Document *doc, unsigned short nodeType); +NodeEntry *NodeList_remove(DOM_NodeList *nl, DOM_Node *oldChild); +NodeEntry *NodeList_append(DOM_NodeList *nl, DOM_Node *newChild); +DOM_NodeList *Document_createNodeList(DOM_Document *doc); +DOM_NamedNodeMap *Document_createNamedNodeMap(DOM_Document *doc); + +/* Forward references for events.c + */ + +void updateCommonParent(DOM_Node *node); + +/* DOM_Exception + */ + +struct msgno_entry dom_codes[] = { + { 1, "The index specified was out of range" }, + { 0, "The text size is out of range" }, + { 0, "The request violated tree hierarchy constraints" }, + { 0, "The document context is invalid" }, + { 0, "An inappropriate character was encountered" }, + { 0, "The node does not support the addition of data" }, + { 0, "No modification allowed" }, + { 0, "The specified node was not found" }, + { 0, "The requested operation is not supported" }, + { 0, "The attribute is being used elsewhere" }, + { 0, "An XML parser error occured" }, + { 0, "Failed to create DOM object" }, + { 0, "Character encoding error" }, + { 0, "The event type was not specified by initialization" }, + { 0, "A filtered list cannot be modified" }, + { 0, NULL } +}; + +int _exception = 0; + +int * +_DOM_Exception(void) +{ + return &_exception; +} + +unsigned short child_matrix[] = { + 0x00dd, /* DOM_ELEMENT_NODE 1 */ + 0x0014, /* DOM_ATTRIBUTE_NODE 2 */ + 0x0000, /* DOM_TEXT_NODE 3 */ + 0x0000, /* DOM_CDATA_SECTION_NODE 4 */ + 0x00dd, /* DOM_ENTITY_REFERENCE_NODE 5 */ + 0x00dd, /* DOM_ENTITY_NODE 6 */ + 0x0000, /* DOM_PROCESSING_INSTRUCTION_NODE 7 */ + 0x0000, /* DOM_COMMENT_NODE 8 */ + 0x02c1, /* DOM_DOCUMENT_NODE 9 */ + 0x0820, /* DOM_DOCUMENT_TYPE_NODE 10 */ + 0x00dd, /* DOM_DOCUMENT_FRAGMENT_NODE 11 */ + 0x0000 /* DOM_NOTATION_NODE 12 */ +}; + +const char *node_names[] = { + "No such node type", + "DOM_ELEMENT_NODE", + "DOM_ATTRIBUTE_NODE", + "DOM_TEXT_NODE", + "DOM_CDATA_SECTION_NODE", + "DOM_ENTITY_REFERENCE_NODE", + "DOM_ENTITY_NODE", + "DOM_PROCESSING_INSTRUCTION_NODE", + "DOM_COMMENT_NODE", + "DOM_DOCUMENT_NODE", + "DOM_DOCUMENT_TYPE_NODE", + "DOM_DOCUMENT_FRAGMENT_NODE", + "DOM_NOTATION_NODE" +}; + +/* DOM_Implementation and DOM_ImplementationLS + */ + +int +DOM_Implementation_hasFeature(DOM_String *feature, DOM_String *version) +{ + feature = NULL; version = NULL; + return 0; +} +DOM_DocumentType * +DOM_Implementation_createDocumentType(DOM_String *qualifiedName, + DOM_String *publicId, DOM_String *systemId) +{ + DOM_DocumentType *doctype; + DOM_NamedNodeMap *entities; + DOM_NamedNodeMap *notations; + + if ((doctype = Document_createNode(NULL, DOM_DOCUMENT_TYPE_NODE)) == NULL) { + AMSG(""); + return NULL; + } + if ((doctype->nodeName = doctype->u.DocumentType.name = strdup(qualifiedName)) == NULL || + (publicId && ((doctype->u.DocumentType.publicId = strdup(publicId))) == NULL) || + (systemId && ((doctype->u.DocumentType.systemId = strdup(systemId))) == NULL)) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(NULL, doctype); + return NULL; + } + if ((entities = Document_createNamedNodeMap(NULL)) == NULL || + (notations = Document_createNamedNodeMap(NULL)) == NULL) { + AMNO(DOM_CREATE_FAILED); + DOM_Document_destroyNode(NULL, doctype); + return NULL; + } + entities->filter = DOM_ENTITY_NODE; + notations->filter = DOM_NOTATION_NODE; + entities->list = notations->list = doctype->childNodes; + doctype->u.DocumentType.entities = entities; + doctype->u.DocumentType.notations = notations; + + return doctype; +} +DOM_Document * +DOM_Implementation_createDocument(DOM_String *namespaceURI, + DOM_String *qualifiedName, DOM_DocumentType *doctype) +{ + DOM_Document *doc; + DOM_Element *el; + + namespaceURI = NULL; + + msgno_add_codes(dom_codes); + + if ((doc = Document_createNode(NULL, DOM_DOCUMENT_NODE)) == NULL) { + AMSG(""); + return NULL; + } + doc->nodeName = "#document"; + if (doctype) { + DOM_Node_appendChild(doc, doctype); + } + + if (qualifiedName && *qualifiedName) { + if ((el = DOM_Document_createElement(doc, qualifiedName)) == NULL) { + AMSG(""); + DOM_Document_destroyNode(doc, doc); + return NULL; + } + DOM_Node_appendChild(doc, el); + } + + return doc; +} + +DOM_String * +DOM_Element_getAttribute(const DOM_Element *element, const DOM_String *name) +{ + DOM_Node *node; + DOM_String *r = NULL; + + if (element && name && element->attributes) { + if ((node = DOM_NamedNodeMap_getNamedItem(element->attributes, name))) { + if ((r = strdup(node->nodeValue)) == NULL) { + AMSG(""); + return NULL; + } + } else if ((r = strdup("")) == NULL) { + PMNO(errno); + return NULL; + } + } + + return r; +} +void +DOM_Element_setAttribute(DOM_Element *element, + const DOM_String *name, const DOM_String *value) +{ + DOM_Attr *attr; + DOM_String *prevValue; + unsigned short attrChange; + DOM_MutationEvent evt; + + if (element == NULL || name == NULL || + value == NULL || element->attributes == NULL) { + return; + } + + attr = DOM_NamedNodeMap_getNamedItem(element->attributes, name); + if (attr) { + prevValue = attr->nodeValue; + attrChange = DOM_MUTATION_EVENT_MODIFICATION; + if ((attr->nodeValue = attr->u.Attr.value = strdup(value)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(attr->ownerDocument, attr); + return; + } + } else { + prevValue = NULL; + attrChange = DOM_MUTATION_EVENT_ADDITION; + if ((attr = DOM_Document_createAttribute(element->ownerDocument, name)) == NULL) { + AMNO(DOM_CREATE_FAILED); + return; + } + free(attr->nodeValue); + if ((attr->nodeValue = attr->u.Attr.value = strdup(value)) == NULL) { + DOM_Exception = errno; + DOM_Document_destroyNode(attr->ownerDocument, attr); + return; + } + DOM_NamedNodeMap_setNamedItem(element->attributes, attr); + } + + DOM_MutationEvent_initMutationEvent(&evt, "DOMAttrModified", 1, 0, + attr, prevValue, attr->nodeValue, attr->nodeName, attrChange); +/*MSG("attr=%p,prevValue=[%s],newValue=[%s],attrName=%s", attr, prevValue, attr->nodeValue, attr->nodeName); + */ + DOM_EventTarget_dispatchEvent(element, &evt); + + updateCommonParent(element->parentNode); + + free(prevValue); +} +void +DOM_Element_removeAttribute(DOM_Element *element, const DOM_String *name) +{ + DOM_Attr *attr; + DOM_MutationEvent evt; + + if (element == NULL || name == NULL) { + return; + } + + attr = DOM_NamedNodeMap_removeNamedItem(element->attributes, name); + + /* removeAttribute doesn't throw exceptions on NOT_FOUND_ERR */ + if (DOM_Exception == DOM_NOT_FOUND_ERR) + DOM_Exception = 0; + + if (attr) { + DOM_MutationEvent_initMutationEvent(&evt, "DOMAttrModified", 1, 0, + attr, attr->nodeValue, NULL, attr->nodeName, DOM_MUTATION_EVENT_REMOVAL); + DOM_EventTarget_dispatchEvent(element, &evt); + + updateCommonParent(element->parentNode); + + DOM_Document_destroyNode(attr->ownerDocument, attr); + } +} +DOM_Attr * +DOM_Element_getAttributeNode(const DOM_Element *element, const DOM_String *name) +{ + if (element && name) { + return DOM_NamedNodeMap_getNamedItem(element->attributes, name); + } + return NULL; +} +DOM_Attr * +DOM_Element_setAttributeNode(DOM_Element *element, DOM_Attr *newAttr) +{ + DOM_Node *attr; + DOM_MutationEvent evt; + + if (element == NULL || newAttr == NULL) { + return NULL; + } + if (element->ownerDocument != newAttr->ownerDocument) { + DOM_Exception = DOM_WRONG_DOCUMENT_ERR; + PMNO(DOM_Exception); + return NULL; + } + + attr = DOM_NamedNodeMap_setNamedItem(element->attributes, newAttr); + + if (attr) { + DOM_MutationEvent_initMutationEvent(&evt, "DOMAttrModified", 1, 0, + attr, attr->nodeValue, NULL, attr->nodeName, DOM_MUTATION_EVENT_REMOVAL); + DOM_EventTarget_dispatchEvent(element, &evt); + } + + DOM_MutationEvent_initMutationEvent(&evt, "DOMAttrModified", 1, 0, + newAttr, NULL, newAttr->nodeValue, newAttr->nodeName, DOM_MUTATION_EVENT_ADDITION); + DOM_EventTarget_dispatchEvent(element, &evt); + + updateCommonParent(element->parentNode); + + return attr; +} +DOM_Attr * +DOM_Element_removeAttributeNode(DOM_Element *element, DOM_Attr *oldAttr) +{ + DOM_MutationEvent evt; + + if (element == NULL || oldAttr == NULL || + NodeList_remove(element->attributes, oldAttr) == NULL) { + DOM_Exception = DOM_NOT_FOUND_ERR; + PMNO(DOM_Exception); + return NULL; + } + DOM_MutationEvent_initMutationEvent(&evt, "DOMAttrModified", 1, 0, + oldAttr, oldAttr->nodeValue, NULL, oldAttr->nodeName, DOM_MUTATION_EVENT_REMOVAL); + DOM_EventTarget_dispatchEvent(element, &evt); + + updateCommonParent(element->parentNode); + + return oldAttr; +} + +static void +getElementsPreorder(DOM_NodeList *list, DOM_Node *node, const DOM_String *tagname) +{ + DOM_Node *n; + + if (list && node && node->nodeType == DOM_ELEMENT_NODE && tagname) { + if ((tagname[0] == '*' && tagname[1] == '\0') || + strcoll(tagname, node->nodeName) == 0) { + NodeList_append(list, node); + } + for (n = node->firstChild; n != NULL; n = n->nextSibling) { + getElementsPreorder(list, n, tagname); + } + } +} + +DOM_NodeList * +DOM_Element_getElementsByTagName(DOM_Element *element, const DOM_String *name) +{ + DOM_NodeList *list; + DOM_Node *n; + + if (element && element->nodeType == DOM_ELEMENT_NODE && name && + (list = Document_createNodeList(element->ownerDocument))) { + for (n = element->firstChild; n != NULL; n = n->nextSibling) { + getElementsPreorder(list, n, name); + } + return list; + } + + return NULL; +} +void +DOM_Element_normalize(DOM_Element *element) +{ + DOM_Node *node; + DOM_Text *last = NULL; + + if (element) { + for (node = element->firstChild; node != NULL; node = node->nextSibling) { + if (node->nodeType == DOM_TEXT_NODE) { + if (last) { + DOM_CharacterData_insertData(node, 0, last->nodeValue); + DOM_Node_removeChild(element, last); + DOM_Document_destroyNode(last->ownerDocument, last); + } + last = node; + } else { + last = NULL; + DOM_Element_normalize(node); + } + if (DOM_Exception) { + AMSG(""); + return; + } + } + } +} + +DOM_String * +DOM_CharacterData_substringData(DOM_CharacterData *data, + int offset, int count) +{ + DOM_String *sub; + int dlen; + + if (data == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (offset < 0 || offset > (dlen = data->u.CharacterData.length) || count < 0) { + DOM_Exception = DOM_INDEX_SIZE_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (count > (dlen - offset)) { + count = dlen - offset; + } + if ((sub = mbsoff(data->nodeValue, offset)) == NULL || + (sub = mbsndup(sub, -1, count)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return NULL; + } + return sub; +} +void +DOM_CharacterData_appendData(DOM_CharacterData *data, const DOM_String *arg) +{ + DOM_String *str, *prevValue; + size_t dsize, asize; + DOM_MutationEvent evt; + + if (data == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return; + } + if (arg) { + dsize = mbssize(data->nodeValue); + asize = mbssize(arg); + if ((str = malloc(dsize + asize + 1)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return; + } + + memcpy(str, data->nodeValue, dsize); + memcpy(str + dsize, arg, asize); + str[dsize + asize] = '\0'; + + prevValue = data->nodeValue; + data->nodeValue = data->u.CharacterData.data = str; + data->u.CharacterData.length += mbslen(arg); + + DOM_MutationEvent_initMutationEvent(&evt, "DOMCharacterDataModified", 1, 0, + NULL, prevValue, data->nodeValue, NULL, 0); + DOM_EventTarget_dispatchEvent(data, &evt); + + updateCommonParent(data->parentNode); + + free(prevValue); + } +} +void +DOM_CharacterData_insertData(DOM_CharacterData *data, + int offset, const DOM_String *arg) +{ + DOM_String *str, *prevValue; + size_t dsize, asize, o; + DOM_MutationEvent evt; + + if (data == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return; + } + if (offset < 0 || offset > data->u.CharacterData.length) { + DOM_Exception = DOM_INDEX_SIZE_ERR; + PMNO(DOM_Exception); + return; + } + if (arg) { + dsize = mbssize(data->nodeValue); + asize = mbssize(arg); + if ((str = malloc(dsize + asize + 1)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return; + } + + o = mbsoff(data->nodeValue, offset) - data->nodeValue; + memcpy(str, data->nodeValue, o); + memcpy(str + o, arg, asize); + memcpy(str + o + asize, data->nodeValue + o, dsize - o); + str[dsize + asize] = '\0'; + + prevValue = data->nodeValue; + data->nodeValue = data->u.CharacterData.data = str; + data->u.CharacterData.length += mbslen(arg); + + DOM_MutationEvent_initMutationEvent(&evt, "DOMCharacterDataModified", 1, 0, + NULL, prevValue, data->nodeValue, NULL, 0); + DOM_EventTarget_dispatchEvent(data, &evt); + + updateCommonParent(data->parentNode); + + free(prevValue); + } +} +void +DOM_CharacterData_deleteData(DOM_CharacterData *data, + int offset, int count) +{ + DOM_String *p1, *p2, *str, *prevValue; + int p1size, p2size, dlen; + DOM_MutationEvent evt; + + if (data == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return; + } + if (offset < 0 || offset > (dlen = data->u.CharacterData.length)) { + DOM_Exception = DOM_INDEX_SIZE_ERR; + PMNO(DOM_Exception); + return; + } + if (count < 0 || (offset + count) > dlen) { + count = dlen - offset; + } + + p1 = mbsoff(data->nodeValue, offset); + p1size = p1 - data->nodeValue; + p2 = mbsoff(p1, count); + p2size = strlen(p2); + + if ((str = malloc(p1size + p2size + 1)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return; + } + memcpy(str, data->nodeValue, p1size); + memcpy(str + p1size, p2, p2size); + str[p1size + p2size] = '\0'; + + prevValue = data->nodeValue; + data->nodeValue = data->u.CharacterData.data = str; + data->u.CharacterData.length = dlen - count; + + DOM_MutationEvent_initMutationEvent(&evt, "DOMCharacterDataModified", 1, 0, + NULL, prevValue, data->nodeValue, NULL, 0); + DOM_EventTarget_dispatchEvent(data, &evt); + + updateCommonParent(data->parentNode); + + free(prevValue); +} +void +DOM_CharacterData_replaceData(DOM_CharacterData *data, int offset, int count, + const DOM_String *arg) +{ + DOM_CharacterData_deleteData(data, offset, count); + DOM_CharacterData_insertData(data, offset, arg); +} +int +DOM_CharacterData_getLength(DOM_CharacterData *data) +{ + return data ? data->u.CharacterData.length : 0; +} + +DOM_Text * +DOM_Text_splitText(DOM_Text *text, int offset) +{ + DOM_Text *node; + + if (text == NULL || text->parentNode == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + + if (offset < 0 || offset > text->u.CharacterData.length) { + DOM_Exception = DOM_INDEX_SIZE_ERR; + PMNO(DOM_Exception); + return NULL; + } + node = DOM_Document_createTextNode(text->ownerDocument, + mbsoff(text->nodeValue, offset)); + if (node == NULL) { + AMNO(DOM_CREATE_FAILED); + return NULL; + } + DOM_CharacterData_deleteData(text, offset, -1); + DOM_Node_insertBefore(text->parentNode, node, text->nextSibling); + + return node; +} + + +DOM_Element * +DOM_Document_createElement(DOM_Document *doc, const DOM_String *tagName) +{ + DOM_Element *element; + + element = Document_createNode(doc, DOM_ELEMENT_NODE); + if (element) { + if ((element->nodeName = element->u.Element.tagName = strdup(tagName)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(doc, element); + return NULL; + } + if ((element->attributes = Document_createNamedNodeMap(doc)) == NULL) { + AMNO(DOM_CREATE_FAILED); + DOM_Document_destroyNode(doc, element); + return NULL; + } + element->attributes->_ownerElement = element; /* for Attr.ownerElement */ + } + + return element; +} +DOM_DocumentFragment * +DOM_Document_createDocumentFragment(DOM_Document *doc) +{ + DOM_DocumentFragment *frag; + + frag = Document_createNode(doc, DOM_DOCUMENT_FRAGMENT_NODE); + if (frag) { + frag->nodeName = "#document-fragment"; + } + + return frag; +} +DOM_Text * +DOM_Document_createTextNode(DOM_Document *doc, const DOM_String *data) +{ + DOM_Text *text; + + text = Document_createNode(doc, DOM_TEXT_NODE); + if (text) { + text->nodeName = "#text"; + text->nodeValue = text->u.CharacterData.data = strdup(data); + if (text->nodeValue == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(doc, text); + return NULL; + } + text->u.CharacterData.length = mbslen(data); + } + + return text; +} +DOM_Comment * +DOM_Document_createComment(DOM_Document *doc, const DOM_String *data) +{ + DOM_Comment *comment; + + comment = Document_createNode(doc, DOM_COMMENT_NODE); + if (comment) { + comment->nodeName = "#comment"; + comment->nodeValue = comment->u.CharacterData.data = strdup(data); + if (comment->nodeValue == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(doc, comment); + return NULL; + } + comment->u.CharacterData.length = mbslen(data); + } + + return comment; +} +DOM_CDATASection * +DOM_Document_createCDATASection(DOM_Document *doc, const DOM_String *data) +{ + DOM_CDATASection *cdata; + + cdata = Document_createNode(doc, DOM_CDATA_SECTION_NODE); + if (cdata) { + cdata->nodeName = "#cdata-section"; + cdata->nodeValue = cdata->u.CharacterData.data = strdup(data); + if (cdata->u.CharacterData.data == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(doc, cdata); + return NULL; + } + cdata->u.CharacterData.length = mbslen(data); + } + + return cdata; +} +DOM_ProcessingInstruction * +DOM_Document_createProcessingInstruction(DOM_Document *doc, + const DOM_String *target, const DOM_String *data) +{ + DOM_ProcessingInstruction *pi; + + pi = Document_createNode(doc, DOM_PROCESSING_INSTRUCTION_NODE); + if (pi) { + pi->nodeName = pi->u.ProcessingInstruction.target = strdup(target); + pi->nodeValue = pi->u.ProcessingInstruction.data = strdup(data); + if (pi->nodeName == NULL || pi->nodeValue == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(doc, pi); + return NULL; + } + } + + return pi; +} +DOM_Attr * +DOM_Document_createAttribute(DOM_Document *doc, const DOM_String *name) +{ + DOM_Attr *attr; + + attr = Document_createNode(doc, DOM_ATTRIBUTE_NODE); + if (attr) { + attr->nodeName = attr->u.Attr.name = strdup(name); + attr->nodeValue = attr->u.Attr.value = strdup(""); + attr->u.Attr.specified = 1; + if (attr->nodeName == NULL || attr->nodeValue == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(doc, attr); + return NULL; + } + } + + return attr; +} +DOM_EntityReference * +DOM_Document_createEntityReference(DOM_Document *doc, const DOM_String *name) +{ + DOM_EntityReference *eref; + + eref = Document_createNode(doc, DOM_ENTITY_REFERENCE_NODE); + if (eref && (eref->nodeName = strdup(name)) == NULL) { + DOM_Document_destroyNode(doc, eref); + return NULL; + } + + return eref; +} + +DOM_NodeList * +DOM_Document_getElementsByTagName(DOM_Document *doc, const DOM_String *tagname) +{ + DOM_NodeList *list; + + if (doc && doc->nodeType == DOM_DOCUMENT_NODE && + tagname && (list = Document_createNodeList(doc))) { + getElementsPreorder(list, doc->u.Document.documentElement, tagname); + return list; + } + + return NULL; +} +DOM_DocumentType * +DOM_Document_getDoctype(DOM_Document *doc) +{ + return doc ? doc->u.Document.doctype : NULL; +} +DOM_Element * +DOM_Document_getDocumentElement(DOM_Document *doc) +{ + return doc ? doc->u.Document.documentElement : NULL; +} + +/* Temporary functions */ + +void +printNode(DOM_Node *node, int indent) +{ + DOM_Node *n; + int i; + + if (node == NULL) { + printf("node was null\n"); + return; + } + + for (i = 0; i < indent; i++) { + printf(" "); + } + + printf("%s: %s=%s\n", node_names[node->nodeType], node->nodeName, node->nodeValue); + + if (node->nodeType == DOM_ELEMENT_NODE && node->attributes->length) { + printf(" "); + n = DOM_NamedNodeMap_item(node->attributes, 0); + printf("%s=%s", n->nodeName, n->nodeValue); + for (i = 1; i < node->attributes->length; i++) { + n = DOM_NamedNodeMap_item(node->attributes, i); + printf(",%s=%s", n->nodeName, n->nodeValue); + } + printf("\n"); + for (i = 0; i < indent; i++) { + printf(" "); + } + } + for (n = node->firstChild; n != NULL; n = n->nextSibling) { + printNode(n, indent + 1); + } +} +void +DOM_Node_printNode2(DOM_Node *node) +{ + printf("\n"); + printNode(node, 0); +} +void +DOM_Node_printNode(DOM_Node *node) +{ + if (node == NULL) { + printf("node was null\n"); + return; + } + + printf("\nnodeName=%s,nodeValue=%s,", node->nodeName, node->nodeValue); + printf("\n\ttype=%u", node->nodeType); + printf(",parentNode->nodeName=%s,firstChild->nodeName=%s", (node->parentNode == NULL ? "(null)" : node->parentNode->nodeName), (node->firstChild == NULL ? "(null)" : node->firstChild->nodeName)); + printf(",lastChild->nodeName=%s,\n\tchildNodes->length=%u", (node->lastChild == NULL ? "(null)" : node->lastChild->nodeName), (node->childNodes == NULL ? 0 : node->childNodes->length)); + printf(",previousSibling->nodeName=%s,nextSibling->nodeName=%s,attributes->length=%u\n", (node->previousSibling == NULL ? "(null)" : node->previousSibling->nodeName), (node->nextSibling == NULL ? "(null)": node->nextSibling->nodeName), (node->attributes == NULL ? 0 : node->attributes->length)); + fflush(stdout); +} + + +/* NamedNodeMap + */ + +void +DOM_Document_destroyNamedNodeMap(DOM_Document *doc, DOM_NamedNodeMap *map, int free_nodes) +{ + DOM_Document_destroyNodeList(doc, map, free_nodes); +} +DOM_NamedNodeMap * +Document_createNamedNodeMap(DOM_Document *doc) +{ + return Document_createNodeList(doc); +} + +DOM_Node * +DOM_NamedNodeMap_getNamedItem(const DOM_NamedNodeMap *map, const DOM_String *name) +{ + NodeEntry *e; + unsigned short nodeType; + + if (map && name) { + if (map->filter) { + nodeType = map->filter; + map = map->list; + for (e = map->first; e != NULL; e = e->next) { + if (e->node->nodeType == nodeType && strcoll(name, e->node->nodeName) == 0) { + return e->node; + } + } + } else { + for (e = map->first; e != NULL; e = e->next) { + if (strcoll(name, e->node->nodeName) == 0) { + return e->node; + } + } + } + } + + return NULL; +} +DOM_Node * +DOM_NamedNodeMap_setNamedItem(DOM_NamedNodeMap *map, DOM_Node *arg) +{ + NodeEntry *e; + + if (map && arg) { + if (map->filter) { + DOM_Exception = DOM_NO_MODIFICATION_ALLOWED_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (map->_ownerDocument != arg->ownerDocument) { + DOM_Exception = DOM_WRONG_DOCUMENT_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (arg->nodeType == DOM_ATTRIBUTE_NODE && arg->u.Attr.ownerElement && + arg->u.Attr.ownerElement != map->_ownerElement) { + DOM_Exception = DOM_INUSE_ATTRIBUTE_ERR; + PMNO(DOM_Exception); + return NULL; + } + for (e = map->first; e != NULL && strcoll(arg->nodeName, e->node->nodeName); e = e->next) { + ; + } + if (e) { + DOM_Node *tmp = e->node; + e->node = arg; + if (arg->nodeType == DOM_ATTRIBUTE_NODE) { + arg->u.Attr.ownerElement = map->_ownerElement; + tmp->u.Attr.ownerElement = NULL; + } + return tmp; + } + NodeList_append(map, arg); + } + + return NULL; +} +DOM_Node * +DOM_NamedNodeMap_removeNamedItem(DOM_NamedNodeMap *map, const DOM_String *name) +{ + NodeEntry *e; + DOM_Node *r = NULL; + + if (map && name) { + if (map->filter) { + DOM_Exception = DOM_NO_MODIFICATION_ALLOWED_ERR; + PMNO(DOM_Exception); + return NULL; + } + for (e = map->first; e != NULL; e = e->next) { + if (strcoll(name, e->node->nodeName) == 0 && + NodeList_remove(map, e->node)) { + r = e->node; + free(e); + if (r->nodeType == DOM_ATTRIBUTE_NODE) { + r->u.Attr.ownerElement = NULL; + } + return r; + } + } + } + + DOM_Exception = DOM_NOT_FOUND_ERR; + PMNO(DOM_Exception); + return NULL; +} +DOM_Node * +DOM_NamedNodeMap_item(const DOM_NamedNodeMap *map, int index) +{ + return DOM_NodeList_item(map, index); +} + + +/* Forward references + */ + +void DOM_Document_destroyNamedNodeMap(DOM_Document *doc, DOM_NamedNodeMap *nnm, int free_nodes); +void updateCommonParent(DOM_Node *node); + +/* Node + */ + +void +DOM_Document_destroyNode(DOM_Document *doc, DOM_Node *node) +{ + if (node == NULL) { + return; + } + + if (node->childNodes) { + DOM_Document_destroyNodeList(doc, node->childNodes, 1); + } + if (node->listeners) { + unsigned int i; + + for (i = 0; i < node->listeners_len; i++) { + if (node->listeners[i]) { + free(node->listeners[i]->type); + free(node->listeners[i]); + } + } + free(node->listeners); + } + + switch(node->nodeType) { + case DOM_ELEMENT_NODE: + DOM_Document_destroyNamedNodeMap(doc, node->attributes, 1); + free(node->nodeName); + break; + case DOM_TEXT_NODE: + case DOM_COMMENT_NODE: + case DOM_CDATA_SECTION_NODE: + free(node->nodeValue); + break; + case DOM_ATTRIBUTE_NODE: + free(node->nodeName); + free(node->nodeValue); + break; + case DOM_ENTITY_REFERENCE_NODE: + case DOM_ENTITY_NODE: + free(node->nodeName); + free(node->nodeValue); + free(node->u.Entity.publicId); + free(node->u.Entity.systemId); + free(node->u.Entity.notationName); + break; + case DOM_PROCESSING_INSTRUCTION_NODE: + free(node->nodeName); + free(node->nodeValue); + break; + case DOM_DOCUMENT_NODE: + free(node->u.Document.version); + free(node->u.Document.encoding); + break; + case DOM_DOCUMENT_TYPE_NODE: + DOM_Document_destroyNamedNodeMap(doc, node->u.DocumentType.entities, 0); + DOM_Document_destroyNamedNodeMap(doc, node->u.DocumentType.notations, 0); + free(node->u.DocumentType.publicId); + free(node->u.DocumentType.systemId); + free(node->nodeName); + break; + case DOM_NOTATION_NODE: + free(node->nodeName); + free(node->u.Notation.publicId); + free(node->u.Notation.systemId); + break; + } + free(node); +} +DOM_Node * +Document_createNode(DOM_Document *doc, unsigned short nodeType) +{ + DOM_Node *node; + + msgno_add_codes(dom_codes); + + if (doc == NULL && nodeType != DOM_DOCUMENT_NODE && nodeType != DOM_DOCUMENT_TYPE_NODE) { + DOM_Exception = NULL_POINTER_ERR; + PMNF(DOM_Exception, ": doc=NULL,nodeType=%u", nodeType); + return NULL; + } + + node = calloc(sizeof *node, 1); + if (node == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return NULL; + } + + node->nodeType = nodeType; + node->ownerDocument = doc; + switch (nodeType) { + case DOM_DOCUMENT_NODE: + case DOM_DOCUMENT_TYPE_NODE: + /* DocumentType doesn't really have children but we need to store DTD + * entries other than entities and notations */ + case DOM_ELEMENT_NODE: + case DOM_ATTRIBUTE_NODE: + case DOM_ENTITY_REFERENCE_NODE: + case DOM_ENTITY_NODE: + case DOM_DOCUMENT_FRAGMENT_NODE: + node->childNodes = Document_createNodeList(doc); + if (node->childNodes == NULL) { + AMNO(DOM_CREATE_FAILED); + DOM_Document_destroyNode(doc, node); + return NULL; + } + } + + return node; +} + +static int +_isAncestor(DOM_Node *node, DOM_Node *parent) +{ + DOM_Node *p; + + for (p = parent; p; p = p->parentNode) { + if (p == node) { + return 1; + } + } + return 0; +} + +static void +dispatchEventPreorder(DOM_Node *node, DOM_MutationEvent *evt) +{ + DOM_Node *n; + + DOM_EventTarget_dispatchEvent(node, evt); + + for (n = node->firstChild; n != NULL; n = n->nextSibling) { + dispatchEventPreorder(n, evt); + } +} +static void +dispatchEventPostorder(DOM_Node *node, DOM_MutationEvent *evt) +{ + DOM_Node *n; + + for (n = node->firstChild; n != NULL; n = n->nextSibling) { + dispatchEventPostorder(n, evt); + } + + DOM_EventTarget_dispatchEvent(node, evt); +} +static DOM_Node * +_removeChild(DOM_Node *node, DOM_Node *oldChild) +{ + NodeEntry *e; + DOM_MutationEvent evt; + + if (NodeList_exists(node->childNodes, oldChild) == 0) { + return NULL; + } + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeRemoved", 1, 0, node, NULL, NULL, NULL, 0); + DOM_EventTarget_dispatchEvent(oldChild, &evt); + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeRemovedFromDocument", 0, 0, NULL, NULL, NULL, NULL, 0); + dispatchEventPostorder(oldChild, &evt); + + e = NodeList_remove(node->childNodes, oldChild); + free(e); + + if (node->firstChild == node->lastChild) { + node->firstChild = node->lastChild = NULL; + } else if (oldChild == node->firstChild) { + node->firstChild = oldChild->nextSibling; + node->firstChild->previousSibling = NULL; + } else if (oldChild == node->lastChild) { + node->lastChild = oldChild->previousSibling; + node->lastChild->nextSibling = NULL; + } else { + oldChild->previousSibling->nextSibling = oldChild->nextSibling; + oldChild->nextSibling->previousSibling = oldChild->previousSibling; + } + + oldChild->previousSibling = NULL; + oldChild->nextSibling = NULL; + oldChild->parentNode = NULL; + + if (MODIFYING_DOC_ELEM(node, oldChild)) { + node->u.Document.documentElement = NULL; + } else if (MODIFYING_DOCTYPE_ELEM(node, oldChild)) { + node->u.Document.doctype = NULL; + oldChild->ownerDocument = NULL; + } else { + updateCommonParent(node); + } + + return oldChild; +} +DOM_Node * +DOM_Node_insertBefore(DOM_Node *node, DOM_Node *newChild, DOM_Node *refChild) +{ + NodeEntry *e; + DOM_MutationEvent evt; + + if (node == NULL || newChild == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (newChild->ownerDocument != node->ownerDocument && + newChild->ownerDocument != node) { + DOM_Exception = DOM_WRONG_DOCUMENT_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (refChild != NULL && refChild->parentNode != node) { + DOM_Exception = DOM_HIERARCHY_REQUEST_ERR; + PMNO(DOM_Exception); + return NULL; + } + + if (newChild->nodeType == DOM_DOCUMENT_FRAGMENT_NODE) { + DOM_Node *n, *nxt; + + for (n = newChild->firstChild; n != NULL; n = n->nextSibling) { + if (INVALID_HIER_REQ(node, n) || _isAncestor(n, node)) { + DOM_Exception = DOM_HIERARCHY_REQUEST_ERR; + PMNO(DOM_Exception); + return NULL; + } + } + for (n = newChild->firstChild; n != NULL; n = nxt) { + nxt = n->nextSibling; + if (_removeChild(newChild, n) == NULL) { + return NULL; + } + if (DOM_Node_insertBefore(node, n, refChild) == NULL) { + DOM_Document_destroyNode(n->ownerDocument, n); + return NULL; + } + } + return newChild; + } + if (INVALID_HIER_REQ(node, newChild) || _isAncestor(newChild, node)) { + DOM_Exception = DOM_HIERARCHY_REQUEST_ERR; + PMNO(DOM_Exception); + return NULL; + } + + _removeChild(node, newChild); + + if ((e = NodeList_insert(node->childNodes, newChild, refChild)) == NULL) { + return NULL; + } + + if (node->firstChild == NULL) { + node->firstChild = node->lastChild = newChild; + newChild->previousSibling = NULL; + newChild->nextSibling = NULL; + } else if (refChild == NULL) { + newChild->previousSibling = node->lastChild; + node->lastChild->nextSibling = newChild; + node->lastChild = newChild; + newChild->nextSibling = NULL; + } else { + newChild->previousSibling = refChild->previousSibling; + newChild->nextSibling = refChild; + if (refChild == node->firstChild) { + node->firstChild = newChild; + newChild->previousSibling = NULL; + } else { + refChild->previousSibling->nextSibling = newChild; + } + refChild->previousSibling = newChild; + } + newChild->parentNode = node; + + if (MODIFYING_DOC_ELEM(node, newChild)) { + node->u.Document.documentElement = newChild; + } else if (MODIFYING_DOCTYPE_ELEM(node, newChild)) { + node->u.Document.doctype = newChild; + newChild->ownerDocument = node; + } + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeInserted", 1, 0, node, NULL, NULL, NULL, 0); + DOM_EventTarget_dispatchEvent(newChild, &evt); + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeInsertedIntoDocument", 0, 0, NULL, NULL, NULL, NULL, 0); + dispatchEventPreorder(newChild, &evt); + + updateCommonParent(node); + + return newChild; +} +DOM_Node * +DOM_Node_replaceChild(DOM_Node *node, DOM_Node *newChild, DOM_Node *oldChild) +{ + DOM_MutationEvent evt; + + if (node == NULL || newChild == NULL || oldChild == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (newChild->ownerDocument != node->ownerDocument && + newChild->ownerDocument != node) { + DOM_Exception = DOM_WRONG_DOCUMENT_ERR; + PMNO(DOM_Exception); + return NULL; + } + + if (!NodeList_exists(node->childNodes, oldChild)) { + DOM_Exception = DOM_NOT_FOUND_ERR; + PMNO(DOM_Exception); + return NULL; + } + + if (newChild->nodeType == DOM_DOCUMENT_FRAGMENT_NODE) { + DOM_Node *n, *nxt; + + for (n = newChild->firstChild; n != NULL; n = n->nextSibling) { + if (INVALID_HIER_REQ(node, n) || _isAncestor(n, node)) { + DOM_Exception = DOM_HIERARCHY_REQUEST_ERR; + PMNO(DOM_Exception); + return NULL; + } + } + for (n = newChild->firstChild; n != NULL; n = nxt) { + nxt = n->nextSibling; + if (_removeChild(newChild, n) == NULL) { + return NULL; + } + if (DOM_Node_insertBefore(node, n, oldChild) == NULL) { + DOM_Document_destroyNode(n->ownerDocument, n); + return NULL; + } + } + + if (_removeChild(node, oldChild) == NULL) { + return NULL; + } + + return oldChild; + } + if (INVALID_HIER_REQ(node, newChild) || _isAncestor(newChild, node)) { + DOM_Exception = DOM_HIERARCHY_REQUEST_ERR; + PMNO(DOM_Exception); + return NULL; + } + + _removeChild(node, newChild); + + if (NodeList_exists(node->childNodes, oldChild) == 0) { + return NULL; + } + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeRemoved", 1, 0, node, NULL, NULL, NULL, 0); + DOM_EventTarget_dispatchEvent(oldChild, &evt); + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeRemovedFromDocument", 0, 0, NULL, NULL, NULL, NULL, 0); + dispatchEventPostorder(oldChild, &evt); + + NodeList_replace(node->childNodes, newChild, oldChild); + + node->firstChild = node->childNodes->first->node; + node->lastChild = node->childNodes->last->node; + + if ((newChild->previousSibling = oldChild->previousSibling)) { + newChild->previousSibling->nextSibling = newChild; + } + if ((newChild->nextSibling = oldChild->nextSibling)) { + newChild->nextSibling->previousSibling = newChild; + } + + newChild->parentNode = node; + oldChild->parentNode = NULL; + oldChild->previousSibling = NULL; + oldChild->nextSibling = NULL; + + if (MODIFYING_DOC_ELEM(node, newChild)) { + node->u.Document.documentElement = newChild; + } else if (MODIFYING_DOCTYPE_ELEM(node, newChild)) { + node->u.Document.doctype = newChild; + newChild->ownerDocument = node; + } + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeInserted", 1, 0, node, NULL, NULL, NULL, 0); + DOM_EventTarget_dispatchEvent(newChild, &evt); + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeInsertedIntoDocument", 0, 0, NULL, NULL, NULL, NULL, 0); + dispatchEventPreorder(newChild, &evt); + + updateCommonParent(node); + + return oldChild; +} +DOM_Node * +DOM_Node_removeChild(DOM_Node *node, DOM_Node *oldChild) +{ + if (node == NULL || oldChild == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (oldChild->ownerDocument != node->ownerDocument && + oldChild->ownerDocument != node) { + DOM_Exception = DOM_WRONG_DOCUMENT_ERR; + PMNO(DOM_Exception); + return NULL; + } + + if ((oldChild = _removeChild(node, oldChild)) == NULL) { + DOM_Exception = DOM_NOT_FOUND_ERR; + PMNO(DOM_Exception); + } + + return oldChild; +} +DOM_Node * +DOM_Node_appendChild(DOM_Node *node, DOM_Node *newChild) +{ + DOM_MutationEvent evt; + + if (node == NULL || newChild == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (newChild->ownerDocument != node->ownerDocument && + node->nodeType != DOM_DOCUMENT_NODE && + newChild->nodeType != DOM_DOCUMENT_TYPE_NODE) { + DOM_Exception = DOM_WRONG_DOCUMENT_ERR; + PMNO(DOM_Exception); + return NULL; + } + + if (newChild->nodeType == DOM_DOCUMENT_FRAGMENT_NODE) { + DOM_Node *n, *nxt; + + for (n = newChild->firstChild; n != NULL; n = n->nextSibling) { + if (INVALID_HIER_REQ(node, n) || _isAncestor(n, node)) { + DOM_Exception = DOM_HIERARCHY_REQUEST_ERR; + PMNO(DOM_Exception); + return NULL; + } + } + for (n = newChild->firstChild; n != NULL; n = nxt) { + nxt = n->nextSibling; + if (_removeChild(newChild, n) == NULL) { + return NULL; + } + if (DOM_Node_appendChild(node, n) == NULL) { + DOM_Document_destroyNode(n->ownerDocument, n); + return NULL; + } + } + return newChild; + } + if (INVALID_HIER_REQ(node, newChild) || _isAncestor(newChild, node)) { + DOM_Exception = DOM_HIERARCHY_REQUEST_ERR; + PMNO(DOM_Exception); + return NULL; + } + + _removeChild(node, newChild); + + if (NodeList_append(node->childNodes, newChild) == NULL) { + return NULL; + } + + if (node->firstChild == NULL) { + node->firstChild = node->lastChild = newChild; + newChild->previousSibling = NULL; + newChild->nextSibling = NULL; + } else { + node->lastChild->nextSibling = newChild; + newChild->previousSibling = node->lastChild; + node->lastChild = newChild; + } + newChild->nextSibling = NULL; + newChild->parentNode = node; + + if (MODIFYING_DOC_ELEM(node, newChild)) { + node->u.Document.documentElement = newChild; + } else if (MODIFYING_DOCTYPE_ELEM(node, newChild)) { + node->u.Document.doctype = newChild; + newChild->ownerDocument = node; + } + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeInserted", 1, 0, node, NULL, NULL, NULL, 0); + DOM_EventTarget_dispatchEvent(newChild, &evt); + + DOM_MutationEvent_initMutationEvent(&evt, + "DOMNodeInsertedIntoDocument", 0, 0, NULL, NULL, NULL, NULL, 0); + dispatchEventPreorder(newChild, &evt); + + updateCommonParent(node); + + return newChild; +} +int +DOM_Node_hasChildNodes(const DOM_Node *node) +{ + return node != NULL && node->firstChild; +} +extern const char *node_names[]; +static DOM_Node * +Node_cloneNode(DOM_Document *ownerDocument, DOM_Node *node, int deep) +{ + DOM_Node *clone = NULL; + DOM_Node *ntmp, *ctmp; + NodeEntry *e; + DOM_String *tmp; + + switch(node->nodeType) { + case DOM_ELEMENT_NODE: + clone = DOM_Document_createElement(ownerDocument, node->nodeName); + if (clone) { + for (e = node->attributes->first; e != NULL; e = e->next) { + if ((ctmp = Node_cloneNode(ownerDocument, e->node, deep)) == NULL || + NodeList_append(clone->attributes, ctmp) == NULL) { + DOM_Document_destroyNode(clone->ownerDocument, ctmp); + DOM_Document_destroyNode(clone->ownerDocument, clone); + return NULL; + } + } + } + break; + case DOM_ATTRIBUTE_NODE: + if ((clone = DOM_Document_createAttribute(ownerDocument, node->nodeName))) { + clone->u.Attr.specified = node->u.Attr.specified; + free(clone->nodeValue); + clone->u.Attr.value = clone->nodeValue = mbsdup(node->nodeValue); + if (clone->u.Attr.value == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(clone->ownerDocument, clone); + return NULL; + } + } + break; + case DOM_COMMENT_NODE: + clone = DOM_Document_createComment(ownerDocument, node->nodeValue); + break; + case DOM_TEXT_NODE: + clone = DOM_Document_createTextNode(ownerDocument, node->nodeValue); + break; + case DOM_CDATA_SECTION_NODE: + clone = DOM_Document_createCDATASection(ownerDocument, node->nodeValue); + break; + case DOM_DOCUMENT_FRAGMENT_NODE: + clone = DOM_Document_createDocumentFragment(ownerDocument); + break; + case DOM_DOCUMENT_NODE: + clone = ownerDocument; + break; + case DOM_PROCESSING_INSTRUCTION_NODE: + clone = DOM_Document_createProcessingInstruction(ownerDocument, + node->u.ProcessingInstruction.target, + node->u.ProcessingInstruction.data); + break; + case DOM_ENTITY_NODE: + if ((clone = Document_createNode(ownerDocument, DOM_ENTITY_NODE))) { + tmp = node->nodeValue; + if ((clone->nodeName = mbsdup(node->nodeName)) == NULL || + /* This will eventually go away as Entities should not have nodeValues + */ + (clone->nodeValue = mbsdup(node->nodeValue)) == NULL || + (node->u.Entity.publicId && + (clone->u.Entity.publicId = mbsdup(node->u.Entity.publicId)) == NULL) || + (node->u.Entity.systemId && + (clone->u.Entity.systemId = mbsdup(node->u.Entity.systemId)) == NULL) || + (node->u.Entity.notationName && + (clone->u.Entity.notationName = mbsdup(node->u.Entity.notationName)) == NULL)) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(clone->ownerDocument, clone); + return NULL; + } + free(tmp); + } + break; + case DOM_NOTATION_NODE: + if ((clone = Document_createNode(ownerDocument, DOM_NOTATION_NODE))) { + if ((clone->nodeName = mbsdup(node->nodeName)) == NULL || + (node->u.Notation.publicId && + (clone->u.Notation.publicId = mbsdup(node->u.Notation.publicId)) == NULL) || + (node->u.Notation.systemId && + (clone->u.Notation.systemId = mbsdup(node->u.Notation.systemId)) == NULL)) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(clone->ownerDocument, clone); + return NULL; + } + } + break; + case DOM_DOCUMENT_TYPE_NODE: + if ((clone = DOM_Implementation_createDocumentType(node->nodeName, NULL, NULL))) { + if ((node->u.DocumentType.publicId && + (clone->u.DocumentType.publicId = mbsdup(node->u.DocumentType.publicId)) == NULL) || + (node->u.DocumentType.systemId && + (clone->u.DocumentType.systemId = mbsdup(node->u.DocumentType.systemId)) == NULL)) { + DOM_Exception = errno; + PMNO(DOM_Exception); + DOM_Document_destroyNode(clone->ownerDocument, clone); + return NULL; + } + } + ownerDocument->u.Document.doctype = clone; + clone->ownerDocument = ownerDocument; + break; + case DOM_ENTITY_REFERENCE_NODE: + DOM_Exception = DOM_NOT_SUPPORTED_ERR; + PMNO(DOM_Exception); + return NULL; + } + + if (deep && clone && node->childNodes) { + for (ntmp = node->firstChild; ntmp != NULL; ntmp = ntmp->nextSibling) { + ctmp = Node_cloneNode(ownerDocument, ntmp, 1); + if (ctmp == NULL || DOM_Node_appendChild(clone, ctmp) == NULL) { + DOM_Document_destroyNode(clone->ownerDocument, ctmp); + DOM_Document_destroyNode(clone->ownerDocument, clone); + return NULL; + } + } + } + + return clone; +} +DOM_Node * +DOM_Node_cloneNode(DOM_Node *node, int deep) +{ + if (node == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (node->nodeType == DOM_DOCUMENT_NODE) { + DOM_Document *doc; + if ((doc = DOM_Implementation_createDocument(NULL, NULL, NULL)) == NULL) { + AMSG(""); + return NULL; + } + return Node_cloneNode(doc, node, deep); + } + return Node_cloneNode(node->ownerDocument, node, deep); +} +DOM_String * +DOM_Node_getNodeValue(DOM_Node *node) +{ + if (node == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + return node->nodeValue; +} +void +DOM_Node_setNodeValue(DOM_Node *node, DOM_String *value) +{ + DOM_String *str = NULL; + + if (node == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return; + } + switch(node->nodeType) { + case DOM_ATTRIBUTE_NODE: + case DOM_COMMENT_NODE: + case DOM_TEXT_NODE: + case DOM_CDATA_SECTION_NODE: + case DOM_PROCESSING_INSTRUCTION_NODE: + if ((str = mbsdup(value)) == NULL) { + DOM_Exception = errno; + AMSG(""); + return; + } + break; + } + switch(node->nodeType) { + case DOM_ATTRIBUTE_NODE: + free(node->nodeValue); + node->nodeValue = node->u.Attr.value = str; + break; + case DOM_COMMENT_NODE: + case DOM_TEXT_NODE: + case DOM_CDATA_SECTION_NODE: + free(node->nodeValue); + node->nodeValue = node->u.CharacterData.data = str; + break; + case DOM_PROCESSING_INSTRUCTION_NODE: + free(node->nodeValue); + node->nodeValue = node->u.ProcessingInstruction.data = str; + break; + default: + return; /* No effect */ + } +} + + +#if FAST_NODELIST + +/* The number of nodes required in a list before hashing starts */ +#define FAST_FILLFACTOR 16 + +static void _removeFromMap(DOM_NodeList* nl, DOM_Node* key) +{ + if (nl->_map) { + if (hashmap_get(nl->_map, key) != NULL) { + void* d = NULL; + void* k = key; + hashmap_remove(nl->_map, &k, &d); + } + } +} + +static int _addToMap(DOM_NodeList* nl, DOM_Node* key, NodeEntry* val) +{ + if (!nl->_map && nl->length > FAST_FILLFACTOR) { + + nl->_map = hashmap_new(0, NULL, NULL, NULL); + + /* Hash what we currently have */ + if (nl->_map) { + NodeEntry *e = nl->first; + while (e) { + _addToMap(nl, e->node, e); + e = e->next; + } + } + } + + if (nl->_map) { + _removeFromMap(nl, key); + + if (hashmap_put(nl->_map, key, val) == -1) { + DOM_Exception = errno; + return -1; + } + } + + return 0; +} + +#endif + +static NodeEntry* _lookupNode(DOM_NodeList* nl, DOM_Node* node) +{ + NodeEntry* s; + +#if FAST_NODELIST + if (nl->_map) + s = (NodeEntry*)hashmap_get(nl->_map, node); + else +#endif + for (s = nl->first; s != NULL && s->node != node; s = s->next) { + ; + } + + return s; +} + +/* NodeList + */ + +DOM_NodeList * +Document_createNodeList(DOM_Document *doc) +{ + DOM_NodeList *r; + + if ((r = calloc(sizeof *r, 1)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + } + r->_ownerDocument = doc; + + return r; +} +void +DOM_Document_destroyNodeList(DOM_Document *doc, DOM_NodeList *nl, int free_nodes) +{ + if (nl) { + if (nl->filter == 0) { + NodeEntry *e, *tmp; + + e = nl->first; + while (e != NULL) { + if (free_nodes) { + DOM_Document_destroyNode(doc, e->node); + } + tmp = e; + e = e->next; + free(tmp); + } + } + +#if FAST_NODELIST + if(nl->_map) + hashmap_del(nl->_map, NULL, NULL, NULL); +#endif + + free(nl); + } +} + +DOM_Node * +NodeList_itemFiltered(const DOM_NodeList *list, int index, unsigned short nodeType) +{ + if (list && index >= 0 && index < list->length) { + NodeEntry *e; + + for (e = list->first; e != NULL; e = e->next) { + if (e->node->nodeType == nodeType) { + if (index == 0) { + return e->node; + } + index--; + } + } + } + + return NULL; +} +DOM_Node * +DOM_NodeList_item(const DOM_NodeList *list, int index) +{ + if (list) { + if (list->filter) { + return NodeList_itemFiltered(list->list, index, list->filter); + } + + if (index >= 0 && index < list->length) { + NodeEntry *e; + + for (e = list->first; e != NULL; e = e->next, index--) { + if (index == 0) { + return e->node; + } + } + } + } + + return NULL; +} +NodeEntry * +NodeList_insert(DOM_NodeList *nl, DOM_Node *newChild, DOM_Node *refChild) +{ + NodeEntry *e; + NodeEntry *s = NULL; + + if (nl == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (nl->filter) { + DOM_Exception = DOM_FILTERED_LIST_ERR; + PMNO(DOM_Exception); + return NULL; + } + + if(refChild != NULL) + { + s = _lookupNode(nl, refChild); + if(s == NULL || s->node != refChild) { + DOM_Exception = DOM_NOT_FOUND_ERR; + PMNO(DOM_Exception); + return NULL; + } + } + + if ((e = calloc(sizeof *e, 1)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return NULL; + } + +#if FAST_NODELIST + if (_addToMap(nl, newChild, e) == -1) { + PMNO(DOM_Exception); + free(e); + return NULL; + } +#endif + + e->node = newChild; + if (nl->length == 0) { + nl->first = nl->last = e; + } else if (refChild == NULL) { + e->prev = nl->last; + nl->last->next = e; + nl->last = e; + } else { + e->prev = s->prev; + e->next = s; + if (s == nl->first) { + nl->first = e; + } else { + s->prev->next = e; + } + s->prev = e; + } + nl->length++; + + /* If an attribute is being added this is probably a NamedNodeMap + * in which case we must set the ownerElement. + */ + if (newChild->nodeType == DOM_ATTRIBUTE_NODE) { + newChild->u.Attr.ownerElement = nl->_ownerElement; + } + + return e; +} +NodeEntry * +NodeList_replace(DOM_NodeList *nl, DOM_Node *newChild, DOM_Node *oldChild) +{ + NodeEntry *e; + + if (nl == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (nl->filter) { + DOM_Exception = DOM_FILTERED_LIST_ERR; + PMNO(DOM_Exception); + return NULL; + } + + e = _lookupNode(nl, oldChild); + if (e == NULL) { + DOM_Exception = DOM_NOT_FOUND_ERR; + PMNO(DOM_Exception); + return NULL; + } + +#if FAST_NODELIST + _removeFromMap(nl, oldChild); + if(_addToMap(nl, newChild, e) == -1) { + PMNO(DOM_Exception); + return NULL; + } +#endif + + e->node = newChild; + + if (oldChild->nodeType == DOM_ATTRIBUTE_NODE) { + oldChild->u.Attr.ownerElement = NULL; + } + + return e; +} +NodeEntry * +NodeList_remove(DOM_NodeList *nl, DOM_Node *oldChild) +{ + NodeEntry *e; + + if (nl == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (nl->filter) { + DOM_Exception = DOM_FILTERED_LIST_ERR; + PMNO(DOM_Exception); + return NULL; + } + + e = _lookupNode(nl, oldChild); + if (e == NULL) { + return NULL; + } + +#if FAST_NODELIST + _removeFromMap(nl, oldChild); +#endif + + if (nl->first == nl->last) { + nl->first = nl->last = NULL; + } else if (e == nl->first) { + nl->first = e->next; + nl->first->prev = NULL; + } else if (e == nl->last) { + nl->last = e->prev; + nl->last->next = NULL; + } else { + e->prev->next = e->next; + e->next->prev = e->prev; + } + nl->length--; + + /* Decrement a filtered node list too? */ + + if (oldChild->nodeType == DOM_ATTRIBUTE_NODE) { + oldChild->u.Attr.ownerElement = NULL; + } + + return e; +} +extern const char *node_names[]; +NodeEntry * +NodeList_append(DOM_NodeList *nl, DOM_Node *newChild) +{ + NodeEntry *e; + DOM_DocumentType *doctype; + + if (nl == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNF(DOM_Exception, ": %p", newChild); + return NULL; + } + if (nl->filter) { + DOM_Exception = DOM_FILTERED_LIST_ERR; + PMNO(DOM_Exception); + return NULL; + } + + if ((e = calloc(sizeof *e, 1)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return NULL; + } + +#if FAST_NODELIST + if(_addToMap(nl, newChild, e) == -1) { + PMNO(DOM_Exception); + free(e); + return NULL; + } +#endif + + e->node = newChild; + if (nl->first == NULL) { + nl->first = nl->last = e; + } else { + nl->last->next = e; + e->prev = nl->last; + nl->last = e; + } + + nl->length++; + + /* If the node list is the DocumentType children and a Notation + * or Entity is being added we must artificially update the length + * member of those filtered lists + */ + if (newChild->ownerDocument && + (doctype = newChild->ownerDocument->u.Document.doctype) && + nl == doctype->childNodes) { + if (newChild->nodeType == DOM_NOTATION_NODE) { + doctype->u.DocumentType.notations->length++; + } else if (newChild->nodeType == DOM_ENTITY_NODE) { + doctype->u.DocumentType.entities->length++; + } + } + /* If an attribute is being added this is probably a NamedNodeMap + * in which case we must set the ownerElement. + */ + if (newChild->nodeType == DOM_ATTRIBUTE_NODE) { + newChild->u.Attr.ownerElement = nl->_ownerElement; + } + + return e; +} +int +NodeList_exists(DOM_NodeList *nl, DOM_Node *child) +{ + NodeEntry *e; + + if (nl == NULL || nl->filter) { + return 0; + } + + e = _lookupNode(nl, child); + return e != NULL; +} + +#if HAVE_ENCDEC > 0 +#include +#elif HAVE_STRNLEN < 1 + +static size_t +strnlen(const char *s, size_t maxlen) +{ + size_t len; + for (len = 0; *s && len < maxlen; s++, len++); + return len; +} + +#else + +size_t strnlen(const char *s, size_t maxlen); + +#endif + +/* Forward references for node.c + */ + +DOM_Node *Document_createNode(DOM_Document *doc, unsigned short nodeType); + +static int +fputds(const DOM_String *s, FILE *stream) +{ + return fputs(s, stream); +} + +static void +fputds_encoded(const DOM_String *s, FILE *stream) +{ + size_t l; + + while (*s) { + l = strcspn(s, "<>&\""); + if (l > 0) { + fwrite((void*)s, 1, sizeof(DOM_String) * l, stream); + s += l; + } + switch (*s) { + case '\0': + break; + case '<': + fputs("<", stream); + break; + case '>': + fputs(">", stream); + break; + case '&': + fputs("'", stream); + break; + case '"': + fputs(""", stream); + break; + default: + AMSG(""); + break; + }; + if(*s) + ++s; + } +} + +int +DOM_DocumentLS_fwrite(const DOM_DocumentLS *node, FILE *stream) +{ + NodeEntry *e; + DOM_Node *c; + + if (node == NULL || stream == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNF(DOM_Exception, ": node=%p,stream=%p", node, stream); + return -1; + } + + if (DOM_Exception) { + return -1; + } + + switch (node->nodeType) { + case DOM_ELEMENT_NODE: + fputc('<', stream); + fputds(node->nodeName, stream); + for (e = node->attributes->first; e != NULL; e = e->next) { + fputc(' ', stream); + fputds(e->node->nodeName, stream); + fputs("=\"", stream); + fputds_encoded(e->node->nodeValue, stream); + fputc('"', stream); + } + if (DOM_Node_hasChildNodes(node)) { + fputc('>', stream); + for (c = node->firstChild; c != NULL; c = c->nextSibling) { + if (DOM_DocumentLS_fwrite(c, stream) == -1) { + /* Don't put msgno macro here or might overrun buf */ + return -1; + } + } + fputs("nodeName, stream); + fputc('>', stream); + } else { + fputs("/>", stream); + } + break; + case DOM_ATTRIBUTE_NODE: + break; + case DOM_TEXT_NODE: + fputds_encoded(node->nodeValue, stream); + break; + case DOM_CDATA_SECTION_NODE: + break; + case DOM_ENTITY_REFERENCE_NODE: + break; + case DOM_NOTATION_NODE: + fputs(" nodeName, stream); + if (node->u.Entity.publicId) { + fputs(" PUBLIC \"", stream); + fputds(node->u.Entity.publicId, stream); + fputs("\" \"", stream); + fputds(node->u.Entity.systemId, stream); + fputc('"', stream); + } else if (node->u.Entity.systemId) { + fputs(" SYSTEM \"", stream); + fputds(node->u.Entity.systemId, stream); + fputc('"', stream); + } + fputs(">", stream); + break; + case DOM_ENTITY_NODE: + fputs(" nodeName, stream); + if (node->nodeValue) { + fputc('"', stream); + fputds(node->nodeValue, stream); + fputc('"', stream); + } else { + if (node->u.Entity.publicId) { + fputs(" PUBLIC \"", stream); + fputds(node->u.Entity.publicId, stream); + fputs("\" \"", stream); + fputds(node->u.Entity.systemId, stream); + fputc('"', stream); + } else if (node->u.Entity.systemId) { + fputs(" SYSTEM \"", stream); + fputds(node->u.Entity.systemId, stream); + fputc('"', stream); + } + if (node->u.Entity.notationName) { + fputs(" NDATA ", stream); + fputds(node->u.Entity.notationName, stream); + } + } + fputs(">", stream); + break; + case DOM_PROCESSING_INSTRUCTION_NODE: + fputs("u.ProcessingInstruction.target, stream); + fputc(' ', stream); + fputds_encoded(node->u.ProcessingInstruction.data, stream); + fputs("?>", stream); + break; + case DOM_COMMENT_NODE: + fputs("", stream); + break; + case DOM_DOCUMENT_NODE: + fputs("u.Document.version ? node->u.Document.version : "1.0", stream); + fputc('\"', stream); +#ifdef CODESET + fputs(" encoding=\"", stream); + fputs(nl_langinfo(CODESET), stream); + fputc('\"', stream); +#endif + if (node->u.Document.standalone != 0) { + fputs(" standalone=\"yes\"", stream); + } + fputs("?>"NL, stream); + for (c = node->firstChild; c != NULL; c = c->nextSibling) { + if (DOM_DocumentLS_fwrite(c, stream) == -1) { + AMSG(""); + return -1; + } + } + fputs(NL, stream); + break; + case DOM_DOCUMENT_TYPE_NODE: + fputs(NL"u.DocumentType.name, stream); + if (node->u.DocumentType.systemId) { + fputs(" SYSTEM \"", stream); + fputds(node->u.DocumentType.systemId, stream); + fputc('"', stream); + } else if (node->u.DocumentType.publicId) { + fputs(" PUBLIC \"", stream); + fputds(node->u.DocumentType.publicId, stream); + fputc('"', stream); + } + if (node->u.DocumentType.internalSubset) { + fputs(" ["NL, stream); + fputds(node->u.DocumentType.internalSubset, stream); + fputs("]>"NL, stream); + } else { + fputs(">"NL, stream); + } + break; + case DOM_DOCUMENT_FRAGMENT_NODE: + break; + } + + return DOM_Exception ? -1 : 0; +} +int +DOM_DocumentLS_save(DOM_DocumentLS *doc, const char *uri, const DOM_Node *node) +{ + FILE *fd; + + if ((doc == NULL && node == NULL) || uri == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNF(DOM_Exception, ": doc=%p,uri=%s,node=%p", doc, uri, node); + return -1; + } + + fd = fopen(uri, "w"); + if (fd && DOM_DocumentLS_fwrite(doc ? doc : node, fd) == 0) { + fclose(fd); + return 0; + } + DOM_Exception = errno; + PMNF(DOM_Exception, ": uri=%s", uri); + + return -1; +} + + +/* DOM_DocumentEvent - Introduced in DOM Level 2 + */ + +void +DOM_DocumentEvent_destroyEvent(DOM_DocumentEvent *doc, DOM_Event *evt) +{ + if (doc && evt) { + if (evt->type) { + /*free(evt->type); */ + } + free(evt); + } +} + +DOM_Event * +DOM_DocumentEvent_createEvent(DOM_DocumentEvent *doc, const DOM_String *eventType) +{ + DOM_Event *evt; + + if (doc == NULL || eventType == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return NULL; + } + if (strcmp(eventType, "Events") == 0 || + strcmp(eventType, "UIEvents") == 0 || + strcmp(eventType, "TextEvents") == 0) { + evt = calloc(sizeof *evt, 1); + if (evt == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return NULL; + } + } else { + DOM_Exception = DOM_NOT_SUPPORTED_ERR; + PMNO(DOM_Exception); + return NULL; + } + return evt; +} + +/* DOM_Event - Introduced in DOM Level 2 + */ + +void +DOM_Event_stopPropagation(DOM_Event *evt) +{ + if (evt) { + evt->_sp = 1; + } +} +void +DOM_Event_preventDefault(DOM_Event *evt) +{ + if (evt && evt->cancelable) { + evt->_pd = 1; + } +} +void +DOM_Event_initEvent(DOM_Event *evt, const DOM_String *eventTypeArg, + int canBubbleArg, int cancelableArg) +{ + if (evt == NULL || eventTypeArg == NULL || *eventTypeArg == '\0') { + return; + } + evt->type = eventTypeArg; /* no dup? */ + evt->bubbles = canBubbleArg; + evt->cancelable = cancelableArg; +} + +/* DOM_UIEvent + */ + +void +DOM_UIEvent_initUIEvent(DOM_UIEvent *evt, const DOM_String *typeArg, + int canBubbleArg, int cancelableArg, + DOM_AbstractView *viewArg, long detailArg) +{ + if (evt == NULL || typeArg == NULL || *typeArg == '\0') { + return; + } + DOM_Event_initEvent(evt, typeArg, canBubbleArg, cancelableArg); + evt->view = viewArg; + evt->detail = detailArg; +} + +/* DOM_EventTarget - Introduced in DOM Level 2 + */ + +void +DOM_EventTarget_addEventListener(DOM_EventTarget *target, const DOM_String *type, + DOM_EventListener *listener, + DOM_EventListener_handleEvent listener_fn, + int useCapture) +{ + ListenerEntry *e; + unsigned int i; + int opos = -1; + + if (target == NULL || type == NULL || listener_fn == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return; + } + + for (i = 0; i < target->listeners_len; i++) { + e = target->listeners[i]; /* skip duplicates */ + + if (e == NULL) { + if (opos == -1) { + opos = i; /* find open position for new entry */ + } /* really need a hash code for this */ + } else if (e->listener == listener && e->listener_fn == listener_fn && + e->useCapture == useCapture && strcmp(e->type, type) == 0) { + return; + } + } + + if ((e = malloc(sizeof *e)) == NULL || + (e->type = mbsdup(type)) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + free(e); + return; + } + e->listener = listener; + e->listener_fn = listener_fn; + e->useCapture = useCapture; + + if (opos == -1) { + target->listeners = realloc(target->listeners, + sizeof *e * (target->listeners_len + 1)); + if (target->listeners == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + free(e); + return; + } + target->listeners[target->listeners_len++] = e; + } else { + target->listeners[opos] = e; + } +/*MSG("added listener: type=%s,target=%s,useCapture=%d\n", type, target->nodeName, useCapture); + */ +} +void +DOM_EventTarget_removeEventListener(DOM_EventTarget *target, const DOM_String *type, + DOM_EventListener *listener, + DOM_EventListener_handleEvent listener_fn, + int useCapture) +{ + ListenerEntry *e; + unsigned int i; + + if (target == NULL || type == NULL || listener_fn == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return; + } + + for (i = 0; i < target->listeners_len; i++) { + e = target->listeners[i]; + + if (e && e->listener == listener && e->listener_fn == listener_fn && + e->useCapture == useCapture && strcmp(e->type, type) == 0) { + target->listeners[i] = NULL; + free(e->type); + free(e); + return; + } + } +} +static void +trigger(DOM_EventTarget *target, DOM_Event *evt, int useCapture) +{ + ListenerEntry *e; + unsigned int j, lcount; + + if (target && target->listeners_len && evt->_sp == 0) { + DOM_EventListener_handleEvent *cpy_of_listener_fns; + + if ((cpy_of_listener_fns = malloc(target->listeners_len * + sizeof(*cpy_of_listener_fns))) == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return; + } + + lcount = target->listeners_len; /* copy listeners */ + for (j = 0; j < lcount; j++) { + e = target->listeners[j]; + cpy_of_listener_fns[j] = e ? e->listener_fn : NULL; + } + + evt->currentTarget = target; + for (j = 0; j < lcount; j++) { + e = target->listeners[j]; /* If the entry is NULL, the listener has + * since been removed and is therefore skipped. If it + * is not NULL but the listeners do not match, then + * it was removed but another listener was added in + * its place and therefore should be skipped. However, + * if a listener is removed but then added again + * while the current set is still being processed + * there is a chance that it will be tiggered if it + * meets the criteria tested below. Regardless of + * the slim chances of this occuring (have to be the + * same listener added to the same array) it may + * need to be addressed. + */ +/*MSG("e=%p,e->listener_fn=%p,cpy_of_listener_fns[%d]=%p,e->useCapture=%d,e->type=%s,evt->type=%s", e, e->listener_fn, j, cpy_of_listener_fns[j], e->useCapture, e->type, evt->type); + */ + + if (e && e->listener_fn == cpy_of_listener_fns[j] && + e->useCapture == useCapture && strcmp(e->type, evt->type) == 0) { + e->listener_fn(e->listener, evt); /* invoke the listener function */ + } + } + free(cpy_of_listener_fns); + } +} +int +DOM_EventTarget_dispatchEvent(DOM_EventTarget *target, DOM_Event *evt) +{ + DOM_EventTarget **targets, *t; + unsigned int tcount, i; + + if (target == NULL || evt == NULL) { + DOM_Exception = NULL_POINTER_ERR; + PMNO(DOM_Exception); + return 1; + } +/*MSG("type=%s,target=%s,listeners_len=%d", evt->type, target->nodeName, target->listeners_len); + */ + + if (evt->type == NULL || *evt->type == '\0') { + DOM_Exception = DOM_UNSPECIFIED_EVENT_TYPE_ERR; + PMNO(DOM_Exception); + return 1; + } + + targets = NULL; + evt->target = target; /* post-initialization */ + evt->timeStamp = timestamp(); + evt->_sp = 0; + evt->_pd = 0; + + tcount = 0; /* count targets/ancestors */ + for (t = target->parentNode; t; t = t->parentNode) { + tcount++; + } + if (tcount) { + targets = malloc(sizeof *targets * tcount); + if (targets == NULL) { + DOM_Exception = errno; + PMNO(DOM_Exception); + return 1; + } + } + i = tcount; /* save state of tree in targets array */ + for (t = target->parentNode; t; t = t->parentNode) { + targets[--i] = t; + } + /* Trigger capturers + */ + evt->eventPhase = DOM_EVENT_CAPTURING_PHASE; + for (i = 0; i < tcount && evt->_sp == 0; i++) { + trigger(targets[i], evt, 1); + } + /* Trigger regular listeners + */ + evt->eventPhase = DOM_EVENT_AT_TARGET; + trigger(target, evt, 0); + + /* Trigger bubblers + */ + evt->eventPhase = DOM_EVENT_BUBBLING_PHASE; + i = tcount; + while (i-- && evt->bubbles && evt->_sp == 0) { + trigger(targets[i], evt, 0); + } + + if (targets) { + free(targets); + } + return !evt->_pd; +} + +/* DOM_TextEvent - Introduced in DOM Level 3 + * http://www.w3.org/TR/2002/WD-DOM-Level-3-Events-20020208/events.html + */ + + +int +DOM_TextEvent_checkModifier(DOM_TextEvent *evt, unsigned int modifier) +{ + return evt->_modifiers & (1 << (modifier - 1)); +} +void +DOM_TextEvent_initTextEvent(DOM_TextEvent *evt, const DOM_String *typeArg, + int canBubbleArg, int cancelableArg, + DOM_AbstractView *viewArg, long detailArg, + DOM_String *outputStringArg, + unsigned int keyValArg, + unsigned int virtKeyValArg, + int visibleOutputGeneratedArg, + int numPadArg) +{ + if (evt == NULL || typeArg == NULL || *typeArg == '\0') { + return; + } + DOM_UIEvent_initUIEvent(evt, typeArg, canBubbleArg, cancelableArg, viewArg, detailArg); + evt->outputString = outputStringArg; + evt->keyVal = keyValArg; + evt->virtKeyVal = virtKeyValArg; + evt->visibleOutputGenerated = visibleOutputGeneratedArg; + evt->numPad = numPadArg; +} +void +DOM_TextEvent_initModifier(DOM_TextEvent *evt, unsigned int modifier, int value) +{ + if (evt && modifier > 0 && modifier <= DOM_VK_RIGHT_META) { + if (value) { + evt->_modifiers |= 1 << (modifier - 1); + } else { + evt->_modifiers &= ~(1 << (modifier - 1)); + } + } +} + +/* MutationEvent + */ + +void +DOM_MutationEvent_initMutationEvent(DOM_MutationEvent *evt, DOM_String *typeArg, + int canBubbleArg, int cancelableArg, + DOM_Node *relatedNodeArg, + DOM_String *prevValueArg, + DOM_String *newValueArg, + DOM_String *attrNameArg, + unsigned short attrChangeArg) +{ + if (evt == NULL || typeArg == NULL || *typeArg == '\0') { + return; + } + DOM_Event_initEvent(evt, typeArg, canBubbleArg, cancelableArg); + evt->relatedNode = relatedNodeArg; + evt->prevValue = prevValueArg; + evt->newValue = newValueArg; + evt->attrName = attrNameArg; + evt->attrChange = attrChangeArg; +} +void +updateCommonParent(DOM_Node *node) +{ + DOM_Node *n, *cp; + + if (node == NULL || node->ownerDocument == NULL) { + return; + } + if (node->ownerDocument->u.Document.commonParent == NULL) { + node->ownerDocument->u.Document.commonParent = node; + return; + } + + cp = NULL; + for (n = node; n; n = n->parentNode) { + if (n == node->ownerDocument->u.Document.commonParent) { + return; + } else if (cp == NULL && n->subtreeModified == 1) { + cp = n; + } else { + n->subtreeModified = 1; + } + } + + node->ownerDocument->u.Document.commonParent = cp; +} +static void +_clearSubtreeModified(DOM_Document *doc) +{ + DOM_Node *n; + + for (n = doc->firstChild; n != NULL; n = n->nextSibling) { + if (n->subtreeModified) { + n->subtreeModified = 0; + _clearSubtreeModified(n); + } + } + doc->u.Document.commonParent = NULL; +} +void +DOM_MutationEvent_processSubtreeModified(DOM_Document *doc) +{ + DOM_Node *target; + DOM_MutationEvent evt; + + if (doc->u.Document.commonParent == NULL) { + return; + } + + target = doc->u.Document.commonParent; + _clearSubtreeModified(doc); + + DOM_MutationEvent_initMutationEvent(&evt, "DOMSubtreeModified", + 1, 0, NULL, NULL, NULL, NULL, 0); + DOM_EventTarget_dispatchEvent(target, &evt); +} diff --git a/src/dom.h b/src/dom.h new file mode 100644 index 0000000..b439d60 --- /dev/null +++ b/src/dom.h @@ -0,0 +1,526 @@ +/* DOMC Document Object Model library in C + * Copyright (c) 2001 Michael B. Allen + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* dom.h - internal interfaces + */ + +#ifndef DOM_H +#define DOM_H + + +#include +#include +#include +#include + +struct msgno_entry { + int msgno; + const char *msg; +}; + +const char *msgno_msg(int msgno); + +extern struct msgno_entry dom_codes[]; + +#if defined(__sparc__) + #include +#elif defined(_WIN32) + typedef unsigned __int64 uint64_t; +#else + #include +#endif + +/* Enable this for hashing and fast access to large child node lists */ +#define FAST_NODELIST 0 + +#if FAST_NODELIST +#include +#endif + +/* DOM_String + */ + +typedef char DOM_String; + +/* DOM_TimeStamp - Introduced in DOM Level 2 + */ + +typedef uint64_t DOM_TimeStamp; + +/* DOM_Exception + */ + +extern int *_DOM_Exception(void); + +#define DOM_Exception (*_DOM_Exception()) + +/* DOM_EventException - Introduced in DOM Level 2 + */ + +#define DOM_UNSPECIFIED_EVENT_TYPE_ERR dom_codes[13].msgno + +/* DOM_Node + */ + +typedef struct DOM_Node DOM_Node; +typedef struct DOM_NodeList DOM_NodeList; +typedef struct DOM_NodeList DOM_NamedNodeMap; +typedef struct NodeEntry NodeEntry; + +typedef DOM_Node DOM_Attr; +typedef DOM_Node DOM_Element; +typedef DOM_Node DOM_CharacterData; +typedef DOM_CharacterData DOM_Text; +typedef DOM_CharacterData DOM_Comment; +typedef DOM_Text DOM_CDATASection; +typedef DOM_Node DOM_DocumentType; +typedef DOM_Node DOM_Notation; +typedef DOM_Node DOM_Entity; +typedef DOM_Node DOM_EntityReference; +typedef DOM_Node DOM_ProcessingInstruction; +typedef DOM_Node DOM_DocumentFragment; +typedef DOM_Node DOM_Document; +typedef DOM_Document DOM_DocumentLS; +/* Introduced in DOM Level 2: */ +typedef DOM_Node DOM_EventTarget; +typedef struct ListenerEntry ListenerEntry; +typedef DOM_Document DOM_DocumentEvent; +typedef DOM_Document DOM_AbstractView; +typedef DOM_Document DOM_DocumentView; + +#define DOM_ELEMENT_NODE 1 +#define DOM_ATTRIBUTE_NODE 2 +#define DOM_TEXT_NODE 3 +#define DOM_CDATA_SECTION_NODE 4 +#define DOM_ENTITY_REFERENCE_NODE 5 +#define DOM_ENTITY_NODE 6 +#define DOM_PROCESSING_INSTRUCTION_NODE 7 +#define DOM_COMMENT_NODE 8 +#define DOM_DOCUMENT_NODE 9 +#define DOM_DOCUMENT_TYPE_NODE 10 +#define DOM_DOCUMENT_FRAGMENT_NODE 11 +#define DOM_NOTATION_NODE 12 + +/* events forward references - Introduced in DOM Level 2 + */ + +typedef struct DOM_Event DOM_Event; +typedef struct DOM_Event DOM_UIEvent; +typedef DOM_UIEvent DOM_TextEvent; +typedef struct DOM_Event DOM_MutationEvent; + +typedef void DOM_EventListener; +typedef void (*DOM_EventListener_handleEvent)(DOM_EventListener *this, DOM_Event *evt); + +struct ListenerEntry { + DOM_String *type; + DOM_EventListener *listener; + DOM_EventListener_handleEvent listener_fn; + int useCapture; +}; + +struct DOM_Node { + DOM_String *nodeName; + DOM_String *nodeValue; + unsigned short nodeType; + DOM_Node *parentNode; + DOM_NodeList *childNodes; + DOM_Node *firstChild; + DOM_Node *lastChild; + DOM_Node *previousSibling; + DOM_Node *nextSibling; + DOM_NamedNodeMap *attributes; + DOM_Document *ownerDocument; + /* Custom Fields */ + unsigned int listeners_len; + ListenerEntry **listeners; + unsigned short subtreeModified; + union { + struct { + DOM_DocumentType *doctype; + DOM_Element *documentElement; + DOM_DocumentView *document; + DOM_AbstractView *defaultView; + DOM_Node *commonParent; + DOM_String *version; + DOM_String *encoding; + int standalone; + } Document; + struct { + DOM_String *name; + DOM_NamedNodeMap *entities; + DOM_NamedNodeMap *notations; + DOM_String *publicId; + DOM_String *systemId; + DOM_String *internalSubset; + } DocumentType; + struct { + DOM_String *tagName; + } Element; + struct { + DOM_String *name; + int specified; + DOM_String *value; + DOM_Element *ownerElement; + } Attr; + struct { + DOM_String *data; + int length; + } CharacterData; + struct { + DOM_String *publicId; + DOM_String *systemId; + } Notation; + struct { + DOM_String *publicId; + DOM_String *systemId; + DOM_String *notationName; + } Entity; + struct { + DOM_String *target; + DOM_String *data; + } ProcessingInstruction; + } u; + unsigned int rtfxRefCount; /* Reference counting added for RTFX */ + void* userData; /* User data added for RTFX */ +}; + +DOM_Node *DOM_Node_insertBefore(DOM_Node *node, DOM_Node *newChild, DOM_Node *refChild); +DOM_Node *DOM_Node_replaceChild(DOM_Node *node, DOM_Node *newChild, DOM_Node *oldChild); +DOM_Node *DOM_Node_removeChild(DOM_Node *node, DOM_Node *oldChild); +DOM_Node *DOM_Node_appendChild(DOM_Node *node, DOM_Node *newChild); +int DOM_Node_hasChildNodes(const DOM_Node *node); +DOM_Node *DOM_Node_cloneNode(DOM_Node *node, int deep); +DOM_String *DOM_Node_getNodeValue(DOM_Node *node); +void DOM_Node_setNodeValue(DOM_Node *node, DOM_String *value); + +/* DOM_NodeList, DOM_NamedNodeMap + */ + +struct NodeEntry { + NodeEntry *prev; + NodeEntry *next; + DOM_Node *node; +}; +struct DOM_NodeList { + DOM_Document *_ownerDocument; + DOM_Element *_ownerElement; + int length; + NodeEntry *first; + NodeEntry *last; + unsigned short filter; + struct DOM_NodeList *list; /* Used for entities and notations */ +#if FAST_NODELIST + struct hashmap* _map; +#endif + unsigned int rtfxRefCount; /* Reference counting added for RTFX */ +}; + +DOM_Node *DOM_NodeList_item(const DOM_NodeList *nl, int index); + +DOM_Node *DOM_NamedNodeMap_getNamedItem(const DOM_NamedNodeMap *map, const DOM_String *name); +DOM_Node *DOM_NamedNodeMap_setNamedItem(DOM_NamedNodeMap *map, DOM_Node *arg); +DOM_Node *DOM_NamedNodeMap_removeNamedItem(DOM_NamedNodeMap *map, const DOM_String *name); +DOM_Node *DOM_NamedNodeMap_item(const DOM_NamedNodeMap *map, int index); + +/* DOM_Implementation + */ + +int DOM_Implementation_hasFeature(DOM_String *feature, DOM_String *version); +DOM_DocumentType *DOM_Implementation_createDocumentType(DOM_String *qualifiedName, + DOM_String *publicId, DOM_String *systemId); +DOM_Document *DOM_Implementation_createDocument(DOM_String *namespaceURI, + DOM_String *qualifiedName, DOM_DocumentType *doctype); + +/* DOM_Element + */ + +DOM_String *DOM_Element_getAttribute(const DOM_Element *element, const DOM_String *name); +void DOM_Element_setAttribute(DOM_Element *element, const DOM_String *name, + const DOM_String *value); +void DOM_Element_removeAttribute(DOM_Element *element, const DOM_String *name); +DOM_Attr *DOM_Element_getAttributeNode(const DOM_Element *element, const DOM_String *name); +DOM_Attr *DOM_Element_setAttributeNode(DOM_Element *element, DOM_Attr *newAttr); +DOM_Attr *DOM_Element_removeAttributeNode(DOM_Element *element, DOM_Attr *oldAttr); +DOM_NodeList *DOM_Element_getElementsByTagName(DOM_Element *element, const DOM_String *name); +void DOM_Element_normalize(DOM_Element *element); + +/* DOM_CharacterData + */ + +DOM_String *DOM_CharacterData_substringData(DOM_CharacterData *data, + int offset, int count); +void DOM_CharacterData_appendData(DOM_CharacterData *data, const DOM_String *arg); +void DOM_CharacterData_insertData(DOM_CharacterData *data, int offset, + const DOM_String *arg); +void DOM_CharacterData_deleteData(DOM_CharacterData *data, int offset, int count); +void DOM_CharacterData_replaceData(DOM_CharacterData *data, int offset, int count, + const DOM_String *arg); +int DOM_CharacterData_getLength(DOM_CharacterData *data); + +/* DOM_Text + */ + +DOM_Text *DOM_Text_splitText(DOM_Text *text, int offset); + +/* DOM_Document + */ + +DOM_Element *DOM_Document_createElement(DOM_Document *doc, const DOM_String *tagName); +DOM_DocumentFragment *DOM_Document_createDocumentFragment(DOM_Document *doc); +DOM_Text *DOM_Document_createTextNode(DOM_Document *doc, const DOM_String *data); +DOM_Comment *DOM_Document_createComment(DOM_Document *doc, const DOM_String *data); +DOM_CDATASection *DOM_Document_createCDATASection(DOM_Document *doc, const DOM_String *data); +DOM_ProcessingInstruction *DOM_Document_createProcessingInstruction(DOM_Document *doc, + const DOM_String *target, const DOM_String *data); +DOM_Attr *DOM_Document_createAttribute(DOM_Document *doc, const DOM_String *name); +DOM_EntityReference *DOM_Document_createEntityReference(DOM_Document *doc, + const DOM_String *name); +DOM_NodeList *DOM_Document_getElementsByTagName(DOM_Document *doc, const DOM_String *tagname); + +void DOM_Document_destroyNode(DOM_Document *doc, DOM_Node *node); +void DOM_Document_destroyNodeList(DOM_Document *doc, DOM_NodeList *nl, int free_nodes); + +DOM_DocumentType *DOM_Document_getDoctype(DOM_Document *doc); +DOM_Element *DOM_Document_getDocumentElement(DOM_Document *doc); + +/* DOM_DocumentLS - This does NOT resemble the Load/Save interfaces + * described in the latest W3C drafts at all. + */ + +int DOM_DocumentLS_save(DOM_DocumentLS *this, const char *uri, const DOM_Node *node); +int DOM_DocumentLS_fwrite(const DOM_DocumentLS *this, FILE *stream); + +/* Events - Introduced in DOM Level 2 + * http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html + */ + +/* DOM_Event - Introduced in DOM Level 2 + */ + +#define DOM_EVENT_CAPTURING_PHASE 1 +#define DOM_EVENT_AT_TARGET 2 +#define DOM_EVENT_BUBBLING_PHASE 3 + +struct DOM_Event { + const DOM_String *type; + DOM_EventTarget *target; + DOM_EventTarget *currentTarget; + unsigned short eventPhase; + int bubbles; + int cancelable; + DOM_TimeStamp timeStamp; +/* custom -- do not touch */ + int _pd; + int _sp; + unsigned int _modifiers; +/* UIEvent members */ + DOM_AbstractView *view; + long detail; +/* TextEvent members */ + DOM_String *outputString; + unsigned long keyVal; + unsigned long virtKeyVal; + int visibleOutputGenerated; + int numPad; +/* MutationEvent members */ + DOM_Node *relatedNode; + DOM_String *prevValue; + DOM_String *newValue; + DOM_String *attrName; + unsigned short attrChange; +}; + +void DOM_Event_stopPropagation(DOM_Event *evt); +void DOM_Event_preventDefault(DOM_Event *evt); +void DOM_Event_initEvent(DOM_Event *evt, const DOM_String *eventTypeArg, + int canBubbleArg, int cancelableArg); + +/* DOM_DocumentEvent - Introduced in DOM Level 2 + */ + +DOM_Event *DOM_DocumentEvent_createEvent(DOM_DocumentEvent *doc, + const DOM_String *eventType); +void DOM_DocumentEvent_destroyEvent(DOM_DocumentEvent *doc, DOM_Event *evt); + +/* DOM_UIEvent + */ + +void DOM_UIEvent_initUIEvent(DOM_UIEvent *evt, + const DOM_String *typeArg, + int canBubbleArg, + int cancelableArg, + DOM_AbstractView *viewArg, + long detailArg); + +/* DOM_EventTarget - Introduced in DOM Level 2 + */ + +void DOM_EventTarget_addEventListener(DOM_EventTarget *target, + const DOM_String *type, + DOM_EventListener *listener, + DOM_EventListener_handleEvent listener_fn, + int useCapture); +void DOM_EventTarget_removeEventListener(DOM_EventTarget *target, + const DOM_String *type, + DOM_EventListener *listener, + DOM_EventListener_handleEvent listener_fn, + int useCapture); +int DOM_EventTarget_dispatchEvent(DOM_EventTarget *target, DOM_Event *evt); + +/* DOM_TextEvent - Introduced in DOM Level 3 + * http://www.w3.org/TR/2002/WD-DOM-Level-3-Events-20020208/events.html + */ + +#define DOM_VK_UNDEFINED 0x0 +#define DOM_VK_RIGHT_ALT 0x01 +#define DOM_VK_LEFT_ALT 0x02 +#define DOM_VK_LEFT_CONTROL 0x03 +#define DOM_VK_RIGHT_CONTROL 0x04 +#define DOM_VK_LEFT_SHIFT 0x05 +#define DOM_VK_RIGHT_SHIFT 0x06 +#define DOM_VK_LEFT_META 0x07 +#define DOM_VK_RIGHT_META 0x08 +#define DOM_VK_CAPS_LOCK 0x09 +#define DOM_VK_DELETE 0x0A +#define DOM_VK_END 0x0B +#define DOM_VK_ENTER 0x0C +#define DOM_VK_ESCAPE 0x0D +#define DOM_VK_HOME 0x0E +#define DOM_VK_INSERT 0x0F +#define DOM_VK_NUM_LOCK 0x10 +#define DOM_VK_PAUSE 0x11 +#define DOM_VK_PRINTSCREEN 0x12 +#define DOM_VK_SCROLL_LOCK 0x13 +#define DOM_VK_LEFT 0x14 +#define DOM_VK_RIGHT 0x15 +#define DOM_VK_UP 0x16 +#define DOM_VK_DOWN 0x17 +#define DOM_VK_PAGE_DOWN 0x18 +#define DOM_VK_PAGE_UP 0x19 +#define DOM_VK_F1 0x1A +#define DOM_VK_F2 0x1B +#define DOM_VK_F3 0x1C +#define DOM_VK_F4 0x1D +#define DOM_VK_F5 0x1E +#define DOM_VK_F6 0x1F +#define DOM_VK_F7 0x20 +#define DOM_VK_F8 0x21 +#define DOM_VK_F9 0x22 +#define DOM_VK_F10 0x23 +#define DOM_VK_F11 0x24 +#define DOM_VK_F12 0x25 +#define DOM_VK_F13 0x26 +#define DOM_VK_F14 0x27 +#define DOM_VK_F15 0x28 +#define DOM_VK_F16 0x29 +#define DOM_VK_F17 0x2A +#define DOM_VK_F18 0x2B +#define DOM_VK_F19 0x2C +#define DOM_VK_F20 0x2D +#define DOM_VK_F21 0x2E +#define DOM_VK_F22 0x2F +#define DOM_VK_F23 0x30 +#define DOM_VK_F24 0x31 + +int DOM_TextEvent_checkModifier(DOM_TextEvent *evt, unsigned int modifier); +void DOM_TextEvent_initTextEvent(DOM_TextEvent *evt, const DOM_String *typeArg, + int canBubbleArg, int cancelableArg, + DOM_AbstractView *viewArg, long detailArg, + DOM_String *outputStringArg, + unsigned int keyValArg, + unsigned int virtKeyValArg, + int visibleOutputGeneratedArg, + int numPadArg); +void DOM_TextEvent_initModifier(DOM_TextEvent *evt, unsigned int modifier, int value); + +/* Useful X KeySym to keyVal and virtKeyVal conversion functions + * Add these .o's to the OBJS line in the Makefile to compile + */ + +unsigned int keysym2ucs(unsigned short keysym); +unsigned int keysym2domvk(unsigned short keysym); + +/* MutationEvent + */ + +#define DOM_MUTATION_EVENT_MODIFICATION 1 +#define DOM_MUTATION_EVENT_ADDITION 2 +#define DOM_MUTATION_EVENT_REMOVAL 3 + +void DOM_MutationEvent_initMutationEvent(DOM_MutationEvent *evt, + DOM_String *typeArg, + int canBubbleArg, + int cancelableArg, + DOM_Node *relatedNodeArg, + DOM_String *prevValueArg, + DOM_String *newValueArg, + DOM_String *attrNameArg, + unsigned short attrChangeArg); +void DOM_MutationEvent_processSubtreeModified(DOM_EventTarget *subtree); + +/* Temporary Functions + */ + +void DOM_Node_printNode(DOM_Node *node); +void DOM_Node_printNode2(DOM_Node *node); + +#define DOM_INDEX_SIZE_ERR dom_codes[0].msgno +#define DOM_DOMSTRING_SIZE_ERR dom_codes[1].msgno +#define DOM_HIERARCHY_REQUEST_ERR dom_codes[2].msgno +#define DOM_WRONG_DOCUMENT_ERR dom_codes[3].msgno +#define DOM_INVALID_CHARACTER_ERR dom_codes[4].msgno +#define DOM_NO_DATA_ALLOWED_ERR dom_codes[5].msgno +#define DOM_NO_MODIFICATION_ALLOWED_ERR dom_codes[6].msgno +#define DOM_NOT_FOUND_ERR dom_codes[7].msgno +#define DOM_NOT_SUPPORTED_ERR dom_codes[8].msgno +#define DOM_INUSE_ATTRIBUTE_ERR dom_codes[9].msgno +#define DOM_XML_PARSER_ERR dom_codes[10].msgno +#define DOM_CREATE_FAILED dom_codes[11].msgno +#define DOM_CHARACTER_ENC_ERR dom_codes[12].msgno +#define DOM_UNSPECIFIED_EVENT_TYPE_ERR dom_codes[13].msgno +#define DOM_FILTERED_LIST_ERR dom_codes[14].msgno + +#define CANNOT_HAVE_CHILD_OF(p, c) !(child_matrix[(p)->nodeType - 1] & \ + (1 << ((c)->nodeType - 1))) +#define MODIFYING_DOC_ELEM(p, c) ((p)->nodeType == DOM_DOCUMENT_NODE && \ + (c)->nodeType == DOM_ELEMENT_NODE) +#define MODIFYING_DOCTYPE_ELEM(p, c) ((p)->nodeType == DOM_DOCUMENT_NODE && \ + (c)->nodeType == DOM_DOCUMENT_TYPE_NODE) +#define INVALID_HIER_REQ(p, c) (CANNOT_HAVE_CHILD_OF(p, c) || \ + (MODIFYING_DOC_ELEM(p, c) && (p)->u.Document.documentElement)) + +extern unsigned short child_matrix[]; + +DOM_NodeList *Document_createNodeList(DOM_Document *doc); +DOM_Node *NodeList_itemFiltered(const DOM_NodeList *list, int index, unsigned short nodeType); +NodeEntry *NodeList_insert(DOM_NodeList *nl, DOM_Node *newChild, DOM_Node *refChild); +NodeEntry *NodeList_replace(DOM_NodeList *nl, DOM_Node *newChild, DOM_Node *oldChild); +NodeEntry *NodeList_remove(DOM_NodeList *nl, DOM_Node *oldChild); +NodeEntry *NodeList_append(DOM_NodeList *nl, DOM_Node *newChild); +int NodeList_exists(DOM_NodeList *nl, DOM_Node *child); + +DOM_NamedNodeMap *Document_createNamedNodeMap(DOM_Document *doc); + +#endif /* DOM_H */ diff --git a/src/domcxx.h b/src/domcxx.h index 747b63f..896b761 100644 --- a/src/domcxx.h +++ b/src/domcxx.h @@ -54,7 +54,6 @@ namespace DOM extern "C" { #define this _this - #include "domc.h" #include "dom.h" #undef this } diff --git a/src/domhelpers.h b/src/domhelpers.h index f042edd..65ab4e9 100644 --- a/src/domhelpers.h +++ b/src/domhelpers.h @@ -111,7 +111,7 @@ typedef std::stack NodeStack; * For iterating through the elements in a document. */ class ElementIterator - : public std::iterator + : public std::iterator { public: ElementIterator() diff --git a/src/usuals.h b/src/usuals.h index 4faff55..833ecda 100644 --- a/src/usuals.h +++ b/src/usuals.h @@ -54,6 +54,7 @@ #endif #include +#include #ifndef ASSERT #ifdef _DEBUG diff --git a/src/xmlfixups.cpp b/src/xmlfixups.cpp index 16b4b35..6ea8933 100644 --- a/src/xmlfixups.cpp +++ b/src/xmlfixups.cpp @@ -453,7 +453,7 @@ void XmlFixups::runPassTwo(const DOM::Document& doc) // Mark each node as we've seen it so we don't // do a given element twice - if((int)el.getUserData() == PASS_TWO) + if((int)(unsigned long)el.getUserData() == PASS_TWO) continue; el.setUserData((void*)PASS_TWO); -- cgit v1.2.3