www.pudn.com > simplec++codeforp2p.rar > xml.cpp


// ------------------------------------------------ 
// File : xml.cpp 
// Date: 4-apr-2002 
// Author: giles 
// Desc:  
//		Basic XML parsing/creation  
// 
// (c) 2002 peercast.org 
// ------------------------------------------------ 
// This program is free software; you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation; either version 2 of the License, or 
// (at your option) any later version. 
 
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more details. 
// ------------------------------------------------ 
 
#include "xml.h" 
#include "stream.h" 
#include  
#include  
 
// ---------------------------------- 
void XML::Node::add(Node *n) 
{ 
	if (!n) 
		return; 
 
	n->parent = this; 
 
    if (child) 
    { 
    	// has children, add to last sibling 
        Node *s = child; 
        while (s->sibling) 
        	s = s->sibling; 
        s->sibling = n; 
 
    }else{ 
    	// no children yet 
        child = n; 
    } 
} 
// --------------------------------- 
inline char nibsToByte(char n1, char n2) 
{ 
	if (n1 >= 'A') n1 = n1-'A'+10; 
	else n1 = n1-'0'; 
	if (n2 >= 'A') n2 = n2-'A'+10; 
	else n2 = n2-'0'; 
 
    return ((n2&0xf)<<4)|(n1&0xf); 
} 
 
// ---------------------------------- 
int XML::Node::getBinaryContent(void *ptr, int size) 
{ 
	char *in = contData; 
    char *out = (char *)ptr; 
 
    int i=0; 
    while (*in) 
    { 
    	if (isWhiteSpace(*in)) 
        { 
        	in++; 
        }else 
        { 
        	if (i >= size) 
            	throw StreamException("Too much binary data"); 
	    	out[i++] = nibsToByte(in[0],in[1]); 
	        in+=2; 
        } 
    } 
    return i; 
} 
// ---------------------------------- 
void XML::Node::setBinaryContent(void *ptr, int size) 
{ 
	const char hexTable[] = "0123456789ABCDEF"; 
    const int lineWidth = 1023; 
 
	contData = new char[size*2+1+(size/lineWidth)]; 
 
    char *bp = (char *)ptr; 
    register char *ap = contData; 
 
    for(register int i=0; i>4)&0xf]; 
        if ((i&lineWidth)==lineWidth) 
	    	*ap++ = '\n'; 
    } 
    ap[0] = 0; 
} 
 
 
// ---------------------------------- 
void XML::Node::setContent(const char *n) 
{ 
	contData = strdup(n); 
} 
// ---------------------------------- 
void XML::Node::setAttributes(const char *n) 
{ 
    char c; 
 
	attrData = strdup(n); 
 
    // count maximum amount of attributes 
    int maxAttr = 1;		// 1 for tag name 
    bool inQ = false; 
    int i=0; 
    while ((c=attrData[i++])!=0) 
    { 
    	if (c=='\"') 
			inQ ^= true; 
 
		if (!inQ) 
			if (c=='=') 
				maxAttr++; 
    } 
 
 
    attr = new Attribute[maxAttr]; 
 
    attr[0].namePos = 0; 
    attr[0].valuePos = 0; 
 
    numAttr=1; 
 
    i=0; 
 
    // skip until whitespace 
    while (c=attrData[i++]) 
    	if (isWhiteSpace(c)) 
        	break; 
 
    if (!c) return;	// no values 
 
    attrData[i-1]=0; 
 
 
    while ((c=attrData[i])!=0) 
    { 
    	if (!isWhiteSpace(c)) 
        { 
			if (numAttr>=maxAttr) 
				throw StreamException("Too many attributes"); 
 
			// get start of tag name 
        	attr[numAttr].namePos = i; 
 
 
			// skip whitespaces until next '=' 
			// terminate name on next whitespace or '=' 
            while (attrData[i]) 
			{ 
				c = attrData[i++]; 
 
				if ((c == '=') || isWhiteSpace(c)) 
				{ 
					attrData[i-1] = 0;	// null term. name 
					if (c == '=') 
                		break; 
				} 
			} 
 
			// skip whitespaces 
            while (attrData[i]) 
			{ 
	            if (isWhiteSpace(attrData[i])) 
					i++; 
				else 
					break; 
			} 
 
			// check for valid start of attribute value - '"' 
			if (attrData[i++] != '\"') 
            	throw StreamException("Bad tag value"); 
 
            attr[numAttr++].valuePos = i; 
 
			// terminate attribute value at next '"' 
 
            while (attrData[i]) 
				if (attrData[i++] == '\"') 
                	break; 
 
			attrData[i-1] = 0;	// null term. value 
 
 
        }else{ 
	        i++; 
    	} 
    } 
} 
// ---------------------------------- 
XML::Node::Node(const char *fmt,...) 
{ 
	va_list ap; 
  	va_start(ap, fmt); 
 
	char tmp[8192]; 
	vsprintf(tmp,fmt,ap); 
	setAttributes(tmp); 
 
   	va_end(ap);	 
	init(); 
} 
 
