📄 xmlnode.cpp
字号:
case '+':
if(!p->m_nod) return E_XML_NO_TAG;
x = va_arg(ap,CXMLNode *);
if(!x) return E_XML_BAD_ARG;
if(child) p->appendChild(x);
else p->appendSibling(x);
p = x;
break;
case '*':
if(p->m_flags & XNF_FULL_NODE) return E_XML_PENDING_ATTRIB;
a = va_arg(ap,CXMLAttrib *);
if(!a) return E_XML_BAD_ARG;
p->appendAttrib(a);
break;
case '#':
if(!p->m_nod) return E_XML_NO_TAG;
s = va_arg(ap,const char *);
if(!s || !*s) return E_XML_BAD_ARG;
x = new CXMLNode;
if(!x) return E_OUTOF_MEMORY;
if((e=x->setNod(s))) return e;
x->m_flags = XNT_CDATA;
if(child) p->appendChild(x);
else p->appendSibling(x);
p = x;
break;
case '<':
if(!p->m_nod) return E_XML_NO_TAG;
if(fmt[1]=='/')
{
s = va_arg(ap,const char *);
if(!s || !*s) return E_XML_BAD_ARG;
len = strlen(s);
p = p->findOpenTag(s,len);
if(!p) return E_XML_BAD_TILE;
}
else
{
if((p->m_flags & XNF_INDEP_TAG) || p->m_type==XNT_META) child = false;
x = new CXMLNode;
if(!x) return E_OUTOF_MEMORY;
if(child) p->appendChild(x);
else p->appendSibling(x);
p = x;
}
break;
case ' ':
if(!p->m_nod) return E_XML_NO_TAG;
if(p->m_flags & XNF_FULL_NODE) return E_XML_PENDING_ATTRIB;
break;
case '/':
if(!p->m_nod) return E_XML_NO_TAG;
if(p->m_type!=XNT_TAG) return E_XML_CONFLICT_TYPES;
if(p->m_flags & (XNF_CLOSE_TAG|XNF_INDEP_TAG)) return E_XML_CONFLICT_FLAGS;
p->m_flags |= XNF_INDEP_TAG|XNF_FULL_NODE;
break;
case '>':
if(!p->m_nod) return E_XML_NO_TAG;
if(p->m_type!=XNT_TAG) return E_XML_CONFLICT_TYPES;
if(p->m_type==XNT_META || (p->m_flags & XNF_INDEP_TAG))
{
if(!p->m_parent) return E_XML_BAD_TILE;
p->m_flags |= XNF_FULL_NODE;
p = p->m_parent;
}
break;
case '!':
case '?':
if(p->m_flags || p->m_type==XNT_META) return E_XML_CONFLICT_TYPES;
if(p->m_flags & XNF_FULL_NODE) return E_XML_PENDING_ATTRIB;
p->m_flags = *fmt;
p->m_type = XNT_META;
break;
case 'c':
case 'd':
case 'l':
case 'n':
case 'p':
case 's':
case 'u':
case 'w':
case 'x':
if(p->m_flags & XNF_FULL_NODE) return E_XML_PENDING_ATTRIB;
if(p->m_nod) formatAttrib(p,fmt,ap);
else formatNod(xc,p,fmt,ap);
break;
default:return E_XML_BAD_FORMAT;
}
}
}
catch(...)
{
return E_ACCESS_VIOLATE;
}
return 0;
}
char* CXMLNode::toStr(char *p,CXMLCodec *xc) const
{
assert(m_nod && p);
//generate leading symbols
if(m_type==XNT_CDATA && m_parent->m_children==1){}//no leading space
else
{
unsigned bytes = m_depth * CXMLNode::m_indent; //leading spaces for nicer looking
for(;bytes;--bytes) *p++ = ' ';
}
if(m_type==XNT_TAG)
{
*p++ = '<'; //begin tag "<"
if(m_flags & XNF_CLOSE_TAG) *p++ = '/'; //close tag "/"
}
else if(m_type==XNT_META) //begin meta "<!", "<?"
{
*p++ = '<';
*p++ = (char)m_flags;
}
else if(m_type==XNT_COMMENT)//"<!--"
{
*p++ = '<';
*p++ = '!';
*p++ = '-';
*p++ = '-';
}
{//to reduce stack size
//generate tag
unsigned n = m_len;
if(m_type==XNT_CDATA && xc) n = xc->xstrSize(m_nod,m_len);
if(n==m_len)
{
memcpy(p,m_nod,m_len);
p += m_len;
}
else p = xc->xencode(m_nod,m_len,p);
}
//generate attribute list
if(m_attribs)
{
for(CXMLAttrib *a=m_head;a;a=a->getNext())
{
*p++ = ' ';//separator " "
p = a->toStr(p);
}
}
//generate ending symbols
if(m_type==XNT_META)//end meta "!>", "?>"
{
*p++ = (char)m_flags;
*p++ = '>';
}
else if(m_type==XNT_COMMENT)//"-->"
{
*p++ = '-';
*p++ = '-';
*p++ = '>';
}
else if(m_type==XNT_TAG)
{
if((m_flags & XNF_INDEP_TAG) || (!m_children && !(m_flags & XNF_CLOSE_TAG)))//end tag "/>"
{
*p++ = '/';
*p++ = '>';
}
else *p++ = '>';//end tag ">"
}
//generate children node list
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) *p++ = '\n';//"\n"
p = m_first->toStr(p,xc);
if(m_children==1 && m_first->m_type==XNT_CDATA){}//no line feed
else if(CXMLNode::m_indent) *p++ = '\n';//"\n"
//generate close tag
if(m_type==XNT_TAG && !(m_flags & XNF_INDEP_TAG))//close tag "</tag>"
{
if(m_first->m_type==XNT_CDATA && m_children==1){}//no leading space
else
{
unsigned bytes = m_depth * CXMLNode::m_indent; //leading spaces for nicer looking
for(;bytes;--bytes) *p++ = ' ';
}
*p++ = '<';
*p++ = '/';
memcpy(p,m_nod,m_len);
p += m_len;
*p++ = '>';
}
}
//generate next sibling
if(m_next)
{
if(CXMLNode::m_indent) *p++ = '\n';//line feed "\n" if pad leading space
p = m_next->toStr(p,xc);
}
return p;
}
CXMLNode* CXMLNode::load(CXMLNodeCache *xnc,const char*& b,const char *e,int *err,CXMLCodec *xc)
{
if(err) *err = E_OUTOF_MEMORY;
CXMLNode *x = xnc ? xnc->reuse() : new CXMLNode;
if(!x)
{
if(err && xnc && xnc->getAllocCount()>=xnc->getAllocLimit()) *err = E_BEYOND_LIMIT;
return 0;
}
int r = x->load(b,e,xc);
if(err) *err = r;
return x;
}
int CXMLNode::save(FILE *fp,CXMLCodec *xc) const
{
assert(m_nod && fp);
if(m_type==XNT_CDATA && m_parent->m_children==1){}//no leading space
else
{
unsigned bytes = m_depth * CXMLNode::m_indent; //leading spaces for nicer looking
for(;bytes;--bytes) if(fwrite(" ",1,1,fp)!=1) return E_XML_SAVE_WRITE;
}
if(m_type==XNT_TAG)//begin tag "<"
{
if(fwrite("<",1,1,fp)!=1) return E_XML_SAVE_WRITE;
if(m_flags & XNF_CLOSE_TAG)
{
if(fwrite("/",1,1,fp)!=1) return E_XML_SAVE_WRITE;
}
}
else if(m_type==XNT_META) //begin meta "<!", "<?"
{
if(fwrite("<",1,1,fp)!=1
|| fwrite(&m_flags,1,1,fp)!=1) return E_XML_SAVE_WRITE;
}
else if(m_type==XNT_COMMENT)//"<!--"
{
if(fwrite("<!--",1,4,fp)!=4) return E_XML_SAVE_WRITE;
}
{//to reduce stack size
unsigned n = m_len;
if(m_type==XNT_CDATA && xc) n = xc->xstrSize(m_nod,m_len);
if(n==m_len)
{
if(fwrite(m_nod,1,m_len,fp)!=m_len) return E_XML_SAVE_WRITE;
}
else
{
char *p = new char[n];
if(!p) return E_OUTOF_MEMORY;
xc->xencode(m_nod,m_len,p);
bool ok = fwrite(p,1,n,fp)==n;
delete [] p;
if(!ok) return E_XML_SAVE_WRITE;
}
}
if(m_attribs)
{
for(CXMLAttrib *a=m_head;a;a=a->getNext())
{
//separator " "
if(fwrite(" ",1,1,fp)!=1) return E_XML_SAVE_WRITE;
int e = a->save(fp);
if(e) return e;
}
}
//generate ending symbols
if(m_type==XNT_META)//end meta "!>", "?>"
{
if(fwrite(&m_flags,1,1,fp)!=1
|| fwrite(">",1,1,fp)!=1) return E_XML_SAVE_WRITE;
}
else if(m_type==XNT_COMMENT)//"-->"
{
if(fwrite("-->",1,3,fp)!=3) return E_XML_SAVE_WRITE;
}
else if(m_type==XNT_TAG)
{
if((m_flags & XNF_INDEP_TAG) || (!m_children && !(m_flags & XNF_CLOSE_TAG)))//end tag "/>"
{
if(fwrite("/>",1,2,fp)!=2) return E_XML_SAVE_WRITE;
}
else if(fwrite(">",1,1,fp)!=1) return E_XML_SAVE_WRITE;//end tag ">"
}
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) if(fwrite("\n",1,1,fp)!=1) return E_XML_SAVE_WRITE;//"\n"
int e = m_first->save(fp,xc);
if(e) return e;
if(m_children==1 && m_first->m_type==XNT_CDATA){}//no line feed
else if(CXMLNode::m_indent) if(fwrite("\n",1,1,fp)!=1) return E_XML_SAVE_WRITE;//"\n"
//generate close tag
if(m_type==XNT_TAG && !(m_flags & XNF_INDEP_TAG))//close tag "</tag>"
{
if(m_first->m_type==XNT_CDATA && m_children==1){}//no leading space
else
{
unsigned bytes = m_depth * CXMLNode::m_indent; //leading spaces for nicer looking
for(;bytes;--bytes) if(fwrite(" ",1,1,fp)!=1) return E_XML_SAVE_WRITE;
}
if(fwrite("</",1,2,fp)!=2
|| fwrite(m_nod,1,m_len,fp)!=m_len
|| fwrite(">",1,1,fp)!=1) return E_XML_SAVE_WRITE;
}
}
if(m_next)
{
if(CXMLNode::m_indent && fwrite("\n",1,1,fp)!=1) return E_XML_SAVE_WRITE;//line feed "\n" if pad leading space
int e = m_next->save(fp,xc);
if(e) return e;
}
return 0;
}
int CXMLNode::save(const char *path,CXMLCodec *xc,bool overwrite) const
{
if(!overwrite && !access(path,2)) return E_XML_FILE_EXIST;
FILE *fp = fopen(path,"wb");
if(!fp) return E_XML_SAVE_FILE;
int e = save(fp,xc);
fclose(fp);
return e;
}
int CXMLNode::loadCData(const char*& b,const char *e,CXMLCodec *xc)
{
//CData node has no child or attributes
if(m_children){m_first->free();m_first=m_last=0;}
if(m_attribs){m_head->free();m_head=m_tail=0;}
--e;
xmlSkipBlanksReverse(e);
unsigned len = e - b + 1;
assert(len);
m_flags = XNF_FULL_NODE;
m_type = XNT_CDATA;
int err = replaceNod(b,len,xc);
b = e + 1;
return err;
}
int CXMLNode::loadComment(const char*& b,const char *e)
{
assert(b[0]=='<' && b[1]=='!' && b[2]=='-' && b[3]=='-');
assert(e[0]=='-' && e[1]=='-' && e[2]=='>');
//CData node has no child or attributes
if(m_children){m_first->free();m_first=m_last=0;}
if(m_attribs){m_head->free();m_head=m_tail=0;}
const char *s = b + 4;
const char *t = e - 1;
xmlSkipBlanks(s);
xmlSkipBlanksReverse(t);
for(;!xmlIsBlank(*t) && t<=e;++t);
unsigned len = t - s;
if(t<=s) return E_XML_EMPTY_COMMENT;
m_flags = XNF_FULL_NODE;
m_type = XNT_COMMENT;
int err = replaceNod(s,len,0);
b = e;
return err;
}
int CXMLNode::loadTag(const char*& b,const char *e)
{
assert(b && e && *b=='<' && *e=='>');
const char *s = b + 1;
const char *t = e - 1;
m_type = XNT_TAG;
m_flags = 0;
xmlSkipBlanks(s);
xmlSkipBlanksReverse(t);
if(*s=='/')
{
if(*t=='/') return E_XML_BAD_CLOSE;
++s;
m_flags |= XNF_CLOSE_TAG;
}
else if((unsigned char)(*s)<0x80 && *s!='_' && !isalnum(*s))
{
assert(!(m_flags & XNF_CLOSE_TAG));
if(*s!=*t) return E_XML_BAD_META;
m_type = XNT_META;
m_flags = *s;
++s;
--t;
}
if(s>t) return E_XML_NO_TAG;
b = s;
xmlSkipSymbol(s);
int err = replaceNod(b,s-b,0);
if(err) return err;
xmlSkipBlanks(s);
b = s;
if(s>t) return 0;
if(m_type!=XNT_META && (m_flags & XNF_CLOSE_TAG)) return E_XML_CLOSETAG_ATTRIB;//close tag with attributes is not allowed
CXMLAttrib *a;
CXMLAttribCache *xac = 0;
if(m_xnc) xac = &m_xnc->getAttribCache();
for(;s<=t;)
{
xmlSkipBlanks(s);
b = s;
if(s>t) break;
if(*s=='/')
{
++s;
xmlSkipBlanks(s);
if(*s!='>' || s<=t) return E_XML_BAD_SLASH;
m_flags |= XNF_INDEP_TAG|XNF_FULL_NODE;
b = s;
break;
}
if(xac)
{
if(!(a=xac->reuse()))
{
if(xac->getAllocLimit() && xac->getAllocCount()>=xac->getAllocLimit()) return E_BEYOND_LIMIT;
else return E_OUTOF_MEMORY;
}
}
else
{
if(!(a=new CXMLAttrib)) return E_OUTOF_MEMORY;
}
err = a->load(s,t);
if(err==E_XML_META_ATTRIB && m_type==XNT_META) err = 0;
if(err){a->free();return err;}
appendAttrib(a);
b = s;
}
return 0;
}
int CXMLNode::load(const char*& b,const char *e,CXMLCodec *xc)
{
if(b[0]=='<')
{
if(b[1]=='!' && b[2]=='-' && b[3]=='-') return CXMLNode::loadComment(b,e);
else return CXMLNode::loadTag(b,e);
}
else return CXMLNode::loadCData(b,e,xc);
}
int CXMLNode::findClosePos(const char*& p,const char **r)
{
assert(p && r);
*r = 0;
const char *t = p;
int e = 0;
if(t[0]=='<' && t[1]=='!' && t[2]=='-' && t[3]=='-')
{
p = t;
t = strstr(t+1,"-->");
if(t) *r = t;
return 0;
}
xmlSkipBlanks(p);
if(!*p) return 0;
if(*p=='<')
{
t = p;
for(;*t;)
{
if(*t=='/')
{
++t;
xmlSkipBlanks(t);
if(!*t) return 0;
xmlSkipSymbol(t);
xmlSkipBlanks(t);
if(!*t) return 0;
if(*t!='>') return E_XML_BAD_SLASH;
}
if(*t=='<' || *t=='>')
{
if(t!=p){*r=t;return 0;}
else ++t;
}
xmlSkipAttribName(t);
xmlSkipBlanks(t);
if(!*t) return 0;
if(*t=='=')
{
++t;
if((e=CXMLAttrib::skipValue(t,(char *)-1))!=0) return e;
xmlSkipBlanks(t);
if(!*t) return 0;
}
}
}
else
{
t = strchr(p+1,'<');
if(t) *r = t;
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -