⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmlnode.cpp

📁 可移植的xml库。已经在windows和linux上测试通过。只使用C++ Runtine
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//xmlnode.cpp

#include "xml.h"

unsigned CXMLNode::m_indent = 1;

CXMLNode::CXMLNode()
{
	reset();
}

CXMLNode::CXMLNode(const CXMLNode& x)
{
	reset();
	if(clone(x)) assert(false);
}

CXMLNode::CXMLNode(CXMLCodec *xc,const char *nod,...)
{
	reset();
	va_list ap;
	va_start(ap,nod);
	if(build(xc,nod,ap)) assert(false);
	va_end(ap);
}

CXMLNode::CXMLNode(CXMLCodec *xc,const char *nod,va_list ap)
{
	reset();
	if(build(xc,nod,ap)) assert(false);
}

CXMLNode::CXMLNode(const char *nod,CXMLAttrib& a)
{
	reset();
	if(setNod(nod,0)) assert(false);
	appendAttrib(&a);
}

CXMLNode::CXMLNode(CXMLCodec *xc,const char *nod,unsigned flags)
{
	reset();
	if(setNod(nod)) assert(false);
	m_flags = flags;
}

CXMLNode::CXMLNode(CXMLCodec *xc,const char *nod,const char *fmt,...)
{
	reset();
	va_list ap;
	va_start(ap,nod);
	if(build(xc,nod,fmt,ap)) assert(false);
	va_end(ap);
}

CXMLNode::CXMLNode(CXMLCodec *xc,const char *nod,const char *fmt,va_list ap)
{
	reset();
	if(build(xc,nod,fmt,ap)) assert(false);
}

CXMLNode::~CXMLNode()
{
	clean();
}

void CXMLNode::clean()
{
	if(m_nod) delete [] m_nod;
	if(m_attribs) delete m_head;
	if(m_next) delete m_next;
	reset();
}

void CXMLNode::free()
{
	if(m_xnc) m_xnc->saveup(this);
	else delete this;
}

bool CXMLNode::isUnder(const CXMLNode& x) const
{
	for(const CXMLNode *p=this;0!=(p=p->m_parent);) if(p==&x) return true;
	return false;
}

bool CXMLNode::isSameTo(const CXMLNode& x) const
{
	if(this==&x) return true;
	if(m_len!=x.m_len
		|| m_type!=x.m_type
		|| m_flags!=x.m_flags
		|| m_children!=x.m_children
		|| m_attribs!=x.m_attribs
		|| (!m_next)!=(!x.m_next)
		|| strcmpi(m_nod,x.m_nod)!=0) return false;
	CXMLAttrib *a,*b=0;
	for(a=m_head,b=x.m_head;a;a=a->getNext(),b=b->getNext())
	{
		if(!a->isSameTo(*b)) return false;
	}
	if(m_next && !m_next->isSameTo(*x.m_next)) return false;
	if(m_first && !m_first->isSameTo(*x.m_first)) return false;
	return true;
}

bool CXMLNode::isSameToExact(const CXMLNode& x) const
{
	if(this==&x) return true;
	if(m_len!=x.m_len
		|| m_type!=x.m_type
		|| m_flags!=x.m_flags
		|| m_children!=x.m_children
		|| m_attribs!=x.m_attribs
		|| (!m_next)!=(!x.m_next)
		|| strcmp(m_nod,x.m_nod)!=0) return false;
	else//for reduce stack size
	{
		CXMLAttrib *a,*b=0;
		for(a=m_head,b=x.m_head;a;a=a->getNext(),b=b->getNext())
		{
			if(!a->isSameToExact(*b)) return false;
		}
	}
	if(m_next && !m_next->isSameToExact(*x.m_next)) return false;
	if(m_first && !m_first->isSameToExact(*x.m_first)) return false;
	return true;
}

CXMLNode* CXMLNode::getRoot() const
{
	const CXMLNode *p = this;
	for(;p->m_parent;p=p->m_parent);
	for(;p->m_prev;p=p->m_prev);
	return (CXMLNode *)p;
}

unsigned CXMLNode::getIndex() const
{
	unsigned idx = 0;
	const CXMLNode *p = this;
	for(;p->m_prev;p=p->m_prev,++idx);
	return idx;
}

unsigned CXMLNode::getSiblings() const
{
	if(m_prev)
	{
		const CXMLNode *p = this;
		for(;p->m_prev;p=p->m_prev);
		return p->getSiblings();
	}
	unsigned n = 1;
	for(const CXMLNode *p=this;p->m_next;p=p->m_next,++n);
	return n;
}

CXMLNode* CXMLNode::getLastSibling() const
{
	const CXMLNode *p = this;
	for(;p->m_next;p=p->m_next);
	return (CXMLNode *)p;
}

