1 // ------------------------------------------------
6 // Basic XML parsing/creation
8 // (c) 2002 peercast.org
9 // ------------------------------------------------
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 // ------------------------------------------------
26 #include "chkMemoryLeak.h"
27 #define DEBUG_NEW new(__FILE__, __LINE__)
31 // ----------------------------------
32 void XML::Node::add(Node *n)
41 // has children, add to last sibling
52 // ---------------------------------
53 inline char nibsToByte(char n1, char n2)
55 if (n1 >= 'A') n1 = n1-'A'+10;
57 if (n2 >= 'A') n2 = n2-'A'+10;
60 return ((n2&0xf)<<4)|(n1&0xf);
63 // ----------------------------------
64 int XML::Node::getBinaryContent(void *ptr, int size)
67 char *out = (char *)ptr;
72 if (isWhiteSpace(*in))
78 throw StreamException("Too much binary data");
79 out[i++] = nibsToByte(in[0],in[1]);
85 // ----------------------------------
86 void XML::Node::setBinaryContent(void *ptr, int size)
88 const char hexTable[] = "0123456789ABCDEF";
89 const int lineWidth = 1023;
91 contData = new char[size*2+1+(size/lineWidth)];
93 char *bp = (char *)ptr;
94 register char *ap = contData;
96 for(register int i=0; i<size; i++)
98 register char c = bp[i];
99 *ap++ = hexTable[c&0xf];
100 *ap++ = hexTable[(c>>4)&0xf];
101 if ((i&lineWidth)==lineWidth)
108 // ----------------------------------
109 void XML::Node::setContent(const char *n)
111 contData = strdup(n);
113 // ----------------------------------
114 void XML::Node::setAttributes(const char *n)
118 attrData = strdup(n);
120 // count maximum amount of attributes
121 int maxAttr = 1; // 1 for tag name
124 while ((c=attrData[i++])!=0)
135 attr = new Attribute[maxAttr];
138 attr[0].valuePos = 0;
144 // skip until whitespace
145 while (c=attrData[i++])
149 if (!c) return; // no values
154 while ((c=attrData[i])!=0)
156 if (!isWhiteSpace(c))
158 if (numAttr>=maxAttr)
159 throw StreamException("Too many attributes");
161 // get start of tag name
162 attr[numAttr].namePos = i;
165 // skip whitespaces until next '='
166 // terminate name on next whitespace or '='
171 if ((c == '=') || isWhiteSpace(c))
173 attrData[i-1] = 0; // null term. name
182 if (isWhiteSpace(attrData[i]))
188 // check for valid start of attribute value - '"'
189 if (attrData[i++] != '\"')
190 throw StreamException("Bad tag value");
192 attr[numAttr++].valuePos = i;
194 // terminate attribute value at next '"'
197 if (attrData[i++] == '\"')
200 attrData[i-1] = 0; // null term. value
208 // ----------------------------------
209 XML::Node::Node(const char *fmt,...)
215 vsprintf(tmp,fmt,ap);
222 // ----------------------------------
223 void XML::Node::init()
225 parent = sibling = child = NULL;
229 // ----------------------------------
230 int XML::Node::findAttrInt(const char *name)
232 char *v = findAttr(name);
236 // ----------------------------------
237 int XML::Node::findAttrID(const char *name)
239 char *v = findAttr(name);
243 // ----------------------------------
244 char *XML::Node::findAttr(const char *name)
246 size_t nlen = strlen(name);
247 for(int i=1; i<numAttr; i++)
249 char *an = getAttrName(i);
250 if (strnicmp(an,name,nlen)==0)
251 return getAttrValue(i);
255 // ----------------------------------
256 void XML::Node::write(Stream &out, int level)
262 for(i=0; i<level; i++)
270 char *name = getAttrValue(0);
273 out.write(name,strlen(name));
275 for(i=1; i<numAttr; i++)
278 char *at = getAttrName(i);
279 out.write(at,strlen(at));
282 char *av = getAttrValue(i);
283 out.write(av,strlen(av));
287 if ((!contData) && (!child))
295 out.write(contData,strlen(contData));
298 child->write(out,level+1);
301 out.write(tabs,strlen(tabs));
304 out.write(name,strlen(name));
309 sibling->write(out,level);
311 // ----------------------------------
314 // LOG("delete %s",getName());
326 Node *nn = n->sibling;
333 // ----------------------------------
340 // ----------------------------------
341 void XML::write(Stream &out)
344 throw StreamException("No XML root");
346 out.writeLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
350 // ----------------------------------
351 void XML::writeCompact(Stream &out)
354 throw StreamException("No XML root");
356 out.writeLine("<?xml ?>");
360 // ----------------------------------
361 void XML::writeHTML(Stream &out)
364 throw StreamException("No XML root");
369 // ----------------------------------
370 void XML::setRoot(Node *n)
376 // ----------------------------------
377 XML::Node *XML::findNode(const char *n)
380 return root->findNode(n);
386 // ----------------------------------
387 XML::Node *XML::Node::findNode(const char *name)
389 if (stricmp(getName(),name)==0)
392 XML::Node *c = child;
396 XML::Node *fn = c->findNode(name);
405 // ----------------------------------
406 void XML::read(Stream &in)
408 const int BUFFER_LEN = 100*1024;
409 static char buf[BUFFER_LEN];
416 char c = in.readChar();
420 if (tp && currNode) // check for content
423 currNode->setContent(buf);
434 if (tp >= BUFFER_LEN)
435 throw StreamException("Tag too long");
441 if (buf[0] == '!') // comment
444 }else if (buf[0] == '?') // doc type
446 if (strnicmp(&buf[1],"xml ",4))
447 throw StreamException("Not XML document");
448 }else if (buf[0] == '/') // end tag
451 throw StreamException("Unexpected end tag");
452 currNode = currNode->parent;
455 //LOG("tag: %s",buf);
457 bool singleTag = false;
459 if (buf[tp-1] == '/') // check for single tag
465 // only add valid tags
468 Node *n = new Node(buf);
483 if (tp >= BUFFER_LEN)
484 throw StreamException("Content too big");