📄 xmlnode.cpp
字号:
//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 + -