CXMLNode* CXMLNode::getFirstSibling() const
{
	const CXMLNode *p = this;
	for(;p->m_prev;p=p->m_prev);
	return (CXMLNode *)p;
}

CXMLNode* CXMLNode::getChildAt(unsigned idx) const
{
	CXMLNode *p = m_first;
	for(;idx>0 && p;--idx,p=p->m_next);
	return p;
}

CXMLNode* CXMLNode::getSiblingAt(unsigned idx) const
{
	if(m_prev)
	{
		unsigned n = idx;
		const CXMLNode *p = this;
		for(;p->m_prev;p=p->m_prev,--n);
		return n==0 ? (CXMLNode *)this : p->getSiblingAt(idx);
	}
	const CXMLNode *p = this;
	for(;idx>0 && p;--idx,p=p->m_next);
	return (CXMLNode *)p;
}

CXMLAttrib* CXMLNode::getAttribAt(unsigned idx) const
{
	CXMLAttrib *a = m_head;
	for(;idx>0 && a;a=a->getNext());
	return a;
}

unsigned CXMLNode::strBytes() const
{
	unsigned bytes = m_len;
	if(m_type==XNT_CDATA && m_parent->m_children==1){}//no leading space
	else bytes += m_depth * CXMLNode::m_indent;		//leading spaces for nicer looking
	if(m_type==XNT_TAG) ++bytes;			//begin tag "<"
	else if(m_type==XNT_META) bytes += 2;	//begin meta "<!", "<?"
	else if(m_type==XNT_COMMENT) bytes += 4;//"<!--"
	if(m_attribs)
	{
		for(CXMLAttrib *a=m_head;a;a=a->getNext())
		{
			++bytes;//seperator " "
			bytes += a->strBytes();
		}
	}
	if(m_type==XNT_META)
	{
		bytes += 2;	//end meta "!>", "?>"
	}
	else if(m_type==XNT_COMMENT) bytes += 3;//"-->"
	else if(m_type!=XNT_CDATA) ++bytes;//end tag ">"
	if((!m_children && !(m_flags & XNF_INDEP_TAG)) || (m_children==1 && m_first->m_type==XNT_CDATA)){}//no line feed
	else if(CXMLNode::m_indent) ++bytes;//line feed "\n" if pad leading space
	if(m_children)
	{
		assert(m_type!=XNT_META && m_type!=XNT_CDATA && m_type!=XNT_COMMENT);
		assert(!(m_flags & XNF_INDEP_TAG));
		if(m_children==1 && m_first->m_type==XNT_CDATA){}//no line feed
		else if(CXMLNode::m_indent) ++bytes;//"\n"
		bytes += m_first->strBytes();
		if(m_type==XNT_TAG && !(m_flags & XNF_INDEP_TAG))
		{
			bytes += 2 + m_len + 1;//close tag "</tag>"
		}
	}
	else if(m_type==XNT_TAG)
	{
		if(m_flags & XNF_INDEP_TAG) ++bytes;//"/>"
		++bytes;	//close tag ">"
	}
	if(m_next)
	{
		if(CXMLNode::m_indent) ++bytes;//line feed "\n" if pad leading space
		bytes += m_next->strBytes();
	}
	return bytes;
}

unsigned CXMLNode::blockBytes() const
{
	assert(m_nod);
	unsigned bytes = m_len + 1;//consumed memory bytes(include '\0')
	for(CXMLAttrib *a=m_head;a;a=a->getNext()) bytes += a->blockBytes();
	bytes += sizeof(*this);
	if(m_first) bytes += m_first->blockBytes();
	if(m_next) bytes += m_next->blockBytes();
	return bytes;
}

unsigned CXMLNode::getIndent()
{
	return CXMLNode::m_indent;
}

int CXMLNode::clone(const CXMLNode& x)
{
	int err = setNod(x.m_nod);
	if(err) return err;
	else//for reduce stack size
	{
		m_type = x.m_type;
		m_flags = x.m_flags;
		CXMLAttrib *a = m_head;
		CXMLAttrib *b = x.m_head;
		for(;a && b;a=a->getNext(),b=b->getNext()) if((err=a->clone(*b))) return err;
		for(;b;b=b->getNext())
		{
			a = new CXMLAttrib;
			if(!a) return E_OUTOF_MEMORY;
			if((err=a->clone(*b))) return err;
			appendAttrib(a);
		}
	}
	if(m_first)
	{
		if(x.m_first)
		{
			if((err=m_first->clone(*x.m_first))) return err;
		}
		else
		{
			m_first->free();
			m_first = 0;
		}
	}
	if(m_next)
	{
		if(x.m_next)
		{
			if((err=m_next->clone(*x.m_next))) return err;
		}
		else
		{
			m_next->free();
			m_next = 0;
		}
	}
	return 0;
}

