Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TXMLEngine.cxx
Go to the documentation of this file.
1 // @(#)root/xml:$Id: 1bd040ac1c03c58bcad15b5206d602680a831c0a $
2 // Author: Sergey Linev 10.05.2004
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //________________________________________________________________________
13 //
14 // TXMLEngine class is used to write and read ROOT XML files - TXMLFile.
15 // It does not conform to complete xml standard and cannot be used
16 // as parser for arbitrary XML files. For such cases TXMLParser should
17 // be used. This class was introduced to exclude dependency from
18 // external libraries (like libxml2) and improve speed / memory consumption.
19 //
20 //________________________________________________________________________
21 
22 #include "TXMLEngine.h"
23 
24 #include "Riostream.h"
25 #include "TString.h"
26 #include "TNamed.h"
27 #include "TObjArray.h"
28 #include <stdlib.h>
29 #include <string.h>
30 
31 ClassImp(TXMLEngine);
32 
33 struct SXmlAttr_t {
34  SXmlAttr_t *fNext;
35  // after structure itself memory for attribute name is preserved
36  // if first byte is 0, this is special attribute
37  static inline char *Name(void *arg) { return (char *)arg + sizeof(SXmlAttr_t); }
38 };
39 
40 enum EXmlNodeType {
41  kXML_NODE = 1, // normal node with children
42  kXML_COMMENT = 2, // comment (stored as value of node fName)
43  kXML_PI_NODE = 3, // processing instructions node (like <?name attr="" ?>
44  kXML_RAWLINE = 4, // just one line of xml code
45  kXML_CONTENT = 5 // node content, can appear many times in between of normal nodes
46 };
47 
48 struct SXmlNode_t {
49  EXmlNodeType fType; // this is node type - node, comment, processing instruction and so on
50  SXmlAttr_t *fAttr; // first attribute
51  SXmlAttr_t *fNs; // name space definition (if any)
52  SXmlNode_t *fNext; // next node on the same level of hierarchy
53  SXmlNode_t *fChild; // first child node
54  SXmlNode_t *fLastChild; // last child node
55  SXmlNode_t *fParent; // parent node
56  // consequent bytes after structure are node name
57  // if first byte is 0, next is node content
58  static inline char *Name(void *arg) { return (char *)arg + sizeof(SXmlNode_t); }
59 };
60 
61 struct SXmlDoc_t {
62  SXmlNode_t *fRootNode;
63  char *fDtdName;
64  char *fDtdRoot;
65 };
66 
67 class TXMLOutputStream {
68 protected:
69  std::ostream *fOut;
70  TString *fOutStr;
71  char *fBuf;
72  char *fCurrent;
73  char *fMaxAddr;
74  char *fLimitAddr;
75 
76 public:
77  TXMLOutputStream(const char *filename, Int_t bufsize = 20000)
78  {
79  fOut = new std::ofstream(filename);
80  fOutStr = 0;
81  Init(bufsize);
82  }
83 
84  TXMLOutputStream(TString *outstr, Int_t bufsize = 20000)
85  {
86  fOut = 0;
87  fOutStr = outstr;
88  Init(bufsize);
89  }
90 
91  void Init(Int_t bufsize)
92  {
93  fBuf = (char *)malloc(bufsize);
94  fCurrent = fBuf;
95  fMaxAddr = fBuf + bufsize;
96  fLimitAddr = fBuf + int(bufsize * 0.75);
97  }
98 
99  virtual ~TXMLOutputStream()
100  {
101  if (fCurrent != fBuf)
102  OutputCurrent();
103  delete fOut;
104  free(fBuf);
105  }
106 
107  void OutputCurrent()
108  {
109  if (fCurrent != fBuf) {
110  if (fOut != 0)
111  fOut->write(fBuf, fCurrent - fBuf);
112  else if (fOutStr != 0)
113  fOutStr->Append(fBuf, fCurrent - fBuf);
114  }
115  fCurrent = fBuf;
116  }
117 
118  void OutputChar(char symb)
119  {
120  if (fOut != 0)
121  fOut->put(symb);
122  else if (fOutStr != 0)
123  fOutStr->Append(symb);
124  }
125 
126  void Write(const char *str)
127  {
128  int len = strlen(str);
129  if (fCurrent + len >= fMaxAddr) {
130  OutputCurrent();
131  fOut->write(str, len);
132  } else {
133  while (*str)
134  *fCurrent++ = *str++;
135  if (fCurrent > fLimitAddr)
136  OutputCurrent();
137  }
138  }
139 
140  void Put(char symb, Int_t cnt = 1)
141  {
142  if (fCurrent + cnt >= fMaxAddr)
143  OutputCurrent();
144  if (fCurrent + cnt >= fMaxAddr)
145  for (int n = 0; n < cnt; n++)
146  OutputChar(symb);
147  else {
148  for (int n = 0; n < cnt; n++)
149  *fCurrent++ = symb;
150  if (fCurrent > fLimitAddr)
151  OutputCurrent();
152  }
153  }
154 };
155 
156 class TXMLEntity : public TNamed {
157  Bool_t fSystem; //! is system (file)
158 public:
159  TXMLEntity() : TNamed(), fSystem(kFALSE) {}
160  TXMLEntity(const TString &name, const TString &value, Bool_t sys) : TNamed(name, value), fSystem(sys) {}
161  Bool_t IsSystem() const { return fSystem; }
162 };
163 
164 class TXMLInputStream {
165 protected:
166  std::istream *fInp;
167  const char *fInpStr;
168  Int_t fInpStrLen;
169 
170  char *fBuf;
171  Int_t fBufSize;
172 
173  char *fMaxAddr;
174  char *fLimitAddr;
175 
176  Int_t fTotalPos;
177  Int_t fCurrentLine;
178 
179  TObjArray fEntities; //! array of TXMLEntity
180 
181 public:
182  char *fCurrent;
183 
184  ////////////////////////////////////////////////////////////////////////////
185  /// constructor
186 
187  TXMLInputStream(Bool_t isfilename, const char *filename, Int_t ibufsize)
188  : fInp(0), fInpStr(0), fInpStrLen(0), fBuf(0), fBufSize(0), fMaxAddr(0), fLimitAddr(0), fTotalPos(0),
189  fCurrentLine(0), fEntities(), fCurrent(0)
190  {
191  if (isfilename) {
192  fInp = new std::ifstream(filename);
193  fInpStr = 0;
194  fInpStrLen = 0;
195  } else {
196  fInp = 0;
197  fInpStr = filename;
198  fInpStrLen = filename == 0 ? 0 : strlen(filename);
199  }
200 
201  fBufSize = ibufsize;
202  fBuf = (char *)malloc(fBufSize);
203 
204  fCurrent = 0;
205  fMaxAddr = 0;
206 
207  int len = DoRead(fBuf, fBufSize);
208  fCurrent = fBuf;
209  fMaxAddr = fBuf + len;
210  fLimitAddr = fBuf + int(len * 0.75);
211 
212  fTotalPos = 0;
213  fCurrentLine = 1;
214 
215  fEntities.SetOwner(kTRUE);
216  }
217 
218  ////////////////////////////////////////////////////////////////////////////
219  /// destructor
220 
221  virtual ~TXMLInputStream()
222  {
223  delete fInp;
224  fInp = 0;
225  free(fBuf);
226  fBuf = 0;
227  }
228 
229  ////////////////////////////////////////////////////////////////////////////
230  /// return true if end of file is achieved
231 
232  inline Bool_t EndOfFile() { return (fInp != 0) ? fInp->eof() : (fInpStrLen <= 0); }
233 
234  ////////////////////////////////////////////////////////////////////////////
235  /// return true if end of file and all data from buffer are processed
236 
237  inline Bool_t EndOfStream() { return EndOfFile() && (fCurrent >= fMaxAddr); }
238 
239  ////////////////////////////////////////////////////////////////////////////
240  /// Add new entity
241 
242  void AddEntity(TXMLEntity *ent) { fEntities.Add(ent); }
243 
244  ////////////////////////////////////////////////////////////////////////////
245  /// Returns number of entity
246 
247  Int_t NumEntities() const { return fEntities.GetLast() + 1; }
248 
249  ////////////////////////////////////////////////////////////////////////////
250  /// Search for the entity
251 
252  TXMLEntity *FindEntity(const char *beg, Int_t len)
253  {
254  if (len <= 0)
255  return 0;
256  for (Int_t n = 0; n <= fEntities.GetLast(); n++) {
257  TXMLEntity *entity = (TXMLEntity *)fEntities[n];
258  if ((Int_t)strlen(entity->GetName()) != len)
259  continue;
260  if (strncmp(beg, entity->GetName(), len) == 0)
261  return entity;
262  }
263  return 0;
264  }
265 
266  ////////////////////////////////////////////////////////////////////////////
267  /// Read new data into buffer
268 
269  int DoRead(char *buf, int maxsize)
270  {
271  if (EndOfFile())
272  return 0;
273 
274  int resultsize = 0;
275  if (fInp != 0) {
276  fInp->get(buf, maxsize, 0);
277  resultsize = strlen(buf);
278  } else {
279  resultsize = strlcpy(buf, fInpStr, maxsize);
280  if (resultsize >= maxsize)
281  resultsize = maxsize - 1;
282  fInpStr += resultsize;
283  fInpStrLen -= resultsize;
284  }
285  return resultsize;
286  }
287 
288  ////////////////////////////////////////////////////////////////////////////
289  /// Allocate more data for the buffer, preserving content
290 
291  Bool_t ExpandStream(char *&curr)
292  {
293  if (EndOfFile())
294  return kFALSE;
295  fBufSize *= 2;
296  int curlength = fMaxAddr - fBuf;
297  char *newbuf = (char *)realloc(fBuf, fBufSize);
298  if (!newbuf)
299  return kFALSE;
300 
301  fMaxAddr = newbuf + (fMaxAddr - fBuf);
302  fCurrent = newbuf + (fCurrent - fBuf);
303  fLimitAddr = newbuf + (fLimitAddr - fBuf);
304  curr = newbuf + (curr - fBuf);
305  fBuf = newbuf;
306 
307  int len = DoRead(fMaxAddr, fBufSize - curlength);
308  if (len == 0)
309  return kFALSE;
310  fMaxAddr += len;
311  fLimitAddr += int(len * 0.75);
312  return kTRUE;
313  }
314 
315  ////////////////////////////////////////////////////////////////////////////
316  /// read next portion of data from the stream in the buffer
317 
318  Bool_t ShiftStream()
319  {
320  if (fCurrent < fLimitAddr)
321  return kTRUE; // everything ok, can continue
322  if (EndOfFile())
323  return kTRUE;
324  int rest_len = fMaxAddr - fCurrent;
325  memmove(fBuf, fCurrent, rest_len);
326  int read_len = DoRead(fBuf + rest_len, fBufSize - rest_len);
327 
328  fCurrent = fBuf;
329  fMaxAddr = fBuf + rest_len + read_len;
330  fLimitAddr = fBuf + int((rest_len + read_len) * 0.75);
331  return kTRUE;
332  }
333 
334  ////////////////////////////////////////////////////////////////////////////
335  /// returns absolute byte position in the stream
336 
337  Int_t TotalPos() { return fTotalPos; }
338 
339  ////////////////////////////////////////////////////////////////////////////
340  /// returns current line number in the input stream
341 
342  Int_t CurrentLine() { return fCurrentLine; }
343 
344  ////////////////////////////////////////////////////////////////////////////
345  /// shift current position on provided number of symbol
346 
347  Bool_t ShiftCurrent(Int_t sz = 1)
348  {
349  for (int n = 0; n < sz; n++) {
350  if (*fCurrent == 10)
351  fCurrentLine++;
352  if (fCurrent >= fLimitAddr) {
353  ShiftStream();
354  if (fCurrent >= fMaxAddr)
355  return kFALSE;
356  }
357  fCurrent++;
358  }
359  fTotalPos += sz;
360  return kTRUE;
361  }
362 
363  ////////////////////////////////////////////////////////////////////////////
364  /// Skip spaces at the current position
365 
366  Bool_t SkipSpaces(Bool_t tillendl = kFALSE)
367  {
368  while (fCurrent < fMaxAddr) {
369  char symb = *fCurrent;
370  if ((symb > 26) && (symb != ' '))
371  return kTRUE;
372 
373  if (!ShiftCurrent())
374  return kFALSE;
375 
376  if (tillendl && (symb == 10))
377  return kTRUE;
378  }
379  return kFALSE;
380  }
381 
382  /////////////////////////////////////////////////////////////
383  /// Check if in current position we see specified string
384 
385  Bool_t CheckFor(const char *str)
386  {
387  int len = strlen(str);
388  char *curr = fCurrent;
389  while (curr + len > fMaxAddr) {
390  if (!ExpandStream(curr))
391  return kFALSE;
392  }
393  while (*str != 0)
394  if (*str++ != *curr++)
395  return kFALSE;
396  return ShiftCurrent(len);
397  }
398 
399  /////////////////////////////////////////////////////////////////////
400  /// Search for specified string in the stream
401  /// return number of symbols before string was found, -1 if error
402 
403  Int_t SearchFor(const char *str)
404  {
405  int len = strlen(str);
406 
407  char *curr = fCurrent;
408 
409  do {
410  curr++;
411  while (curr + len > fMaxAddr)
412  if (!ExpandStream(curr))
413  return -1;
414  char *chk0 = curr;
415  const char *chk = str;
416  Bool_t find = kTRUE;
417  while (*chk != 0)
418  if (*chk++ != *chk0++) {
419  find = kFALSE;
420  break;
421  }
422  // if string found, shift to the next symbol after string
423  if (find)
424  return curr - fCurrent;
425  } while (curr < fMaxAddr);
426  return -1;
427  }
428 
429  ////////////////////////////////////////////////////////////////////////////
430  /// returns true if symbol can be used as starting in the node name
431 
432  inline Bool_t GoodStartSymbol(unsigned char symb)
433  {
434  return (((symb >= 'a') && (symb <= 'z')) || ((symb >= 'A') && (symb <= 'Z')) || (symb == '_') ||
435  ((symb >= 0xc0) && (symb <= 0xd6)) || ((symb >= 0xd8) && (symb <= 0xf6)) || (symb > 0xf8));
436  }
437 
438  ////////////////////////////////////////////////////////////////////////////
439  /// locate identifier in the stream, returns length of the identifier (or 0 if fails)
440 
441  Int_t LocateIdentifier()
442  {
443  unsigned char symb = (unsigned char)*fCurrent;
444 
445  Bool_t ok = GoodStartSymbol(symb);
446  if (!ok)
447  return 0;
448 
449  char *curr = fCurrent;
450 
451  do {
452  curr++;
453  if (curr >= fMaxAddr)
454  if (!ExpandStream(curr))
455  return 0;
456  symb = (unsigned char)*curr;
457  ok = GoodStartSymbol(symb) || ((symb >= '0') && (symb <= '9')) || (symb == ':') || (symb == '-') ||
458  (symb == '.') || (symb == 0xb7);
459  if (!ok)
460  return curr - fCurrent;
461  } while (curr < fMaxAddr);
462  return 0;
463  }
464 
465  ////////////////////////////////////////////////////////////////////////////
466  /// locate node content, returns length (or -1 if fails)
467 
468  Int_t LocateContent()
469  {
470  char *curr = fCurrent;
471  while (curr < fMaxAddr) {
472  char symb = *curr;
473  if (symb == '<')
474  return curr - fCurrent;
475  curr++;
476  if (curr >= fMaxAddr)
477  if (!ExpandStream(curr))
478  return -1;
479  }
480  return -1;
481  }
482 
483  ////////////////////////////////////////////////////////////////////////////
484  /// locate attribute value, returns length (or 0 if fails)
485 
486  Int_t LocateValue(unsigned curr_offset, bool withequalsign = true)
487  {
488  char *curr = fCurrent + curr_offset;
489  if (curr >= fMaxAddr)
490  if (!ExpandStream(curr))
491  return 0;
492  if (withequalsign) {
493  if (*curr != '=')
494  return 0;
495  curr++;
496  if (curr >= fMaxAddr)
497  if (!ExpandStream(curr))
498  return 0;
499  }
500  if ((*curr != '\"') && (*curr != '\''))
501  return 0;
502  char quote = *curr;
503  do {
504  curr++;
505  if (curr >= fMaxAddr)
506  if (!ExpandStream(curr))
507  return 0;
508  if (*curr == quote)
509  return curr - (fCurrent + curr_offset) + 1;
510  } while (curr < fMaxAddr);
511  return 0;
512  }
513 };
514 
515 ////////////////////////////////////////////////////////////////////////////////
516 /// default (normal) constructor of TXMLEngine class
517 
518 TXMLEngine::TXMLEngine()
519 {
520  fSkipComments = kFALSE;
521 }
522 
523 ////////////////////////////////////////////////////////////////////////////////
524 /// destructor for TXMLEngine object
525 
526 TXMLEngine::~TXMLEngine()
527 {
528 }
529 
530 ////////////////////////////////////////////////////////////////////////////////
531 /// checks if node has attribute of specified name
532 
533 Bool_t TXMLEngine::HasAttr(XMLNodePointer_t xmlnode, const char *name)
534 {
535  if ((xmlnode == 0) || (name == 0))
536  return kFALSE;
537  SXmlAttr_t *attr = ((SXmlNode_t *)xmlnode)->fAttr;
538  while (attr != 0) {
539  if (strcmp(SXmlAttr_t::Name(attr), name) == 0)
540  return kTRUE;
541  attr = attr->fNext;
542  }
543  return kFALSE;
544 }
545 
546 ////////////////////////////////////////////////////////////////////////////////
547 /// returns value of attribute for xmlnode
548 
549 const char *TXMLEngine::GetAttr(XMLNodePointer_t xmlnode, const char *name)
550 {
551  if (xmlnode == 0)
552  return 0;
553  SXmlAttr_t *attr = ((SXmlNode_t *)xmlnode)->fAttr;
554  while (attr != 0) {
555  if (strcmp(SXmlAttr_t::Name(attr), name) == 0)
556  return SXmlAttr_t::Name(attr) + strlen(name) + 1;
557  attr = attr->fNext;
558  }
559  return 0;
560 }
561 
562 ////////////////////////////////////////////////////////////////////////////////
563 /// returns value of attribute as integer
564 
565 Int_t TXMLEngine::GetIntAttr(XMLNodePointer_t xmlnode, const char *name)
566 {
567  if (xmlnode == 0)
568  return 0;
569  Int_t res = 0;
570  const char *attr = GetAttr(xmlnode, name);
571  if (attr)
572  sscanf(attr, "%d", &res);
573  return res;
574 }
575 
576 ////////////////////////////////////////////////////////////////////////////////
577 /// creates new attribute for xmlnode,
578 /// namespaces are not supported for attributes
579 
580 XMLAttrPointer_t TXMLEngine::NewAttr(XMLNodePointer_t xmlnode, XMLNsPointer_t, const char *name, const char *value)
581 {
582  if (xmlnode == 0)
583  return 0;
584 
585  int namelen(name != 0 ? strlen(name) : 0);
586  int valuelen(value != 0 ? strlen(value) : 0);
587  SXmlAttr_t *attr = (SXmlAttr_t *)AllocateAttr(namelen, valuelen, xmlnode);
588 
589  char *attrname = SXmlAttr_t::Name(attr);
590  if (namelen > 0)
591  strncpy(attrname, name, namelen + 1);
592  else
593  *attrname = 0;
594  attrname += (namelen + 1);
595  if (valuelen > 0)
596  strncpy(attrname, value, valuelen + 1);
597  else
598  *attrname = 0;
599 
600  return (XMLAttrPointer_t)attr;
601 }
602 
603 ////////////////////////////////////////////////////////////////////////////////
604 /// create node attribute with integer value
605 
606 XMLAttrPointer_t TXMLEngine::NewIntAttr(XMLNodePointer_t xmlnode, const char *name, Int_t value)
607 {
608  char sbuf[30];
609  sprintf(sbuf, "%d", value);
610  return NewAttr(xmlnode, 0, name, sbuf);
611 }
612 
613 ////////////////////////////////////////////////////////////////////////////////
614 /// remove attribute from xmlnode
615 
616 void TXMLEngine::FreeAttr(XMLNodePointer_t xmlnode, const char *name)
617 {
618  if (xmlnode == 0)
619  return;
620  SXmlAttr_t *attr = ((SXmlNode_t *)xmlnode)->fAttr;
621  SXmlAttr_t *prev = 0;
622  while (attr != 0) {
623  if (strcmp(SXmlAttr_t::Name(attr), name) == 0) {
624  if (prev != 0)
625  prev->fNext = attr->fNext;
626  else
627  ((SXmlNode_t *)xmlnode)->fAttr = attr->fNext;
628  // fNumNodes--;
629  free(attr);
630  return;
631  }
632 
633  prev = attr;
634  attr = attr->fNext;
635  }
636 }
637 
638 ////////////////////////////////////////////////////////////////////////////////
639 /// Free all attributes of the node
640 
641 void TXMLEngine::FreeAllAttr(XMLNodePointer_t xmlnode)
642 {
643  if (xmlnode == 0)
644  return;
645 
646  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
647  SXmlAttr_t *attr = node->fAttr;
648  while (attr != 0) {
649  SXmlAttr_t *next = attr->fNext;
650  free(attr);
651  attr = next;
652  }
653  node->fAttr = 0;
654 }
655 
656 ////////////////////////////////////////////////////////////////////////////////
657 /// return first attribute in the list, namespace (if exists) will be skipped
658 
659 XMLAttrPointer_t TXMLEngine::GetFirstAttr(XMLNodePointer_t xmlnode)
660 {
661  if (xmlnode == 0)
662  return 0;
663  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
664 
665  SXmlAttr_t *attr = node->fAttr;
666  if ((attr != 0) && (node->fNs == attr))
667  attr = attr->fNext;
668 
669  return (XMLAttrPointer_t)attr;
670 }
671 
672 ////////////////////////////////////////////////////////////////////////////////
673 /// return next attribute in the list
674 
675 XMLAttrPointer_t TXMLEngine::GetNextAttr(XMLAttrPointer_t xmlattr)
676 {
677  if (xmlattr == 0)
678  return 0;
679 
680  return (XMLAttrPointer_t)((SXmlAttr_t *)xmlattr)->fNext;
681 }
682 
683 ////////////////////////////////////////////////////////////////////////////////
684 /// return name of the attribute
685 
686 const char *TXMLEngine::GetAttrName(XMLAttrPointer_t xmlattr)
687 {
688  if (xmlattr == 0)
689  return 0;
690 
691  return SXmlAttr_t::Name(xmlattr);
692 }
693 
694 ////////////////////////////////////////////////////////////////////////////////
695 /// return value of attribute
696 
697 const char *TXMLEngine::GetAttrValue(XMLAttrPointer_t xmlattr)
698 {
699  if (xmlattr == 0)
700  return 0;
701 
702  const char *attrname = SXmlAttr_t::Name(xmlattr);
703  return attrname + strlen(attrname) + 1;
704 }
705 
706 ////////////////////////////////////////////////////////////////////////////////
707 /// create new child element for parent node
708 
709 XMLNodePointer_t TXMLEngine::NewChild(XMLNodePointer_t parent, XMLNsPointer_t ns, const char *name, const char *content)
710 {
711  int namelen(name != 0 ? strlen(name) : 0);
712 
713  SXmlNode_t *node = (SXmlNode_t *)AllocateNode(namelen, parent);
714 
715  if (namelen > 0)
716  strncpy(SXmlNode_t::Name(node), name, namelen + 1);
717  else
718  *SXmlNode_t::Name(node) = 0;
719 
720  node->fNs = (SXmlAttr_t *)ns;
721  int contlen = (content != 0) ? strlen(content) : 0;
722  if (contlen > 0) {
723  SXmlNode_t *contnode = (SXmlNode_t *)AllocateNode(contlen, node);
724  contnode->fType = kXML_CONTENT; // indicate that we creating content node
725  strncpy(SXmlNode_t::Name(contnode), content, contlen + 1);
726  }
727 
728  return (XMLNodePointer_t)node;
729 }
730 
731 ////////////////////////////////////////////////////////////////////////////////
732 /// create namespace attribute for xmlnode.
733 /// namespace attribute will be always the first in list of node attributes
734 
735 XMLNsPointer_t TXMLEngine::NewNS(XMLNodePointer_t xmlnode, const char *reference, const char *name)
736 {
737  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
738  if (name == 0)
739  name = SXmlNode_t::Name(node);
740  int namelen = strlen(name);
741  char *nsname = new char[namelen + 7];
742  snprintf(nsname, namelen + 7, "xmlns:%s", name);
743 
744  SXmlAttr_t *first = node->fAttr;
745  node->fAttr = 0;
746 
747  SXmlAttr_t *nsattr = (SXmlAttr_t *)NewAttr(xmlnode, 0, nsname, reference);
748 
749  node->fAttr = nsattr;
750  nsattr->fNext = first;
751 
752  node->fNs = nsattr;
753  delete[] nsname;
754  return (XMLNsPointer_t)nsattr;
755 }
756 
757 ////////////////////////////////////////////////////////////////////////////////
758 /// return namespace attribute (if exists)
759 
760 XMLNsPointer_t TXMLEngine::GetNS(XMLNodePointer_t xmlnode)
761 {
762  if (xmlnode == 0)
763  return 0;
764  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
765 
766  return (XMLNsPointer_t)node->fNs;
767 }
768 
769 ////////////////////////////////////////////////////////////////////////////////
770 /// return name id of namespace
771 
772 const char *TXMLEngine::GetNSName(XMLNsPointer_t ns)
773 {
774  const char *nsname = GetAttrName((XMLAttrPointer_t)ns);
775 
776  if ((nsname != 0) && (strncmp(nsname, "xmlns:", 6) == 0))
777  nsname += 6;
778 
779  return nsname;
780 }
781 
782 ////////////////////////////////////////////////////////////////////////////////
783 /// return reference id of namespace
784 
785 const char *TXMLEngine::GetNSReference(XMLNsPointer_t ns)
786 {
787  return GetAttrValue((XMLAttrPointer_t)ns);
788 }
789 
790 ////////////////////////////////////////////////////////////////////////////////
791 /// add child element to xmlnode
792 
793 void TXMLEngine::AddChild(XMLNodePointer_t parent, XMLNodePointer_t child)
794 {
795  if ((parent == 0) || (child == 0))
796  return;
797  SXmlNode_t *pnode = (SXmlNode_t *)parent;
798  SXmlNode_t *cnode = (SXmlNode_t *)child;
799 
800  if (cnode->fParent)
801  UnlinkNode(child);
802 
803  cnode->fParent = pnode;
804  if (pnode->fLastChild == 0) {
805  pnode->fChild = cnode;
806  pnode->fLastChild = cnode;
807  } else {
808  // SXmlNode_t* ch = pnode->fChild;
809  // while (ch->fNext!=0) ch=ch->fNext;
810  pnode->fLastChild->fNext = cnode;
811  pnode->fLastChild = cnode;
812  }
813 }
814 
815 ////////////////////////////////////////////////////////////////////////////////
816 /// add node as first child
817 
818 void TXMLEngine::AddChildFirst(XMLNodePointer_t parent, XMLNodePointer_t child)
819 {
820  if ((parent == 0) || (child == 0))
821  return;
822  SXmlNode_t *pnode = (SXmlNode_t *)parent;
823  SXmlNode_t *cnode = (SXmlNode_t *)child;
824 
825  if (cnode->fParent)
826  UnlinkNode(child);
827 
828  cnode->fParent = pnode;
829 
830  cnode->fNext = pnode->fChild;
831  pnode->fChild = cnode;
832 
833  if (pnode->fLastChild == 0)
834  pnode->fLastChild = cnode;
835 }
836 
837 ////////////////////////////////////////////////////////////////////////////////
838 /// Insert new child node after already existing node
839 
840 void TXMLEngine::AddChildAfter(XMLNodePointer_t parent, XMLNodePointer_t child, XMLNodePointer_t afternode)
841 {
842  if (afternode == 0) {
843  AddChild(parent, child);
844  return;
845  }
846 
847  SXmlNode_t *pnode = (SXmlNode_t *)parent;
848  SXmlNode_t *cnode = (SXmlNode_t *)child;
849  SXmlNode_t *anode = (SXmlNode_t *)afternode;
850 
851  if (anode->fParent != pnode) {
852  Error("InsertChildAfter", "Specified afternode is not in childs list of parent node");
853  AddChild(parent, child);
854  return;
855  }
856 
857  if (cnode->fParent)
858  UnlinkNode(child);
859 
860  cnode->fParent = pnode;
861 
862  cnode->fNext = anode->fNext;
863  anode->fNext = cnode;
864 
865  if (pnode->fLastChild == anode)
866  pnode->fLastChild = cnode;
867 }
868 
869 ////////////////////////////////////////////////////////////////////////////////
870 /// Adds comment line to the node
871 
872 Bool_t TXMLEngine::AddComment(XMLNodePointer_t xmlnode, const char *comment)
873 {
874  if ((xmlnode == 0) || (comment == 0))
875  return kFALSE;
876 
877  int commentlen = strlen(comment);
878 
879  SXmlNode_t *node = (SXmlNode_t *)AllocateNode(commentlen, xmlnode);
880  node->fType = kXML_COMMENT;
881  strncpy(SXmlNode_t::Name(node), comment, commentlen + 1);
882 
883  return kTRUE;
884 }
885 
886 ////////////////////////////////////////////////////////////////////////////////
887 /// add comment line to the top of the document
888 
889 Bool_t TXMLEngine::AddDocComment(XMLDocPointer_t xmldoc, const char *comment)
890 {
891  if (xmldoc == 0)
892  return kFALSE;
893 
894  XMLNodePointer_t rootnode = DocGetRootElement(xmldoc);
895  UnlinkNode(rootnode);
896 
897  Bool_t res = AddComment(((SXmlDoc_t *)xmldoc)->fRootNode, comment);
898 
899  AddChild((XMLNodePointer_t)((SXmlDoc_t *)xmldoc)->fRootNode, rootnode);
900 
901  return res;
902 }
903 
904 ////////////////////////////////////////////////////////////////////////////////
905 /// Add just line into xml file
906 /// Line should has correct xml syntax that later it can be decoded by xml parser
907 /// For instance, it can be comment or processing instructions
908 
909 Bool_t TXMLEngine::AddRawLine(XMLNodePointer_t xmlnode, const char *line)
910 {
911  if ((xmlnode == 0) || (line == 0))
912  return kFALSE;
913 
914  int linelen = strlen(line);
915  SXmlNode_t *node = (SXmlNode_t *)AllocateNode(linelen, xmlnode);
916  node->fType = kXML_RAWLINE;
917  strncpy(SXmlNode_t::Name(node), line, linelen + 1);
918 
919  return kTRUE;
920 }
921 
922 ////////////////////////////////////////////////////////////////////////////////
923 /// Add just line on the top of xml document
924 /// Line should has correct xml syntax that later it can be decoded by xml parser
925 
926 Bool_t TXMLEngine::AddDocRawLine(XMLDocPointer_t xmldoc, const char *line)
927 {
928  XMLNodePointer_t rootnode = DocGetRootElement(xmldoc);
929  UnlinkNode(rootnode);
930 
931  Bool_t res = AddRawLine(((SXmlDoc_t *)xmldoc)->fRootNode, line);
932 
933  AddChild((XMLNodePointer_t)((SXmlDoc_t *)xmldoc)->fRootNode, rootnode);
934 
935  return res;
936 }
937 
938 ////////////////////////////////////////////////////////////////////////////////
939 /// Adds style sheet definition to the specified node
940 /// Creates <?xml-stylesheet alternate="yes" title="compact" href="small-base.css" type="text/css"?>
941 /// Attributes href and type must be supplied,
942 /// other attributes: title, alternate, media, charset are optional
943 /// if alternate==0, attribute alternate="no" will be created,
944 /// if alternate>0, attribute alternate="yes"
945 /// if alternate<0, attribute will not be created
946 
947 Bool_t TXMLEngine::AddStyleSheet(XMLNodePointer_t xmlnode, const char *href, const char *type, const char *title,
948  int alternate, const char *media, const char *charset)
949 {
950  if ((xmlnode == 0) || (href == 0) || (type == 0))
951  return kFALSE;
952 
953  const char *nodename = "xml-stylesheet";
954  int nodenamelen = strlen(nodename);
955 
956  SXmlNode_t *node = (SXmlNode_t *)AllocateNode(nodenamelen, xmlnode);
957  node->fType = kXML_PI_NODE;
958  strncpy(SXmlNode_t::Name(node), nodename, nodenamelen + 1);
959 
960  if (alternate >= 0)
961  NewAttr(node, 0, "alternate", (alternate > 0) ? "yes" : "no");
962 
963  if (title != 0)
964  NewAttr(node, 0, "title", title);
965 
966  NewAttr(node, 0, "href", href);
967  NewAttr(node, 0, "type", type);
968 
969  if (media != 0)
970  NewAttr(node, 0, "media", media);
971  if (charset != 0)
972  NewAttr(node, 0, "charset", charset);
973 
974  return kTRUE;
975 }
976 
977 ////////////////////////////////////////////////////////////////////////////////
978 /// Add style sheet definition on the top of document
979 
980 Bool_t TXMLEngine::AddDocStyleSheet(XMLDocPointer_t xmldoc, const char *href, const char *type, const char *title,
981  int alternate, const char *media, const char *charset)
982 {
983  if (xmldoc == 0)
984  return kFALSE;
985 
986  XMLNodePointer_t rootnode = DocGetRootElement(xmldoc);
987  UnlinkNode(rootnode);
988 
989  Bool_t res = AddStyleSheet(((SXmlDoc_t *)xmldoc)->fRootNode, href, type, title, alternate, media, charset);
990 
991  AddChild((XMLNodePointer_t)((SXmlDoc_t *)xmldoc)->fRootNode, rootnode);
992 
993  return res;
994 }
995 
996 ////////////////////////////////////////////////////////////////////////////////
997 /// unlink (detach) xmlnode from parent
998 
999 void TXMLEngine::UnlinkNode(XMLNodePointer_t xmlnode)
1000 {
1001  if (xmlnode == 0)
1002  return;
1003 
1004  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
1005  SXmlNode_t *parent = node->fParent;
1006 
1007  if (parent == 0)
1008  return;
1009 
1010  if (parent->fChild == node) {
1011  parent->fChild = node->fNext;
1012  if (parent->fLastChild == node)
1013  parent->fLastChild = node->fNext;
1014  } else {
1015  SXmlNode_t *ch = parent->fChild;
1016  while (ch->fNext != node)
1017  ch = ch->fNext;
1018  ch->fNext = node->fNext;
1019  if (parent->fLastChild == node)
1020  parent->fLastChild = ch;
1021  }
1022 
1023  node->fParent = 0;
1024  node->fNext = 0;
1025 }
1026 
1027 ////////////////////////////////////////////////////////////////////////////////
1028 /// release all memory, allocated from this node and
1029 /// destroys node itself
1030 
1031 void TXMLEngine::FreeNode(XMLNodePointer_t xmlnode)
1032 {
1033  if (xmlnode == 0)
1034  return;
1035  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
1036 
1037  SXmlNode_t *child = node->fChild;
1038  while (child != 0) {
1039  SXmlNode_t *next = child->fNext;
1040  FreeNode((XMLNodePointer_t)child);
1041  child = next;
1042  }
1043 
1044  SXmlAttr_t *attr = node->fAttr;
1045  while (attr != 0) {
1046  SXmlAttr_t *next = attr->fNext;
1047  // fNumNodes--;
1048  free(attr);
1049  attr = next;
1050  }
1051 
1052  free(node);
1053 
1054  // fNumNodes--;
1055 }
1056 
1057 ////////////////////////////////////////////////////////////////////////////////
1058 /// combined operation. Unlink node and free used memory
1059 
1060 void TXMLEngine::UnlinkFreeNode(XMLNodePointer_t xmlnode)
1061 {
1062  UnlinkNode(xmlnode);
1063  FreeNode(xmlnode);
1064 }
1065 
1066 ////////////////////////////////////////////////////////////////////////////////
1067 /// returns name of xmlnode
1068 
1069 const char *TXMLEngine::GetNodeName(XMLNodePointer_t xmlnode)
1070 {
1071  return xmlnode == 0 ? 0 : SXmlNode_t::Name(xmlnode);
1072 }
1073 
1074 ////////////////////////////////////////////////////////////////////////////////
1075 /// get contents (if any) of xmlnode
1076 
1077 const char *TXMLEngine::GetNodeContent(XMLNodePointer_t xmlnode)
1078 {
1079  if (xmlnode == 0)
1080  return 0;
1081  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
1082  if (node->fChild == 0)
1083  return 0;
1084 
1085  if (node->fChild->fType != kXML_CONTENT)
1086  return 0;
1087 
1088  return SXmlNode_t::Name(node->fChild);
1089 }
1090 
1091 ////////////////////////////////////////////////////////////////////////////////
1092 /// set content of the xmlnode
1093 /// if old node content was exists, it will be replaced
1094 
1095 void TXMLEngine::SetNodeContent(XMLNodePointer_t xmlnode, const char *content, Int_t len)
1096 {
1097  if (xmlnode == 0)
1098  return;
1099  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
1100  if ((node->fChild != 0) && (node->fChild->fType == kXML_CONTENT))
1101  UnlinkFreeNode((XMLNodePointer_t)node->fChild);
1102 
1103  if (content == 0)
1104  return;
1105  if (len <= 0)
1106  len = strlen(content);
1107 
1108  SXmlNode_t *contnode = (SXmlNode_t *)AllocateNode(len, 0);
1109  char *nameptr = SXmlNode_t::Name(contnode);
1110  contnode->fType = kXML_CONTENT;
1111  strncpy(nameptr, content, len);
1112  nameptr += len;
1113  *nameptr = 0; // here we add padding 0 to get normal string
1114 
1115  AddChildFirst(xmlnode, (XMLNodePointer_t)contnode);
1116 }
1117 
1118 ////////////////////////////////////////////////////////////////////////////////
1119 /// add new content of the xmlnode
1120 /// old content will be preserved, one could mix content with child nodes
1121 
1122 void TXMLEngine::AddNodeContent(XMLNodePointer_t xmlnode, const char *content, Int_t len)
1123 {
1124  if ((xmlnode == 0) || (content == 0))
1125  return;
1126  if (len <= 0)
1127  len = strlen(content);
1128 
1129  SXmlNode_t *contnode = (SXmlNode_t *)AllocateNode(len, xmlnode);
1130  char *nameptr = SXmlNode_t::Name(contnode);
1131  contnode->fType = kXML_CONTENT;
1132  strncpy(nameptr, content, len);
1133  nameptr += len;
1134  *nameptr = 0; // here we add padding 0 to get normal string
1135 }
1136 
1137 ////////////////////////////////////////////////////////////////////////////////
1138 /// returns first child of xmlnode
1139 
1140 XMLNodePointer_t TXMLEngine::GetChild(XMLNodePointer_t xmlnode, Bool_t realnode)
1141 {
1142  XMLNodePointer_t res = xmlnode == 0 ? 0 : ((SXmlNode_t *)xmlnode)->fChild;
1143  // skip content(s) node, if specified
1144  if (realnode && (res != 0) && (((SXmlNode_t *)res)->fType != kXML_NODE))
1145  ShiftToNext(res, kTRUE);
1146  return res;
1147 }
1148 
1149 ////////////////////////////////////////////////////////////////////////////////
1150 /// returns parent of xmlnode
1151 
1152 XMLNodePointer_t TXMLEngine::GetParent(XMLNodePointer_t xmlnode)
1153 {
1154  return xmlnode == 0 ? 0 : (XMLNodePointer_t)((SXmlNode_t *)xmlnode)->fParent;
1155 }
1156 
1157 ////////////////////////////////////////////////////////////////////////////////
1158 /// return next to xmlnode node
1159 /// if realnode==kTRUE, any special nodes in between will be skipped
1160 
1161 XMLNodePointer_t TXMLEngine::GetNext(XMLNodePointer_t xmlnode, Bool_t realnode)
1162 {
1163  do {
1164  xmlnode = xmlnode == 0 ? 0 : (XMLNodePointer_t)((SXmlNode_t *)xmlnode)->fNext;
1165  if ((xmlnode == 0) || !realnode)
1166  return xmlnode;
1167  } while (((SXmlNode_t *)xmlnode)->fType != kXML_NODE);
1168 
1169  return xmlnode;
1170 }
1171 
1172 ////////////////////////////////////////////////////////////////////////////////
1173 /// shifts specified node to next
1174 /// if realnode==kTRUE, any special nodes in between will be skipped
1175 
1176 void TXMLEngine::ShiftToNext(XMLNodePointer_t &xmlnode, Bool_t realnode)
1177 {
1178  do {
1179  xmlnode = xmlnode == 0 ? 0 : (XMLNodePointer_t)((SXmlNode_t *)xmlnode)->fNext;
1180  if ((xmlnode == 0) || !realnode)
1181  return;
1182  } while (((SXmlNode_t *)xmlnode)->fType != kXML_NODE);
1183 }
1184 
1185 ////////////////////////////////////////////////////////////////////////////////
1186 /// return kTRUE is this is normal xmlnode
1187 
1188 Bool_t TXMLEngine::IsXmlNode(XMLNodePointer_t xmlnode)
1189 {
1190  return xmlnode == 0 ? kFALSE : (((SXmlNode_t *)xmlnode)->fType == kXML_NODE);
1191 }
1192 
1193 ////////////////////////////////////////////////////////////////////////////////
1194 /// return kTRUE is this is node with special data like comments to data processing instructions
1195 
1196 Bool_t TXMLEngine::IsEmptyNode(XMLNodePointer_t xmlnode)
1197 {
1198  return xmlnode == 0 ? kTRUE : (((SXmlNode_t *)xmlnode)->fType != kXML_NODE);
1199 }
1200 
1201 ////////////////////////////////////////////////////////////////////////////////
1202 /// return kTRUE is this is special node with content
1203 
1204 Bool_t TXMLEngine::IsContentNode(XMLNodePointer_t xmlnode)
1205 {
1206  return xmlnode == 0 ? kFALSE : (((SXmlNode_t *)xmlnode)->fType == kXML_CONTENT);
1207 }
1208 
1209 ////////////////////////////////////////////////////////////////////////////////
1210 /// return kTRUE is this is special node with content
1211 
1212 Bool_t TXMLEngine::IsCommentNode(XMLNodePointer_t xmlnode)
1213 {
1214  return xmlnode == 0 ? kFALSE : (((SXmlNode_t *)xmlnode)->fType == kXML_COMMENT);
1215 }
1216 
1217 ////////////////////////////////////////////////////////////////////////////////
1218 /// Skip all current empty nodes and locate on first "true" node
1219 
1220 void TXMLEngine::SkipEmpty(XMLNodePointer_t &xmlnode)
1221 {
1222  if (IsEmptyNode(xmlnode))
1223  ShiftToNext(xmlnode);
1224 }
1225 
1226 ////////////////////////////////////////////////////////////////////////////////
1227 /// remove all children node from xmlnode
1228 
1229 void TXMLEngine::CleanNode(XMLNodePointer_t xmlnode)
1230 {
1231  if (xmlnode == 0)
1232  return;
1233  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
1234 
1235  SXmlNode_t *child = node->fChild;
1236  while (child != 0) {
1237  SXmlNode_t *next = child->fNext;
1238  FreeNode((XMLNodePointer_t)child);
1239  child = next;
1240  }
1241 
1242  node->fChild = 0;
1243  node->fLastChild = 0;
1244 }
1245 
1246 ////////////////////////////////////////////////////////////////////////////////
1247 /// creates new xml document with provided version
1248 
1249 XMLDocPointer_t TXMLEngine::NewDoc(const char *version)
1250 {
1251  SXmlDoc_t *doc = new SXmlDoc_t;
1252  doc->fRootNode = (SXmlNode_t *)NewChild(0, 0, "??DummyTopNode??", 0);
1253 
1254  if (version != 0) {
1255  XMLNodePointer_t vernode = NewChild((XMLNodePointer_t)doc->fRootNode, 0, "xml");
1256  ((SXmlNode_t *)vernode)->fType = kXML_PI_NODE;
1257  NewAttr(vernode, 0, "version", version);
1258  }
1259 
1260  doc->fDtdName = 0;
1261  doc->fDtdRoot = 0;
1262  return (XMLDocPointer_t)doc;
1263 }
1264 
1265 ////////////////////////////////////////////////////////////////////////////////
1266 /// assigns dtd filename to document
1267 
1268 void TXMLEngine::AssignDtd(XMLDocPointer_t xmldoc, const char *dtdname, const char *rootname)
1269 {
1270  if (xmldoc == 0)
1271  return;
1272  SXmlDoc_t *doc = (SXmlDoc_t *)xmldoc;
1273  delete[] doc->fDtdName;
1274  doc->fDtdName = Makestr(dtdname);
1275  delete[] doc->fDtdRoot;
1276  doc->fDtdRoot = Makestr(rootname);
1277 }
1278 
1279 ////////////////////////////////////////////////////////////////////////////////
1280 /// frees allocated document data and deletes document itself
1281 
1282 void TXMLEngine::FreeDoc(XMLDocPointer_t xmldoc)
1283 {
1284  if (xmldoc == 0)
1285  return;
1286  SXmlDoc_t *doc = (SXmlDoc_t *)xmldoc;
1287  FreeNode((XMLNodePointer_t)doc->fRootNode);
1288  delete[] doc->fDtdName;
1289  delete[] doc->fDtdRoot;
1290  delete doc;
1291 }
1292 
1293 ////////////////////////////////////////////////////////////////////////////////
1294 /// store document content to file
1295 /// if layout<=0, no any spaces or newlines will be placed between
1296 /// xmlnodes. Xml file will have minimum size, but non-readable structure
1297 /// if (layout>0) each node will be started from new line,
1298 /// and number of spaces will correspond to structure depth.
1299 
1300 void TXMLEngine::SaveDoc(XMLDocPointer_t xmldoc, const char *filename, Int_t layout)
1301 {
1302  if (xmldoc == 0)
1303  return;
1304 
1305  SXmlDoc_t *doc = (SXmlDoc_t *)xmldoc;
1306 
1307  TXMLOutputStream out(filename, 100000);
1308 
1309  XMLNodePointer_t child = GetChild((XMLNodePointer_t)doc->fRootNode, kFALSE);
1310 
1311  do {
1312  SaveNode(child, &out, layout, 0);
1313  ShiftToNext(child, kFALSE);
1314  } while (child != 0);
1315 }
1316 
1317 ////////////////////////////////////////////////////////////////////////////////
1318 /// set main (root) node for document
1319 
1320 void TXMLEngine::DocSetRootElement(XMLDocPointer_t xmldoc, XMLNodePointer_t xmlnode)
1321 {
1322  if (xmldoc == 0)
1323  return;
1324 
1325  FreeNode(DocGetRootElement(xmldoc));
1326 
1327  AddChild((XMLNodePointer_t)((SXmlDoc_t *)xmldoc)->fRootNode, xmlnode);
1328 }
1329 
1330 ////////////////////////////////////////////////////////////////////////////////
1331 /// returns root node of document
1332 
1333 XMLNodePointer_t TXMLEngine::DocGetRootElement(XMLDocPointer_t xmldoc)
1334 {
1335  if (xmldoc == 0)
1336  return 0;
1337 
1338  XMLNodePointer_t xmlnode = (XMLNodePointer_t)((SXmlDoc_t *)xmldoc)->fRootNode;
1339 
1340  // typically first child of XML document is version
1341  // therefore just skip it when returning root node of document
1342  return GetChild(xmlnode, kTRUE);
1343 }
1344 
1345 ////////////////////////////////////////////////////////////////////////////////
1346 /// Parses content of file and tries to produce xml structures.
1347 /// The maxbuf argument specifies the max size of the XML file to be
1348 /// parsed. The default value is 100000.
1349 
1350 XMLDocPointer_t TXMLEngine::ParseFile(const char *filename, Int_t maxbuf)
1351 {
1352  if ((filename == 0) || (strlen(filename) == 0))
1353  return 0;
1354  if (maxbuf < 100000)
1355  maxbuf = 100000;
1356  TXMLInputStream inp(true, filename, maxbuf);
1357  return ParseStream(&inp);
1358 }
1359 
1360 ////////////////////////////////////////////////////////////////////////////////
1361 /// parses content of string and tries to produce xml structures
1362 
1363 XMLDocPointer_t TXMLEngine::ParseString(const char *xmlstring)
1364 {
1365  if ((xmlstring == 0) || (strlen(xmlstring) == 0))
1366  return 0;
1367  TXMLInputStream inp(false, xmlstring, 100000);
1368  return ParseStream(&inp);
1369 }
1370 
1371 ////////////////////////////////////////////////////////////////////////////////
1372 /// parses content of the stream and tries to produce xml structures
1373 
1374 XMLDocPointer_t TXMLEngine::ParseStream(TXMLInputStream *inp)
1375 {
1376  if (inp == 0)
1377  return 0;
1378 
1379  XMLDocPointer_t xmldoc = NewDoc(0);
1380 
1381  Bool_t success = false;
1382 
1383  Int_t resvalue = 0;
1384 
1385  do {
1386  ReadNode(((SXmlDoc_t *)xmldoc)->fRootNode, inp, resvalue);
1387 
1388  if (resvalue != 2)
1389  break;
1390 
1391  // coverity[unchecked_value] at this place result of SkipSpaces() doesn't matter - either file is finished (false)
1392  // or there is some more nodes to analyse (true)
1393  if (!inp->EndOfStream())
1394  inp->SkipSpaces();
1395 
1396  if (inp->EndOfStream()) {
1397  success = true;
1398  break;
1399  }
1400  } while (true);
1401 
1402  if (!success) {
1403  DisplayError(resvalue, inp->CurrentLine());
1404  FreeDoc(xmldoc);
1405  return 0;
1406  }
1407 
1408  return xmldoc;
1409 }
1410 
1411 ////////////////////////////////////////////////////////////////////////////////
1412 /// check that first node is xml processing instruction with correct xml version number
1413 
1414 Bool_t TXMLEngine::ValidateVersion(XMLDocPointer_t xmldoc, const char *version)
1415 {
1416  if (xmldoc == 0)
1417  return kFALSE;
1418 
1419  XMLNodePointer_t vernode = GetChild((XMLNodePointer_t)((SXmlDoc_t *)xmldoc)->fRootNode, kFALSE);
1420  if (vernode == 0)
1421  return kFALSE;
1422 
1423  if (((SXmlNode_t *)vernode)->fType != kXML_PI_NODE)
1424  return kFALSE;
1425  if (strcmp(GetNodeName(vernode), "xml") != 0)
1426  return kFALSE;
1427 
1428  const char *value = GetAttr(vernode, "version");
1429  if (value == 0)
1430  return kFALSE;
1431  if (version == 0)
1432  version = "1.0";
1433 
1434  return strcmp(version, value) == 0;
1435 }
1436 
1437 ////////////////////////////////////////////////////////////////////////////////
1438 /// convert single xmlnode (and its child node) to string
1439 /// if layout<=0, no any spaces or newlines will be placed between
1440 /// xmlnodes. Xml file will have minimum size, but non-readable structure
1441 /// if (layout>0) each node will be started from new line,
1442 /// and number of spaces will correspond to structure depth.
1443 
1444 void TXMLEngine::SaveSingleNode(XMLNodePointer_t xmlnode, TString *res, Int_t layout)
1445 {
1446  if ((res == 0) || (xmlnode == 0))
1447  return;
1448 
1449  TXMLOutputStream out(res, 10000);
1450 
1451  SaveNode(xmlnode, &out, layout, 0);
1452 }
1453 
1454 ////////////////////////////////////////////////////////////////////////////////
1455 /// read single xmlnode from provided string
1456 
1457 XMLNodePointer_t TXMLEngine::ReadSingleNode(const char *src)
1458 {
1459  if (src == 0)
1460  return 0;
1461 
1462  TXMLInputStream inp(false, src, 10000);
1463 
1464  Int_t resvalue;
1465 
1466  XMLNodePointer_t xmlnode = ReadNode(0, &inp, resvalue);
1467 
1468  if (resvalue <= 0) {
1469  DisplayError(resvalue, inp.CurrentLine());
1470  FreeNode(xmlnode);
1471  return 0;
1472  }
1473 
1474  return xmlnode;
1475 }
1476 
1477 ////////////////////////////////////////////////////////////////////////////////
1478 /// creates char* variable with copy of provided string
1479 
1480 char *TXMLEngine::Makestr(const char *str)
1481 {
1482  if (str == 0)
1483  return 0;
1484  int len = strlen(str);
1485  if (len == 0)
1486  return 0;
1487  char *res = new char[len + 1];
1488  strncpy(res, str, len + 1);
1489  return res;
1490 }
1491 
1492 ////////////////////////////////////////////////////////////////////////////////
1493 /// creates char* variable with copy of len symbols from provided string
1494 
1495 char *TXMLEngine::Makenstr(const char *str, int len)
1496 {
1497  if ((str == 0) || (len == 0))
1498  return 0;
1499  char *res = new char[len + 1];
1500  strncpy(res, str, len);
1501  *(res + len) = 0;
1502  return res;
1503 }
1504 
1505 ////////////////////////////////////////////////////////////////////////////////
1506 /// Allocates new xml node with specified name length
1507 
1508 XMLNodePointer_t TXMLEngine::AllocateNode(int namelen, XMLNodePointer_t parent)
1509 {
1510  // fNumNodes++;
1511 
1512  SXmlNode_t *node = (SXmlNode_t *)malloc(sizeof(SXmlNode_t) + namelen + 1);
1513 
1514  node->fType = kXML_NODE;
1515  node->fParent = 0;
1516  node->fNs = 0;
1517  node->fAttr = 0;
1518  node->fChild = 0;
1519  node->fLastChild = 0;
1520  node->fNext = 0;
1521 
1522  if (parent != 0)
1523  AddChild(parent, (XMLNodePointer_t)node);
1524 
1525  return (XMLNodePointer_t)node;
1526 }
1527 
1528 ////////////////////////////////////////////////////////////////////////////////
1529 /// Allocate new attribute with specified name length and value length
1530 
1531 XMLAttrPointer_t TXMLEngine::AllocateAttr(int namelen, int valuelen, XMLNodePointer_t xmlnode)
1532 {
1533  // fNumNodes++;
1534 
1535  SXmlAttr_t *attr = (SXmlAttr_t *)malloc(sizeof(SXmlAttr_t) + namelen + 1 + valuelen + 1);
1536 
1537  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
1538 
1539  attr->fNext = 0;
1540 
1541  if (node->fAttr == 0)
1542  node->fAttr = attr;
1543  else {
1544  SXmlAttr_t *d = node->fAttr;
1545  while (d->fNext != 0)
1546  d = d->fNext;
1547  d->fNext = attr;
1548  }
1549 
1550  return (XMLAttrPointer_t)attr;
1551 }
1552 
1553 ////////////////////////////////////////////////////////////////////////////////
1554 /// define if namespace of that name exists for xmlnode
1555 
1556 XMLNsPointer_t TXMLEngine::FindNs(XMLNodePointer_t xmlnode, const char *name)
1557 {
1558  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
1559  while (node != 0) {
1560  if (node->fNs != 0) {
1561  const char *nsname = SXmlAttr_t::Name(node->fNs) + 6;
1562  if (strcmp(nsname, name) == 0)
1563  return node->fNs;
1564  }
1565  node = node->fParent;
1566  }
1567  return 0;
1568 }
1569 
1570 ////////////////////////////////////////////////////////////////////////////////
1571 /// removes namespace extension of nodename
1572 
1573 void TXMLEngine::TruncateNsExtension(XMLNodePointer_t xmlnode)
1574 {
1575  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
1576  if (node == 0)
1577  return;
1578  char *colon = strchr(SXmlNode_t::Name(node), ':');
1579  if (colon == 0)
1580  return;
1581 
1582  char *copyname = SXmlNode_t::Name(node);
1583 
1584  while (*colon != 0)
1585  *(copyname++) = *(++colon);
1586 }
1587 
1588 ////////////////////////////////////////////////////////////////////////////////
1589 /// unpack special symbols, used in xml syntax to code characters
1590 /// these symbols: '<' - &lt, '>' - &gt, '&' - &amp, '"' - &quot, ''' - &apos
1591 
1592 void TXMLEngine::UnpackSpecialCharacters(char *target, const char *source, int srclen)
1593 {
1594  while (srclen > 0) {
1595  if (*source == '&') {
1596  if ((srclen > 3) && (*(source + 1) == 'l') && (*(source + 2) == 't') && (*(source + 3) == ';')) {
1597  *target++ = '<';
1598  source += 4;
1599  srclen -= 4;
1600  } else if ((srclen > 3) && (*(source + 1) == 'g') && (*(source + 2) == 't') && (*(source + 3) == ';')) {
1601  *target++ = '>';
1602  source += 4;
1603  srclen -= 4;
1604  } else if ((srclen > 4) && (*(source + 1) == 'a') && (*(source + 2) == 'm') && (*(source + 3) == 'p') &&
1605  (*(source + 4) == ';')) {
1606  *target++ = '&';
1607  source += 5;
1608  srclen -= 5;
1609  } else if ((srclen > 5) && (*(source + 1) == 'q') && (*(source + 2) == 'u') && (*(source + 3) == 'o') &&
1610  (*(source + 4) == 't') && (*(source + 5) == ';')) {
1611  *target++ = '\"';
1612  source += 6;
1613  srclen -= 6;
1614  } else if ((srclen > 5) && (*(source + 1) == 'a') && (*(source + 2) == 'p') && (*(source + 3) == 'o') &&
1615  (*(source + 4) == 's') && (*(source + 5) == ';')) {
1616  *target++ = '\'';
1617  source += 6;
1618  srclen -= 6;
1619  } else {
1620  *target++ = *source++;
1621  srclen--;
1622  }
1623  } else {
1624  *target++ = *source++;
1625  srclen--;
1626  }
1627  }
1628  *target = 0;
1629 }
1630 
1631 ////////////////////////////////////////////////////////////////////////////////
1632 /// output value to output stream
1633 /// if symbols '<' '&' '>' '"' ''' appears in the string, they
1634 /// will be encoded to appropriate xml symbols: &lt, &amp, &gt, &quot, &apos
1635 
1636 void TXMLEngine::OutputValue(char *value, TXMLOutputStream *out)
1637 {
1638  if (value == 0)
1639  return;
1640 
1641  char *last = value;
1642  char *find = 0;
1643  while ((find = strpbrk(last, "<&>\"")) != 0) {
1644  char symb = *find;
1645  *find = 0;
1646  out->Write(last);
1647  *find = symb;
1648  last = find + 1;
1649  if (symb == '<')
1650  out->Write("&lt;");
1651  else if (symb == '>')
1652  out->Write("&gt;");
1653  else if (symb == '&')
1654  out->Write("&amp;");
1655  else if (symb == '\'')
1656  out->Write("&apos;");
1657  else
1658  out->Write("&quot;");
1659  }
1660  if (*last != 0)
1661  out->Write(last);
1662 }
1663 
1664 ////////////////////////////////////////////////////////////////////////////////
1665 /// stream data of xmlnode to output
1666 
1667 void TXMLEngine::SaveNode(XMLNodePointer_t xmlnode, TXMLOutputStream *out, Int_t layout, Int_t level)
1668 {
1669  if (xmlnode == 0)
1670  return;
1671  SXmlNode_t *node = (SXmlNode_t *)xmlnode;
1672 
1673  Bool_t issingleline = (node->fChild == 0);
1674 
1675  if (layout > 0)
1676  out->Put(' ', level);
1677 
1678  if (node->fType == kXML_COMMENT) {
1679  out->Write("<!--");
1680  out->Write(SXmlNode_t::Name(node));
1681  out->Write("-->");
1682  if (layout > 0)
1683  out->Put('\n');
1684  return;
1685  } else if (node->fType == kXML_RAWLINE) {
1686  out->Write(SXmlNode_t::Name(node));
1687  if (layout > 0)
1688  out->Put('\n');
1689  return;
1690  } else if (node->fType == kXML_CONTENT) {
1691  out->Write(SXmlNode_t::Name(node));
1692  if (layout > 0)
1693  out->Put('\n');
1694  return;
1695  }
1696 
1697  out->Put('<');
1698  if (node->fType == kXML_PI_NODE)
1699  out->Put('?');
1700 
1701  // we suppose that ns is always first attribute
1702  if ((node->fNs != 0) && (node->fNs != node->fAttr)) {
1703  out->Write(SXmlAttr_t::Name(node->fNs) + 6);
1704  out->Put(':');
1705  }
1706  out->Write(SXmlNode_t::Name(node));
1707 
1708  SXmlAttr_t *attr = node->fAttr;
1709  while (attr != 0) {
1710  out->Put(' ');
1711  char *attrname = SXmlAttr_t::Name(attr);
1712  out->Write(attrname);
1713  out->Write("=\"");
1714  attrname += strlen(attrname) + 1;
1715  OutputValue(attrname, out);
1716  out->Put('\"');
1717  attr = attr->fNext;
1718  }
1719 
1720  // if single line, close node with "/>" and return
1721  if (issingleline) {
1722  if (node->fType == kXML_PI_NODE)
1723  out->Write("?>");
1724  else
1725  out->Write("/>");
1726  if (layout > 0)
1727  out->Put('\n');
1728  return;
1729  }
1730 
1731  out->Put('>');
1732 
1733  SXmlNode_t *child = node->fChild;
1734 
1735  if ((child != 0) && (child->fType == kXML_CONTENT) && (child->fNext == 0)) {
1736  // special case when single content node is exists
1737  out->Write(SXmlNode_t::Name(child));
1738  } else {
1739  if (layout > 0)
1740  out->Put('\n');
1741  while (child != 0) {
1742  SaveNode((XMLNodePointer_t)child, out, layout, level + 2);
1743  child = child->fNext;
1744  }
1745  // add starting spaces before closing node
1746  if (layout > 0)
1747  out->Put(' ', level);
1748  }
1749 
1750  out->Write("</");
1751  // we suppose that ns is always first attribute
1752  if ((node->fNs != 0) && (node->fNs != node->fAttr)) {
1753  out->Write(SXmlAttr_t::Name(node->fNs) + 6);
1754  out->Put(':');
1755  }
1756  out->Write(SXmlNode_t::Name(node));
1757  out->Put('>');
1758  if (layout > 0)
1759  out->Put('\n');
1760 }
1761 
1762 ////////////////////////////////////////////////////////////////////////////////
1763 /// Tries to construct xml node from input stream. Node should be
1764 /// child of xmlparent node or it can be closing tag of xmlparent.
1765 /// resvalue <= 0 if error
1766 /// resvalue == 1 if this is endnode of parent
1767 /// resvalue == 2 if this is child
1768 
1769 XMLNodePointer_t TXMLEngine::ReadNode(XMLNodePointer_t xmlparent, TXMLInputStream *inp, Int_t &resvalue)
1770 {
1771  resvalue = 0;
1772 
1773  if (inp == 0)
1774  return 0;
1775  if (!inp->SkipSpaces()) {
1776  resvalue = -1;
1777  return 0;
1778  }
1779  SXmlNode_t *parent = (SXmlNode_t *)xmlparent;
1780 
1781  SXmlNode_t *node = 0;
1782 
1783  // process comments before we start to analyse any node symbols
1784  while (inp->CheckFor("<!--")) {
1785  Int_t commentlen = inp->SearchFor("-->");
1786  if (commentlen <= 0) {
1787  resvalue = -10;
1788  return 0;
1789  }
1790 
1791  if (!fSkipComments) {
1792  node = (SXmlNode_t *)AllocateNode(commentlen, xmlparent);
1793  char *nameptr = SXmlNode_t::Name(node);
1794  node->fType = kXML_COMMENT;
1795  strncpy(nameptr, inp->fCurrent, commentlen); // here copy only content, there is no padding 0 at the end
1796  nameptr += commentlen;
1797  *nameptr = 0; // here we add padding 0 to get normal string
1798  }
1799 
1800  if (!inp->ShiftCurrent(commentlen + 3)) {
1801  resvalue = -1;
1802  return node;
1803  }
1804  if (!inp->SkipSpaces() && !inp->EndOfStream()) {
1805  resvalue = -1;
1806  return node;
1807  }
1808 
1809  resvalue = 2;
1810  return node;
1811  }
1812 
1813  if (*inp->fCurrent != '<') {
1814  // here should be reading of element content
1815  // now one can have content at any place of the node, also after childs
1816  if (parent == 0) {
1817  resvalue = -2;
1818  return 0;
1819  }
1820  int contlen = inp->LocateContent();
1821  if (contlen < 0)
1822  return 0;
1823 
1824  SXmlNode_t *contnode = (SXmlNode_t *)AllocateNode(contlen, xmlparent);
1825  contnode->fType = kXML_CONTENT;
1826  char *contptr = SXmlNode_t::Name(contnode);
1827  UnpackSpecialCharacters(contptr, inp->fCurrent, contlen);
1828  if (!inp->ShiftCurrent(contlen))
1829  return 0;
1830 
1831  if (inp->NumEntities() <= 0) {
1832  resvalue = 2;
1833  return contnode;
1834  }
1835 
1836  // analyze content on possible includes only when ENTITY was specified for document
1837 
1838  const char *beg(0), *lastentity(0), *curr(contptr);
1839 
1840  while (*curr != 0) {
1841  if ((beg == 0) && (*curr == '&'))
1842  beg = curr;
1843  if ((beg == 0) || (*curr != ';')) {
1844  curr++;
1845  continue;
1846  }
1847 
1848  TXMLEntity *entity = inp->FindEntity(beg + 1, curr - beg - 1);
1849 
1850  if (entity != 0) {
1851 
1852  if (lastentity == 0) {
1853  lastentity = contptr;
1854  UnlinkNode(contnode);
1855  }
1856 
1857  if (lastentity != beg)
1858  AddNodeContent(xmlparent, lastentity, beg - lastentity);
1859 
1860  if (entity->IsSystem()) {
1861  XMLDocPointer_t entitydoc = ParseFile(entity->GetTitle());
1862  if (entitydoc == 0) {
1863  resvalue = -14;
1864  return contnode;
1865  }
1866 
1867  XMLNodePointer_t topnode = DocGetRootElement(entitydoc);
1868 
1869  while (topnode != 0) {
1870  XMLNodePointer_t currnode = topnode;
1871  ShiftToNext(topnode, false);
1872  UnlinkNode(currnode);
1873  AddChild(xmlparent, currnode);
1874  }
1875  } else {
1876  AddNodeContent(xmlparent, entity->GetTitle());
1877  }
1878  }
1879 
1880  beg = 0;
1881  curr++;
1882 
1883  lastentity = curr;
1884  }
1885 
1886  if (lastentity != 0) {
1887  // add rest part of the content
1888  if (strlen(lastentity) > 0)
1889  AddNodeContent(xmlparent, lastentity);
1890  // do not forget to cleanup content node
1891  FreeNode(contnode);
1892  contnode = 0;
1893  }
1894 
1895  resvalue = 2;
1896  return contnode;
1897  } else {
1898  // skip "<" symbol
1899  if (!inp->ShiftCurrent())
1900  return 0;
1901  }
1902 
1903  if (*inp->fCurrent == '/') {
1904  // this is a starting of closing node
1905  if (!inp->ShiftCurrent())
1906  return 0;
1907  if (!inp->SkipSpaces())
1908  return 0;
1909  Int_t len = inp->LocateIdentifier();
1910  if (len <= 0) {
1911  resvalue = -3;
1912  return 0;
1913  }
1914 
1915  if (parent == 0) {
1916  resvalue = -4;
1917  return 0;
1918  }
1919 
1920  if (strncmp(SXmlNode_t::Name(parent), inp->fCurrent, len) != 0) {
1921  resvalue = -5;
1922  return 0;
1923  }
1924 
1925  if (!inp->ShiftCurrent(len))
1926  return 0;
1927 
1928  if (!inp->SkipSpaces())
1929  return 0;
1930  if (*inp->fCurrent != '>')
1931  return 0;
1932  if (!inp->ShiftCurrent())
1933  return 0;
1934 
1935  if (parent->fNs != 0)
1936  TruncateNsExtension((XMLNodePointer_t)parent);
1937 
1938  inp->SkipSpaces(kTRUE); // locate start of next string
1939  resvalue = 1;
1940  return 0;
1941  }
1942 
1943  if (*inp->fCurrent == '!') {
1944  // this is start of DTD reading, only limited number of features are supported
1945  if (!inp->ShiftCurrent())
1946  return 0;
1947  if (!inp->CheckFor("DOCTYPE")) {
1948  resvalue = -12;
1949  return 0;
1950  }
1951  if (!inp->SkipSpaces()) {
1952  resvalue = -13;
1953  return 0;
1954  }
1955 
1956  // now skip name of the root element - it is not verified at all
1957  Int_t len = inp->LocateIdentifier();
1958  if (len <= 0) {
1959  resvalue = -13;
1960  return 0;
1961  }
1962  if (!inp->ShiftCurrent(len)) {
1963  resvalue = -13;
1964  return 0;
1965  }
1966  if (!inp->SkipSpaces()) {
1967  resvalue = -13;
1968  return 0;
1969  }
1970 
1971  // this is start of reading ENTITIES
1972  if (inp->CheckFor("[")) {
1973  if (!inp->SkipSpaces())
1974  return 0;
1975  while (true) {
1976  if (inp->CheckFor("<!ENTITY")) {
1977  // process ENTITY from DTD
1978  if (!inp->SkipSpaces()) {
1979  resvalue = -13;
1980  return 0;
1981  }
1982  Int_t namelen = inp->LocateIdentifier();
1983  if (namelen <= 0) {
1984  resvalue = -13;
1985  return 0;
1986  }
1987  TString entity_name(inp->fCurrent, namelen);
1988  if (!inp->ShiftCurrent(namelen)) {
1989  resvalue = -13;
1990  return 0;
1991  }
1992  if (!inp->SkipSpaces()) {
1993  resvalue = -13;
1994  return 0;
1995  }
1996  Bool_t is_system = kFALSE;
1997  if (inp->CheckFor("SYSTEM")) {
1998  if (!inp->SkipSpaces()) {
1999  resvalue = -13;
2000  return 0;
2001  }
2002  is_system = kTRUE;
2003  }
2004 
2005  Int_t valuelen = inp->LocateValue(0, false);
2006  if (valuelen < 2) {
2007  resvalue = -13;
2008  return 0;
2009  }
2010 
2011  TString entity_value(inp->fCurrent + 1, valuelen - 2);
2012 
2013  if (!inp->ShiftCurrent(valuelen)) {
2014  resvalue = -13;
2015  return 0;
2016  }
2017  inp->SkipSpaces();
2018  if (*inp->fCurrent != '>') {
2019  resvalue = -13;
2020  return 0;
2021  }
2022  if (!inp->ShiftCurrent()) {
2023  resvalue = -13;
2024  return 0;
2025  }
2026  inp->SkipSpaces();
2027 
2028  inp->AddEntity(new TXMLEntity(entity_name, entity_value, is_system));
2029  continue;
2030  }
2031 
2032  if (inp->CheckFor("<!ELEMENT")) {
2033  // process ELEMENT from DTD - dummy at the moment
2034  if (!inp->SkipSpaces()) {
2035  resvalue = -13;
2036  return 0;
2037  }
2038  Int_t namelen = inp->LocateIdentifier();
2039  if (namelen <= 0) {
2040  resvalue = -13;
2041  return 0;
2042  }
2043 
2044  if (!inp->ShiftCurrent(namelen)) {
2045  resvalue = -13;
2046  return 0;
2047  }
2048  if (!inp->SkipSpaces()) {
2049  resvalue = -13;
2050  return 0;
2051  }
2052 
2053  if (!inp->CheckFor("(")) {
2054  resvalue = -13;
2055  return 0;
2056  }
2057  if (inp->SearchFor(")") <= 0) {
2058  resvalue = -13;
2059  return 0;
2060  }
2061 
2062  inp->SkipSpaces();
2063  if (*inp->fCurrent != '>') {
2064  resvalue = -13;
2065  return 0;
2066  }
2067  if (!inp->ShiftCurrent()) {
2068  resvalue = -13;
2069  return 0;
2070  }
2071  inp->SkipSpaces();
2072 
2073  continue;
2074  }
2075 
2076  break;
2077  }
2078 
2079  if (!inp->CheckFor("]")) {
2080  resvalue = -13;
2081  return 0;
2082  }
2083  }
2084  inp->SkipSpaces();
2085  if (!inp->CheckFor(">")) {
2086  resvalue = -13;
2087  return 0;
2088  }
2089 
2090  resvalue = 2;
2091  return node;
2092  }
2093 
2094  EXmlNodeType nodetype = kXML_NODE;
2095  Bool_t canhaschildren = true;
2096  char endsymbol = '/';
2097 
2098  // this is case of processing instructions node
2099  if (*inp->fCurrent == '?') {
2100  if (!inp->ShiftCurrent())
2101  return 0;
2102  nodetype = kXML_PI_NODE;
2103  canhaschildren = false;
2104  endsymbol = '?';
2105  }
2106 
2107  if (!inp->SkipSpaces())
2108  return 0;
2109  Int_t len = inp->LocateIdentifier();
2110  if (len <= 0)
2111  return 0;
2112  node = (SXmlNode_t *)AllocateNode(len, xmlparent);
2113  char *nameptr = SXmlNode_t::Name(node);
2114  node->fType = nodetype;
2115 
2116  strncpy(nameptr, inp->fCurrent, len); // here copied content without padding 0
2117  nameptr += len;
2118  *nameptr = 0; // add 0 to the end
2119 
2120  char *colon = strchr(SXmlNode_t::Name(node), ':');
2121  if ((colon != 0) && (parent != 0)) {
2122  *colon = 0;
2123  node->fNs = (SXmlAttr_t *)FindNs(xmlparent, SXmlNode_t::Name(node));
2124  *colon = ':';
2125  }
2126 
2127  if (!inp->ShiftCurrent(len))
2128  return 0;
2129 
2130  do {
2131  if (!inp->SkipSpaces())
2132  return 0;
2133 
2134  char nextsymb = *inp->fCurrent;
2135 
2136  if (nextsymb == endsymbol) { // this is end of short node like <node ... />
2137  if (!inp->ShiftCurrent())
2138  return 0;
2139  if (*inp->fCurrent == '>') {
2140  if (!inp->ShiftCurrent())
2141  return 0;
2142 
2143  if (node->fNs != 0)
2144  TruncateNsExtension((XMLNodePointer_t)node);
2145 
2146  inp->SkipSpaces(kTRUE); // locate start of next string
2147  resvalue = 2;
2148  return node;
2149  } else
2150  return 0;
2151  } else if (nextsymb == '>') { // this is end of parent node, lets find all children
2152  if (!canhaschildren) {
2153  resvalue = -11;
2154  return 0;
2155  }
2156 
2157  if (!inp->ShiftCurrent())
2158  return 0;
2159 
2160  do {
2161  ReadNode(node, inp, resvalue);
2162  } while (resvalue == 2);
2163 
2164  if (resvalue == 1) {
2165  resvalue = 2;
2166  return node;
2167  } else
2168  return 0;
2169  } else {
2170  Int_t attrlen = inp->LocateIdentifier();
2171  if (attrlen <= 0) {
2172  resvalue = -6;
2173  return 0;
2174  }
2175 
2176  int valuelen = inp->LocateValue(attrlen, true);
2177  if (valuelen < 3) {
2178  resvalue = -7;
2179  return 0;
2180  }
2181 
2182  SXmlAttr_t *attr = (SXmlAttr_t *)AllocateAttr(attrlen, valuelen - 3, (XMLNodePointer_t)node);
2183 
2184  char *attrname = SXmlAttr_t::Name(attr);
2185  strncpy(attrname, inp->fCurrent, attrlen);
2186  attrname += attrlen;
2187  *attrname = 0;
2188  attrname++;
2189  UnpackSpecialCharacters(attrname, inp->fCurrent + attrlen + 2, valuelen - 3);
2190 
2191  if (!inp->ShiftCurrent(attrlen + valuelen))
2192  return 0;
2193 
2194  attrname = SXmlAttr_t::Name(attr);
2195 
2196  if ((strlen(attrname) > 6) && (strstr(attrname, "xmlns:") == attrname)) {
2197  if (strcmp(SXmlNode_t::Name(node), attrname + 6) != 0) {
2198  resvalue = -8;
2199  // return 0;
2200  }
2201  if (node->fNs != 0) {
2202  resvalue = -9;
2203  // return 0;
2204  }
2205  node->fNs = attr;
2206  }
2207  }
2208  } while (true);
2209 
2210  return 0;
2211 }
2212 
2213 ////////////////////////////////////////////////////////////////////////////////
2214 /// Displays xml parsing error
2215 
2216 void TXMLEngine::DisplayError(Int_t error, Int_t linenumber)
2217 {
2218  switch (error) {
2219  case -14: Error("ParseFile", "Error include external XML file at line %d", linenumber); break;
2220  case -13: Error("ParseFile", "Error processing DTD part of XML file at line %d", linenumber); break;
2221  case -12: Error("ParseFile", "DOCTYPE missing after <! at line %d", linenumber); break;
2222  case -11:
2223  Error("ParseFile", "Node cannot be closed with > symbol at line %d, for instance <?xml ... ?> node", linenumber);
2224  break;
2225  case -10:
2226  Error("ParseFile", "Error in xml comments definition at line %d, must be <!-- comments -->", linenumber);
2227  break;
2228  case -9: Error("ParseFile", "Multiple namespace definitions not allowed, line %d", linenumber); break;
2229  case -8: Error("ParseFile", "Invalid namespace specification, line %d", linenumber); break;
2230  case -7: Error("ParseFile", "Invalid attribute value, line %d", linenumber); break;
2231  case -6: Error("ParseFile", "Invalid identifier for node attribute, line %d", linenumber); break;
2232  case -5: Error("ParseFile", "Mismatch between open and close nodes, line %d", linenumber); break;
2233  case -4: Error("ParseFile", "Unexpected close node, line %d", linenumber); break;
2234  case -3: Error("ParseFile", "Valid identifier for close node is missing, line %d", linenumber); break;
2235  case -2: Error("ParseFile", "No multiple content entries allowed, line %d", linenumber); break;
2236  case -1: Error("ParseFile", "Unexpected end of xml file"); break;
2237  default: Error("ParseFile", "XML syntax error at line %d", linenumber); break;
2238  }
2239 }