xml.cpp
上传用户:chn_coc
上传日期:2007-12-20
资源大小:563k
文件大小:10k
源码类别:

P2P编程

开发平台:

Windows_Unix

  1. // ------------------------------------------------
  2. // File : xml.cpp
  3. // Date: 4-apr-2002
  4. // Author: giles
  5. // Desc: 
  6. // Basic XML parsing/creation 
  7. //
  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.
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. // GNU General Public License for more details.
  18. // ------------------------------------------------
  19. #include "xml.h"
  20. #include "stream.h"
  21. #include <stdlib.h>
  22. #include <stdarg.h>
  23. // ----------------------------------
  24. void XML::Node::add(Node *n)
  25. {
  26. if (!n)
  27. return;
  28. n->parent = this;
  29.     if (child)
  30.     {
  31.      // has children, add to last sibling
  32.         Node *s = child;
  33.         while (s->sibling)
  34.          s = s->sibling;
  35.         s->sibling = n;
  36.     }else{
  37.      // no children yet
  38.         child = n;
  39.     }
  40. }
  41. // ---------------------------------
  42. inline char nibsToByte(char n1, char n2)
  43. {
  44. if (n1 >= 'A') n1 = n1-'A'+10;
  45. else n1 = n1-'0';
  46. if (n2 >= 'A') n2 = n2-'A'+10;
  47. else n2 = n2-'0';
  48.     return ((n2&0xf)<<4)|(n1&0xf);
  49. }
  50. // ----------------------------------
  51. int XML::Node::getBinaryContent(void *ptr, int size)
  52. {
  53. char *in = contData;
  54.     char *out = (char *)ptr;
  55.     int i=0;
  56.     while (*in)
  57.     {
  58.      if (isWhiteSpace(*in))
  59.         {
  60.          in++;
  61.         }else
  62.         {
  63.          if (i >= size)
  64.              throw StreamException("Too much binary data");
  65.      out[i++] = nibsToByte(in[0],in[1]);
  66.         in+=2;
  67.         }
  68.     }
  69.     return i;
  70. }
  71. // ----------------------------------
  72. void XML::Node::setBinaryContent(void *ptr, int size)
  73. {
  74. const char hexTable[] = "0123456789ABCDEF";
  75.     const int lineWidth = 1023;
  76. contData = new char[size*2+1+(size/lineWidth)];
  77.     char *bp = (char *)ptr;
  78.     register char *ap = contData;
  79.     for(register int i=0; i<size; i++)
  80.     {
  81.      register char c = bp[i];
  82.      *ap++ = hexTable[c&0xf];
  83.      *ap++ = hexTable[(c>>4)&0xf];
  84.         if ((i&lineWidth)==lineWidth)
  85.      *ap++ = 'n';
  86.     }
  87.     ap[0] = 0;
  88. }
  89. // ----------------------------------
  90. void XML::Node::setContent(const char *n)
  91. {
  92. contData = strdup(n);
  93. }
  94. // ----------------------------------
  95. void XML::Node::setAttributes(const char *n)
  96. {
  97.     char c;
  98. attrData = strdup(n);
  99.     // count maximum amount of attributes
  100.     int maxAttr = 1; // 1 for tag name
  101.     bool inQ = false;
  102.     int i=0;
  103.     while ((c=attrData[i++])!=0)
  104.     {
  105.      if (c=='"')
  106. inQ ^= true;
  107. if (!inQ)
  108. if (c=='=')
  109. maxAttr++;
  110.     }
  111.     attr = new Attribute[maxAttr];
  112.     attr[0].namePos = 0;
  113.     attr[0].valuePos = 0;
  114.     numAttr=1;
  115.     i=0;
  116.     // skip until whitespace
  117.     while (c=attrData[i++])
  118.      if (isWhiteSpace(c))
  119.          break;
  120.     if (!c) return; // no values
  121.     attrData[i-1]=0;
  122.     while ((c=attrData[i])!=0)
  123.     {
  124.      if (!isWhiteSpace(c))
  125.         {
  126. if (numAttr>=maxAttr)
  127. throw StreamException("Too many attributes");
  128. // get start of tag name
  129.          attr[numAttr].namePos = i;
  130. // skip whitespaces until next '='
  131. // terminate name on next whitespace or '='
  132.             while (attrData[i])
  133. {
  134. c = attrData[i++];
  135. if ((c == '=') || isWhiteSpace(c))
  136. {
  137. attrData[i-1] = 0; // null term. name
  138. if (c == '=')
  139.                  break;
  140. }
  141. }
  142. // skip whitespaces
  143.             while (attrData[i])
  144. {
  145.             if (isWhiteSpace(attrData[i]))
  146. i++;
  147. else
  148. break;
  149. }
  150. // check for valid start of attribute value - '"'
  151. if (attrData[i++] != '"')
  152.              throw StreamException("Bad tag value");
  153.             attr[numAttr++].valuePos = i;
  154. // terminate attribute value at next '"'
  155.             while (attrData[i])
  156. if (attrData[i++] == '"')
  157.                  break;
  158. attrData[i-1] = 0; // null term. value
  159.         }else{
  160.         i++;
  161.      }
  162.     }
  163. }
  164. // ----------------------------------
  165. XML::Node::Node(const char *fmt,...)
  166. {
  167. va_list ap;
  168.    va_start(ap, fmt);
  169. char tmp[8192];
  170. vsprintf(tmp,fmt,ap);
  171. setAttributes(tmp);
  172.     va_end(ap);
  173. init();
  174. }
  175. // ----------------------------------
  176. void XML::Node::init()
  177. {
  178.     parent = sibling = child = NULL;
  179.     contData = NULL;
  180.     userPtr = NULL;
  181. }
  182. // ----------------------------------
  183. int XML::Node::findAttrInt(const char *name)
  184. {
  185. char *v = findAttr(name);
  186.     if (!v) return 0;
  187.     return atoi(v);
  188. }
  189. // ----------------------------------
  190. int XML::Node::findAttrID(const char *name)
  191. {
  192. char *v = findAttr(name);
  193.     if (!v) return 0;
  194.     return strToID(v);
  195. }
  196. // ----------------------------------
  197. char *XML::Node::findAttr(const char *name)
  198. {
  199. int nlen = strlen(name);
  200. for(int i=1; i<numAttr; i++)
  201.     {
  202.      char *an = getAttrName(i);
  203.      if (strnicmp(an,name,nlen)==0)
  204.          return getAttrValue(i);
  205.     }
  206.     return NULL;
  207. }
  208. // ----------------------------------
  209. void XML::Node::write(Stream &out, int level)
  210. {
  211.     int i;
  212. #if 0
  213.     char tabs[64];
  214.     for(i=0; i<level; i++)
  215.      tabs[i] = ' ';
  216.     tabs[i] = '';
  217.     if (level)
  218.     out.write(tabs,i);
  219. #endif
  220.     char *name = getAttrValue(0);
  221.     out.write("<",1);
  222.     out.write(name,strlen(name));
  223.     for(i=1; i<numAttr; i++)
  224.     {
  225.     out.write(" ",1);
  226.      char *at = getAttrName(i);
  227.     out.write(at,strlen(at));
  228.     out.write("="",2);
  229.         char *av = getAttrValue(i);
  230.     out.write(av,strlen(av));
  231.     out.write(""",1);
  232.     }
  233. if ((!contData) && (!child))
  234. {
  235.     out.write("/>n",3);
  236. }else
  237. {
  238.     out.write(">n",2);
  239.     if (contData)
  240.     out.write(contData,strlen(contData));
  241. if (child)
  242.      child->write(out,level+1);
  243. #if 0
  244.     if (level)
  245.     out.write(tabs,strlen(tabs));
  246. #endif
  247.     out.write("</",2);
  248.     out.write(name,strlen(name));
  249.     out.write(">n",2);
  250. }
  251.     if (sibling)
  252.      sibling->write(out,level);
  253. }
  254. // ----------------------------------
  255. XML::Node::~Node()
  256. {
  257. // LOG("delete %s",getName());
  258. if (contData)
  259.      delete [] contData;
  260.     if (attrData)
  261.      delete [] attrData;
  262.     if (attr)
  263.      delete [] attr;
  264.     Node *n = child;
  265.     while (n)
  266.     {
  267.      Node *nn = n->sibling;
  268.      delete n;
  269.      n = nn;
  270.     }
  271. }
  272. // ----------------------------------
  273. XML::~XML()
  274. {
  275. if (root)
  276.      delete root;
  277. }
  278. // ----------------------------------
  279. void XML::write(Stream &out)
  280. {
  281. if (!root)
  282.      throw StreamException("No XML root");
  283. out.writeLine("<?xml version="1.0" encoding="utf-8" ?>");
  284.     root->write(out,1);
  285. }
  286. // ----------------------------------
  287. void XML::writeCompact(Stream &out)
  288. {
  289. if (!root)
  290.      throw StreamException("No XML root");
  291. out.writeLine("<?xml ?>");
  292.     root->write(out,1);
  293. }
  294. // ----------------------------------
  295. void XML::writeHTML(Stream &out)
  296. {
  297. if (!root)
  298.      throw StreamException("No XML root");
  299.     root->write(out,1);
  300. }
  301. // ----------------------------------
  302. void XML::setRoot(Node *n)
  303. {
  304. root=n;
  305. }
  306. // ----------------------------------
  307. XML::Node *XML::findNode(const char *n)
  308. {
  309. if (root)
  310.        return root->findNode(n);
  311. else
  312. return NULL;
  313. }
  314. // ----------------------------------
  315. XML::Node *XML::Node::findNode(const char *name)
  316. {
  317.     if (stricmp(getName(),name)==0)
  318.      return this;
  319. XML::Node *c = child;
  320. while (c)
  321. {
  322. XML::Node *fn = c->findNode(name);
  323. if (fn)
  324. return fn;
  325. c=c->sibling;
  326. }
  327. return NULL;
  328. }
  329. // ----------------------------------
  330. void XML::read(Stream &in)
  331. {
  332. const int BUFFER_LEN = 100*1024;
  333. static char buf[BUFFER_LEN];
  334.     Node *currNode=NULL;
  335.     int tp=0;
  336.     while (!in.eof())
  337.     {
  338.      char c = in.readChar();
  339.         if (c == '<')
  340.         {
  341.          if (tp && currNode) // check for content
  342.             {
  343.              buf[tp] = 0;
  344.              currNode->setContent(buf);
  345.             }
  346.             tp = 0;
  347.          // read to next '>'
  348.             while (!in.eof())
  349.             {
  350.              c = in.readChar();
  351.                 if (c == '>')
  352.                  break;
  353.          if (tp >= BUFFER_LEN)
  354.               throw StreamException("Tag too long");
  355.                 buf[tp++] = c;
  356.             }
  357.             buf[tp]=0;
  358.             if (buf[0] == '!') // comment
  359.             {
  360.               // do nothing
  361.             }else if (buf[0] == '?') // doc type
  362.             {
  363.              if (strnicmp(&buf[1],"xml ",4))
  364.                  throw StreamException("Not XML document");
  365.             }else if (buf[0] == '/') // end tag
  366.             {
  367.              if (!currNode)
  368.                  throw StreamException("Unexpected end tag");
  369.              currNode = currNode->parent;
  370.             }else  // new tag
  371.             {
  372.             //LOG("tag: %s",buf);
  373.              bool singleTag = false;
  374.                 if (buf[tp-1] == '/')     // check for single tag
  375.                 {
  376.                  singleTag = true;
  377.                     buf[tp-1] = 0;
  378.                 }
  379. // only add valid tags
  380. if (strlen(buf))
  381. {
  382. Node *n = new Node(buf);
  383. if (currNode)
  384.                  currNode->add(n);
  385. else
  386.                  setRoot(n);
  387. if (!singleTag)
  388. currNode = n;
  389. }
  390.             }
  391.             tp = 0;
  392.         } else {
  393.          if (tp >= BUFFER_LEN)
  394.              throw StreamException("Content too big");
  395.          buf[tp++] = c;
  396.         }
  397.     }
  398. }