int CXMLNode::replaceNod(const char *nod,unsigned len,CXMLCodec *xc)
{
	if(len)
	{
		unsigned n = len;
		if(m_type==XNT_CDATA && xc) n = xc->xrawSize(nod,len);
		if(n>=m_bs)
		{
			m_len = m_bs = 0;
			if(m_nod) delete [] m_nod;
			m_nod = new char[n+1];
			if(!m_nod) return E_OUTOF_MEMORY;
			m_bs = n + 1;
		}
		if(n==len) memcpy(m_nod,nod,len);
		else xc->xdecode(nod,len,m_nod);
		m_nod[n] = 0;
		m_len = n;
	}
	else if(m_nod)
	{
		delete [] m_nod;
		m_nod = 0;
		m_len = m_bs = 0;
	}
	return 0;
}

int CXMLNode::setNod(const char *nod,CXMLCodec *xc)
{
	assert(nod && *nod);
	size_t len = strlen(nod);
	assert(len);
	return replaceNod(nod,len,xc);
}

unsigned CXMLNode::updateParent(CXMLNode *p)
{
	assert(p && !p->m_parent && !p->m_prev);
	unsigned n = 0;
	for(CXMLNode *x=this;x;x=x->m_next,++n) x->m_parent = p;
	return n;
}

void CXMLNode::appendChild(CXMLNode *p)
{
	assert(p && !p->m_parent && !p->m_prev);
	if(!m_first)
	{
		assert(!m_last);
		m_first = m_last = p;
	}
	else
	{
		p->m_prev = m_last;
		m_last->m_next = p;
		m_last = p;
	}
	if(!p->m_next)
	{
		++m_children;
		p->m_parent = this;
	}
	else
	{
		m_children += p->updateParent(this);
		m_last = p->getLastSibling();
	}
}

void CXMLNode::preppendChild(CXMLNode *p)
{
	if(!m_first)
	{
		assert(!m_last);
		appendChild(p);
		return;
	}
	assert(p && !p->m_parent && !p->m_prev);
	if(!p->m_next)
	{
		p->m_next = m_first;
		m_first->m_prev = p;
		m_first = p;
		++m_children;
		p->m_parent = this;
	}
	else
	{
		m_children += p->updateParent(this);
		CXMLNode *x = p->getLastSibling();
		x->m_next = m_first;
		m_first->m_prev = x;
		m_first = p;
	}
}

void CXMLNode::insertChild(CXMLNode *p,unsigned ref,bool ahead)
{
	assert(ref<m_children);
	insertChild(p,getChildAt(ref),ahead);
}

void CXMLNode::insertChild(CXMLNode *p,CXMLNode *ref,bool ahead)
{
	assert(ref && ref->isChildOf(*this));
	assert(p && !p->m_parent && !p->m_prev);
	CXMLNode *x = p;
	if(p->m_next)
	{
		m_children += p->updateParent(this);
		x = p->getLastSibling();
	}
	else
	{
		++m_children;
		p->m_parent = this;
	}
	if(ahead)
	{
		if(ref->m_prev){p->m_prev=ref->m_prev;p->m_prev->m_next=p;}
		else m_first = p;
		x->m_next = ref;
		ref->m_prev = x;
	}
	else
	{
		if(ref->m_next){x->m_next=ref->m_next;x->m_next->m_prev=x;}
		else m_last = x;
		p->m_prev = ref;
		ref->m_next = p;
	}
}

void CXMLNode::appendSibling(CXMLNode *p)
{
	if(m_parent)
	{
		m_parent->appendChild(p);
		return;
	}
	if(m_next)
	{
		getLastSibling()->appendSibling(p);
		return;
	}
	assert(p && !p->m_parent && !p->m_prev);
	if(p->m_next)
	{
		p->updateParent(0);
		if(m_next)
		{
			CXMLNode *x = p->getLastSibling();
			x->m_next = m_next;
			m_next->m_prev = x;
		}
	}
	else if(m_next){p->m_next=m_next;m_next->m_prev=p;}
	m_next = p;
	p->m_prev = this;
}

void CXMLNode::preppendSibling(CXMLNode *p)
{
	if(m_parent)
	{
		m_parent->preppendChild(p);
		return;
	}
	if(m_prev)
	{
		getFirstSibling()->preppendSibling(p);
		return;
	}
	assert(p && !p->m_parent && !p->m_prev);
	if(p->m_next)
	{
		p->updateParent(0);
		if(m_prev){p->m_prev=m_prev;p->m_prev->m_next=p;}
		p = p->getLastSibling();
	}
	else if(m_prev){p->m_prev=m_prev;p->m_prev->m_next=p;}
	m_prev = p;
	p->m_next = this;
}

void CXMLNode::insertSibling(CXMLNode *p,int off,bool ahead)
{
	if(!off)
	{
		insertSibling(p,ahead);
		return;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -