// Copyright (c) 2002 David Muse
// See the COPYING file for more information
#include <rudiments/xmldom.h>
#include <rudiments/charstring.h>
#include <rudiments/linkedlist.h>
#include <stdlib.h>
#ifdef RUDIMENTS_NAMESPACE
namespace rudiments {
#endif
class xmldomprivate {
friend class xmldom;
private:
xmldomnode *_nullnode;
xmldomnode *_rootnode;
xmldomnode *_currentparent;
xmldomnode *_currentattribute;
stringlist _strlist;
linkedlist<unsigned long> _refcountlist;
};
xmldom::xmldom() : xmlsax() {
pvt=new xmldomprivate;
pvt->_nullnode=xmldomnode::createNullNode(this);
pvt->_rootnode=pvt->_nullnode;
pvt->_currentparent=NULL;
pvt->_currentattribute=NULL;
}
xmldom::~xmldom() {
if (!pvt->_rootnode->isNullNode()) {
delete pvt->_rootnode;
}
delete pvt->_nullnode;
for (stringlistnode *node=pvt->_strlist.getNodeByIndex(0);
node; node=node->getNext()) {
delete[] node->getData();
}
delete pvt;
}
bool xmldom::parseFile(const char *filename) {
reset();
return xmlsax::parseFile(filename);
}
bool xmldom::parseString(const char *string) {
reset();
return xmlsax::parseString(string);
}
void xmldom::reset() {
if (!pvt->_rootnode->isNullNode()) {
pvt->_rootnode->cascadeOnDelete();
delete pvt->_rootnode;
pvt->_rootnode=pvt->_nullnode;
}
pvt->_currentparent=NULL;
pvt->_currentattribute=NULL;
}
bool xmldom::writeFile(const char *filename, mode_t perms) const {
file fl;
if (!fl.open(filename,O_WRONLY|O_CREAT|O_TRUNC,perms)) {
return false;
}
stringbuffer *xml=pvt->_rootnode->xml();
bool retval=true;
int length=charstring::length(xml->getString());
if (fl.write(xml->getString(),length)!=length) {
retval=false;
}
if (!fl.close()) {
retval=false;
}
return retval;
}
void xmldom::createRootNode() {
pvt->_rootnode=new xmldomnode(this,pvt->_nullnode);
pvt->_rootnode->setName("document");
pvt->_rootnode->setType(ROOT_XMLDOMNODETYPE);
pvt->_currentparent=pvt->_rootnode;
}
xmldomnode *xmldom::getRootNode() const {
return (pvt->_rootnode)?pvt->_rootnode:pvt->_nullnode;
}
bool xmldom::tagStart(const char *name) {
pvt->_currentattribute=NULL;
if (pvt->_rootnode->isNullNode()) {
createRootNode();
}
xmldomnode *tagnode=new xmldomnode(this,pvt->_nullnode);
tagnode->setName(name);
tagnode->setType(TAG_XMLDOMNODETYPE);
pvt->_currentparent->insertChild(tagnode,
pvt->_currentparent->getChildCount());
pvt->_currentparent=tagnode;
return true;
}
bool xmldom::attributeName(const char *name) {
pvt->_currentattribute=new xmldomnode(this,pvt->_nullnode);
pvt->_currentattribute->setName(name);
pvt->_currentattribute->setType(ATTRIBUTE_XMLDOMNODETYPE);
pvt->_currentparent->insertAttribute(pvt->_currentattribute,
pvt->_currentparent->getAttributeCount());
return true;
}
bool xmldom::attributeValue(const char *value) {
if (!pvt->_currentattribute) {
if (!attributeName(value)) {
return false;
}
}
pvt->_currentattribute->setValue(value);
pvt->_currentattribute=NULL;
return true;
}
bool xmldom::text(const char *string) {
pvt->_currentattribute=NULL;
xmldomnode *textnode=new xmldomnode(this,pvt->_nullnode);
textnode->setName("text");
textnode->setValue(string);
textnode->setType(TEXT_XMLDOMNODETYPE);
pvt->_currentparent->insertChild(textnode,
pvt->_currentparent->getChildCount());
return true;
}
bool xmldom::tagEnd(const char *name) {
pvt->_currentattribute=NULL;
pvt->_currentparent=pvt->_currentparent->getParent();
return true;
}
bool xmldom::comment(const char *string) {
pvt->_currentattribute=NULL;
xmldomnode *commentnode=new xmldomnode(this,pvt->_nullnode);
commentnode->setName("comment");
commentnode->setValue(string);
commentnode->setType(COMMENT_XMLDOMNODETYPE);
pvt->_currentparent->insertChild(commentnode,
pvt->_currentparent->getChildCount());
return true;
}
bool xmldom::cdata(const char *string) {
pvt->_currentattribute=NULL;
xmldomnode *cdatanode=new xmldomnode(this,pvt->_nullnode);
cdatanode->setName("cdata");
cdatanode->setValue(string);
cdatanode->setType(CDATA_XMLDOMNODETYPE);
pvt->_currentparent->insertChild(cdatanode,
pvt->_currentparent->getChildCount());
return true;
}
const char *xmldom::cacheString(const char *string) {
if (!string) {
return NULL;
}
unsigned long index=0;
for (stringlistnode *node=pvt->_strlist.getNodeByIndex(0);
node; node=node->getNext()) {
const char *data=node->getData();
if (!charstring::compare(string,data)) {
linkedlistnode<unsigned long> *refnode=
pvt->_refcountlist.getNodeByIndex(index);
refnode->setData(refnode->getData()+1);
return data;
}
index++;
}
char *copy=charstring::duplicate(string);
pvt->_strlist.append(copy);
pvt->_refcountlist.append(1);
return copy;
}
void xmldom::unCacheString(const char *string) {
if (!string) {
return;
}
unsigned long index=0;
for (stringlistnode *node=pvt->_strlist.getNodeByIndex(0);
node; node=node->getNext()) {
char *data=node->getData();
if (!charstring::compare(string,data)) {
linkedlistnode<unsigned long> *refnode=
pvt->_refcountlist.getNodeByIndex(index);
refnode->setData(refnode->getData()-1);
if (refnode->getData()<=0) {
pvt->_refcountlist.removeByIndex(index);
pvt->_strlist.removeByIndex(index);
delete[] data;
return;
}
}
index++;
}
}
#ifdef RUDIMENTS_NAMESPACE
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1