OSDN Git Service

VP27マージ
[peercast-im/PeerCastIM.git] / c: / Git / PeerCast.root / PeerCast / core / common / xml.cpp
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
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 // ------------------------------------------------
20
21 #include "xml.h"
22 #include "stream.h"
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #ifdef _DEBUG
26 #include "chkMemoryLeak.h"
27 #define DEBUG_NEW new(__FILE__, __LINE__)
28 #define new DEBUG_NEW
29 #endif
30
31 // ----------------------------------
32 void XML::Node::add(Node *n)
33 {
34         if (!n)
35                 return;
36
37         n->parent = this;
38
39     if (child)
40     {
41         // has children, add to last sibling
42         Node *s = child;
43         while (s->sibling)
44                 s = s->sibling;
45         s->sibling = n;
46
47     }else{
48         // no children yet
49         child = n;
50     }
51 }
52 // ---------------------------------
53 inline char nibsToByte(char n1, char n2)
54 {
55         if (n1 >= 'A') n1 = n1-'A'+10;
56         else n1 = n1-'0';
57         if (n2 >= 'A') n2 = n2-'A'+10;
58         else n2 = n2-'0';
59
60     return ((n2&0xf)<<4)|(n1&0xf);
61 }
62
63 // ----------------------------------
64 int XML::Node::getBinaryContent(void *ptr, int size)
65 {
66         char *in = contData;
67     char *out = (char *)ptr;
68
69     int i=0;
70     while (*in)
71     {
72         if (isWhiteSpace(*in))
73         {
74                 in++;
75         }else
76         {
77                 if (i >= size)
78                 throw StreamException("Too much binary data");
79                 out[i++] = nibsToByte(in[0],in[1]);
80                 in+=2;
81         }
82     }
83     return i;
84 }
85 // ----------------------------------
86 void XML::Node::setBinaryContent(void *ptr, int size)
87 {
88         const char hexTable[] = "0123456789ABCDEF";
89     const int lineWidth = 1023;
90
91         contData = new char[size*2+1+(size/lineWidth)];
92
93     char *bp = (char *)ptr;
94     register char *ap = contData;
95
96     for(register int i=0; i<size; i++)
97     {
98         register char c = bp[i];
99         *ap++ = hexTable[c&0xf];
100         *ap++ = hexTable[(c>>4)&0xf];
101         if ((i&lineWidth)==lineWidth)
102                 *ap++ = '\n';
103     }
104     ap[0] = 0;
105 }
106
107
108 // ----------------------------------
109 void XML::Node::setContent(const char *n)
110 {
111         contData = strdup(n);
112 }
113 // ----------------------------------
114 void XML::Node::setAttributes(const char *n)
115 {
116     char c;
117
118         attrData = strdup(n);
119
120     // count maximum amount of attributes
121     int maxAttr = 1;            // 1 for tag name
122     bool inQ = false;
123     int i=0;
124     while ((c=attrData[i++])!=0)
125     {
126         if (c=='\"')
127                         inQ ^= true;
128
129                 if (!inQ)
130                         if (c=='=')
131                                 maxAttr++;
132     }
133
134
135     attr = new Attribute[maxAttr];
136
137     attr[0].namePos = 0;
138     attr[0].valuePos = 0;
139
140     numAttr=1;
141
142     i=0;
143
144     // skip until whitespace
145     while (c=attrData[i++])
146         if (isWhiteSpace(c))
147                 break;
148
149     if (!c) return;     // no values
150
151     attrData[i-1]=0;
152
153
154     while ((c=attrData[i])!=0)
155     {
156         if (!isWhiteSpace(c))
157         {
158                         if (numAttr>=maxAttr)
159                                 throw StreamException("Too many attributes");
160
161                         // get start of tag name
162                 attr[numAttr].namePos = i;
163
164
165                         // skip whitespaces until next '='
166                         // terminate name on next whitespace or '='
167             while (attrData[i])
168                         {
169                                 c = attrData[i++];
170
171                                 if ((c == '=') || isWhiteSpace(c))
172                                 {
173                                         attrData[i-1] = 0;      // null term. name
174                                         if (c == '=')
175                                 break;
176                                 }
177                         }
178
179                         // skip whitespaces
180             while (attrData[i])
181                         {
182                     if (isWhiteSpace(attrData[i]))
183                                         i++;
184                                 else
185                                         break;
186                         }
187
188                         // check for valid start of attribute value - '"'
189                         if (attrData[i++] != '\"')
190                 throw StreamException("Bad tag value");
191
192             attr[numAttr++].valuePos = i;
193
194                         // terminate attribute value at next '"'
195
196             while (attrData[i])
197                                 if (attrData[i++] == '\"')
198                         break;
199
200                         attrData[i-1] = 0;      // null term. value
201
202
203         }else{
204                 i++;
205         }
206     }
207 }
208 // ----------------------------------
209 XML::Node::Node(const char *fmt,...)
210 {
211         va_list ap;
212         va_start(ap, fmt);
213
214         char tmp[8192];
215         vsprintf(tmp,fmt,ap);
216         setAttributes(tmp);
217
218         va_end(ap);     
219         init();
220 }
221
222 // ----------------------------------
223 void XML::Node::init()
224 {
225     parent = sibling = child = NULL;
226     contData = NULL;
227     userPtr = NULL;
228 }       
229 // ----------------------------------
230 int XML::Node::findAttrInt(const char *name)
231 {
232         char *v = findAttr(name);
233     if (!v) return 0;
234     return atoi(v);
235 }
236 // ----------------------------------
237 int XML::Node::findAttrID(const char *name)
238 {
239         char *v = findAttr(name);
240     if (!v) return 0;
241     return strToID(v);
242 }
243 // ----------------------------------
244 char *XML::Node::findAttr(const char *name)
245 {
246         size_t nlen = strlen(name);
247         for(int i=1; i<numAttr; i++)
248     {
249         char *an = getAttrName(i);
250         if (strnicmp(an,name,nlen)==0)
251                 return getAttrValue(i);
252     }
253     return NULL;
254 }
255 // ----------------------------------
256 void XML::Node::write(Stream &out, int level)
257 {
258     int i;
259 #if 0
260     char tabs[64];
261
262     for(i=0; i<level; i++)
263         tabs[i] = ' ';
264     tabs[i] = '\0';
265
266
267     if (level)
268             out.write(tabs,i);
269 #endif
270     char *name = getAttrValue(0);
271
272     out.write("<",1);
273     out.write(name,strlen(name));
274
275     for(i=1; i<numAttr; i++)
276     {
277             out.write(" ",1);
278         char *at = getAttrName(i);
279             out.write(at,strlen(at));
280
281             out.write("=\"",2);
282         char *av = getAttrValue(i);
283             out.write(av,strlen(av));
284             out.write("\"",1);
285     }
286
287         if ((!contData) && (!child))
288         {
289             out.write("/>\n",3);
290         }else
291         {
292             out.write(">\n",2);
293
294             if (contData)
295                     out.write(contData,strlen(contData));
296
297                 if (child)
298                 child->write(out,level+1);
299 #if 0
300             if (level)
301                     out.write(tabs,strlen(tabs));
302 #endif
303             out.write("</",2);
304             out.write(name,strlen(name));
305             out.write(">\n",2);
306         }
307
308     if (sibling)
309         sibling->write(out,level);
310 }
311 // ----------------------------------
312 XML::Node::~Node()
313 {
314 //      LOG("delete %s",getName());
315
316         if (contData)
317         delete [] contData;
318     if (attrData)
319         delete [] attrData;
320     if (attr)
321         delete [] attr;
322
323     Node *n = child;
324     while (n)
325     {
326         Node *nn = n->sibling;
327         delete n;
328         n = nn;
329     }
330 }
331
332
333 // ----------------------------------
334 XML::~XML()
335 {
336         if (root)
337         delete root;
338 }
339
340 // ----------------------------------
341 void XML::write(Stream &out)
342 {
343         if (!root)
344         throw StreamException("No XML root");
345
346         out.writeLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
347     root->write(out,1);
348
349 }
350 // ----------------------------------
351 void XML::writeCompact(Stream &out)
352 {
353         if (!root)
354         throw StreamException("No XML root");
355
356         out.writeLine("<?xml ?>");
357     root->write(out,1);
358
359 }
360 // ----------------------------------
361 void XML::writeHTML(Stream &out)
362 {
363         if (!root)
364         throw StreamException("No XML root");
365
366     root->write(out,1);
367 }
368
369 // ----------------------------------
370 void XML::setRoot(Node *n)
371 {
372         root=n;
373 }
374
375
376 // ----------------------------------
377 XML::Node *XML::findNode(const char *n)
378 {
379         if (root)
380         return root->findNode(n);
381         else
382                 return NULL;
383 }
384
385
386 // ----------------------------------
387 XML::Node *XML::Node::findNode(const char *name)
388 {
389         if (stricmp(getName(),name)==0)
390         return this;
391
392         XML::Node *c = child;
393
394         while (c)
395         {
396                 XML::Node *fn = c->findNode(name);
397                 if (fn)
398                         return fn;
399                 c=c->sibling;
400         }
401
402         return NULL;
403 }
404
405 // ----------------------------------
406 void XML::read(Stream &in)
407 {
408         const int BUFFER_LEN = 100*1024;
409         static char buf[BUFFER_LEN];
410
411     Node *currNode=NULL;
412     int tp=0;
413
414     while (!in.eof())
415     {
416         char c = in.readChar();
417
418         if (c == '<')
419         {
420                 if (tp && currNode)     // check for content
421             {
422                 buf[tp] = 0;
423                 currNode->setContent(buf);
424             }
425             tp = 0;
426
427                 // read to next '>'
428             while (!in.eof())
429             {
430                 c = in.readChar();
431                 if (c == '>')
432                         break;
433
434                         if (tp >= BUFFER_LEN)
435                         throw StreamException("Tag too long");
436
437                 buf[tp++] = c;
438             }
439             buf[tp]=0;
440
441             if (buf[0] == '!')                                  // comment
442             {
443                 // do nothing
444             }else if (buf[0] == '?')                    // doc type
445             {
446                 if (strnicmp(&buf[1],"xml ",4))
447                         throw StreamException("Not XML document");
448             }else if (buf[0] == '/')                    // end tag
449             {
450                 if (!currNode)
451                         throw StreamException("Unexpected end tag");
452                 currNode = currNode->parent;
453             }else       // new tag
454             {
455                     //LOG("tag: %s",buf);
456
457                 bool singleTag = false;
458
459                 if (buf[tp-1] == '/')                   // check for single tag
460                 {
461                         singleTag = true;
462                     buf[tp-1] = 0;
463                 }
464
465                                 // only add valid tags
466                                 if (strlen(buf))
467                                 {
468                                         Node *n = new Node(buf);
469
470                                         if (currNode)
471                                 currNode->add(n);
472                                         else
473                                 setRoot(n);
474
475                                         if (!singleTag)
476                                                 currNode = n;
477                                 }
478             }
479
480             tp = 0;
481         } else {
482
483                 if (tp >= BUFFER_LEN)
484                 throw StreamException("Content too big");
485
486                 buf[tp++] = c;
487
488         }
489     }
490 }
491