// ---------------------------------- 
void XML::Node::init() 
{ 
    parent = sibling = child = NULL; 
    contData = NULL; 
    userPtr = NULL; 
}	 
// ---------------------------------- 
int XML::Node::findAttrInt(const char *name) 
{ 
	char *v = findAttr(name); 
    if (!v) return 0; 
    return atoi(v); 
} 
// ---------------------------------- 
int XML::Node::findAttrID(const char *name) 
{ 
	char *v = findAttr(name); 
    if (!v) return 0; 
    return strToID(v); 
} 
// ---------------------------------- 
char *XML::Node::findAttr(const char *name) 
{ 
	int nlen = strlen(name); 
	for(int i=1; i\n",3); 
	}else 
	{ 
	    out.write(">\n",2); 
 
	    if (contData) 
		    out.write(contData,strlen(contData)); 
 
		if (child) 
	    	child->write(out,level+1); 
#if 0 
	    if (level) 
		    out.write(tabs,strlen(tabs)); 
#endif 
	    out.write("\n",2); 
	} 
 
    if (sibling) 
    	sibling->write(out,level); 
} 
// ---------------------------------- 
XML::Node::~Node() 
{ 
//	LOG("delete %s",getName()); 
 
	if (contData) 
    	delete [] contData; 
    if (attrData) 
    	delete [] attrData; 
    if (attr) 
    	delete [] attr; 
 
    Node *n = child; 
    while (n) 
    { 
    	Node *nn = n->sibling; 
    	delete n; 
    	n = nn; 
    } 
} 
 
 
// ---------------------------------- 
XML::~XML() 
{ 
	if (root) 
    	delete root; 
} 
 
// ---------------------------------- 
void XML::write(Stream &out) 
{ 
	if (!root) 
    	throw StreamException("No XML root"); 
 
	out.writeLine(""); 
    root->write(out,1); 
 
} 
// ---------------------------------- 
void XML::writeCompact(Stream &out) 
{ 
	if (!root) 
    	throw StreamException("No XML root"); 
 
	out.writeLine(""); 
    root->write(out,1); 
 
} 
// ---------------------------------- 
void XML::writeHTML(Stream &out) 
{ 
	if (!root) 
    	throw StreamException("No XML root"); 
 
    root->write(out,1); 
} 
 
// ---------------------------------- 
void XML::setRoot(Node *n) 
{ 
	root=n; 
} 
 
 
// ---------------------------------- 
XML::Node *XML::findNode(const char *n) 
{ 
	if (root) 
      	return root->findNode(n); 
	else 
		return NULL; 
} 
 
 
// ---------------------------------- 
XML::Node *XML::Node::findNode(const char *name) 
{ 
   	if (stricmp(getName(),name)==0) 
    	return this; 
 
	XML::Node *c = child; 
 
	while (c) 
	{ 
		XML::Node *fn = c->findNode(name); 
		if (fn) 
			return fn; 
		c=c->sibling; 
	} 
 
	return NULL; 
} 
 
// ---------------------------------- 
void XML::read(Stream &in) 
{ 
	const int BUFFER_LEN = 100*1024; 
	static char buf[BUFFER_LEN]; 
 
    Node *currNode=NULL; 
    int tp=0; 
 
    while (!in.eof()) 
    { 
    	char c = in.readChar(); 
 
        if (c == '<') 
        { 
        	if (tp && currNode)	// check for content 
            { 
            	buf[tp] = 0; 
            	currNode->setContent(buf); 
            } 
            tp = 0; 
 
        	// read to next '>' 
            while (!in.eof()) 
            { 
            	c = in.readChar(); 
                if (c == '>') 
                	break; 
 
	        	if (tp >= BUFFER_LEN) 
    	        	throw StreamException("Tag too long"); 
 
                buf[tp++] = c; 
            } 
            buf[tp]=0; 
 
            if (buf[0] == '!')					// comment 
            { 
             	// do nothing 
            }else if (buf[0] == '?')			// doc type 
            { 
            	if (strnicmp(&buf[1],"xml ",4)) 
                	throw StreamException("Not XML document"); 
            }else if (buf[0] == '/')			// end tag 
            { 
            	if (!currNode) 
                	throw StreamException("Unexpected end tag"); 
            	currNode = currNode->parent; 
            }else 	// new tag 
            { 
	            //LOG("tag: %s",buf); 
 
            	bool singleTag = false; 
 
                if (buf[tp-1] == '/')		   	// check for single tag 
                { 
                	singleTag = true; 
                    buf[tp-1] = 0; 
                } 
 
				// only add valid tags 
				if (strlen(buf)) 
				{ 
					Node *n = new Node(buf); 
 
					if (currNode) 
                		currNode->add(n); 
					else 
                		setRoot(n); 
 
					if (!singleTag) 
						currNode = n; 
				} 
            } 
 
            tp = 0; 
        } else { 
 
        	if (tp >= BUFFER_LEN) 
            	throw StreamException("Content too big"); 
 
        	buf[tp++] = c; 
 
        } 
    } 
}