DABC (Data Acquisition Backbone Core)  2.9.9
XmlEngine.cxx
Go to the documentation of this file.
1 // $Id: XmlEngine.cxx 4714 2021-03-12 16:46:47Z linev $
2 
3 /************************************************************
4  * The Data Acquisition Backbone Core (DABC) *
5  ************************************************************
6  * Copyright (C) 2009 - *
7  * GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
8  * Planckstr. 1, 64291 Darmstadt, Germany *
9  * Contact: http://dabc.gsi.de *
10  ************************************************************
11  * This software can be used under the GPL license *
12  * agreements as stated in LICENSE.txt file *
13  * which is part of the distribution. *
14  ************************************************************/
15 
16 #include "dabc/XmlEngine.h"
17 
18 #include <fstream>
19 #include <cstdlib>
20 #include <cstring>
21 
22 #include "dabc/logging.h"
23 
24 namespace dabc {
25 
26  struct SXmlAttr_t {
28  // after structure itself memory for attribute name is preserved
29  // if first byte is 0, this is special attribute
30  static inline char* Name(void* arg) { return (char*)arg + sizeof(SXmlAttr_t); }
31  };
32 
33  enum EXmlNodeType {
34  kXML_NODE = 1, // normal node with childs
35  kXML_COMMENT = 2, // comment (stored as value of node fName)
36  kXML_PI_NODE = 3, // processing instructions node (like <?name attr="" ?>
37  kXML_RAWLINE = 4 // just one line of xml code
38  };
39 
40  struct SXmlNode_t {
41  EXmlNodeType fType; // this is node type - node, comment, processing instruction and so on
42  SXmlAttr_t *fAttr; // first attribute
43  SXmlAttr_t *fNs; // name space definition (if any)
44  SXmlNode_t *fNext; // next node on the same level of hierarchy
45  SXmlNode_t *fChild; // first child node
46  SXmlNode_t *fLastChild; // last child node
47  SXmlNode_t *fParent; // parent node
48  // consequent bytes after structure are node name
49  // if first byte is 0, next is node content
50  static inline char* Name(void* arg) { return (char*)arg + sizeof(SXmlNode_t); }
51  };
52 
53  struct SXmlDoc_t {
55  char *fDtdName;
56  char *fDtdRoot;
57  };
58 
59 
61  protected:
62 
63  std::ostream *fOut;
64  std::string *fOutStr;
65  char *fBuf;
66  char *fCurrent;
67  char *fMaxAddr;
68  char *fLimitAddr;
69 
70  public:
71  XmlOutputStream(const char* filename, int bufsize = 20000)
72  {
73  fOut = new std::ofstream(filename);
74  fOutStr = 0;
75  Init(bufsize);
76  }
77 
78  XmlOutputStream(std::string* outstr, int bufsize = 20000)
79  {
80  fOut = 0;
81  fOutStr = outstr;
82  Init(bufsize);
83  }
84 
85  void Init(int bufsize)
86  {
87  fBuf = (char*) malloc(bufsize);
88  fCurrent = fBuf;
89  fMaxAddr = fBuf + bufsize;
90  fLimitAddr = fBuf + int(bufsize*0.75);
91  }
92 
93  virtual ~XmlOutputStream()
94  {
95  if (fCurrent!=fBuf) OutputCurrent();
96  delete fOut; fOut = 0;
97  free(fBuf); fBuf = 0;
98  }
99 
101  {
102  if (fCurrent!=fBuf) {
103  if (fOut!=0)
104  fOut->write(fBuf, fCurrent-fBuf);
105  else if (fOutStr!=0)
106  fOutStr->append(fBuf, fCurrent-fBuf);
107  }
108  fCurrent = fBuf;
109  }
110 
111  void OutputChar(char symb)
112  {
113  if (fOut!=0) fOut->put(symb); else
114  if (fOutStr!=0) fOutStr->append(1, symb);
115  }
116 
117  void Write(const char* str)
118  {
119  int len = strlen(str);
120  if (fCurrent+len>=fMaxAddr) {
121  OutputCurrent();
122  fOut->write(str,len);
123  } else {
124  while (*str)
125  *fCurrent++ = *str++;
126  if (fCurrent>fLimitAddr)
127  OutputCurrent();
128  }
129  }
130 
131  void Put(char symb, int cnt=1)
132  {
133  if (fCurrent+cnt>=fMaxAddr)
134  OutputCurrent();
135  if (fCurrent+cnt>=fMaxAddr)
136  for(int n=0;n<cnt;n++)
137  OutputChar(symb);
138  else {
139  for(int n=0;n<cnt;n++)
140  *fCurrent++ = symb;
141  if (fCurrent>fLimitAddr)
142  OutputCurrent();
143  }
144  }
145  };
146 
148  protected:
149 
150  std::istream *fInp;
151  const char *fInpStr;
153 
154  char *fBuf;
155  int fBufSize;
156 
157  char *fMaxAddr;
158  char *fLimitAddr;
159 
162 
163  public:
164 
165  char *fCurrent;
166 
167  XmlInputStream(bool isfilename, const char* filename, int ibufsize)
168  {
169  if (isfilename) {
170  fInp = new std::ifstream(filename);
171  fInpStr = 0;
172  fInpStrLen = 0;
173  } else {
174  fInp = 0;
175  fInpStr = filename;
176  fInpStrLen = filename==0 ? 0 : strlen(filename);
177  }
178 
179  fBufSize = ibufsize;
180  fBuf = (char*) malloc(fBufSize);
181 
182  fCurrent = 0;
183  fMaxAddr = 0;
184 
185  int len = DoRead(fBuf, fBufSize);
186  fCurrent = fBuf;
187  fMaxAddr = fBuf+len;
188  fLimitAddr = fBuf + int(len*0.75);
189 
190  fTotalPos = 0;
191  fCurrentLine = 1;
192  }
193 
194  virtual ~XmlInputStream()
195  {
196  delete fInp; fInp = 0;
197  free(fBuf); fBuf = 0;
198  }
199 
200  inline bool IsBad() { return (fInp!=0) ? !(*fInp) : (fInpStr==0); }
201 
202  inline bool SkipComments() const { return false; }
203 
204  inline bool EndOfFile() { return (fInp!=0) ? fInp->eof() : (fInpStrLen<=0); }
205 
206  inline bool EndOfStream() { return EndOfFile() && (fCurrent>=fMaxAddr); }
207 
208 
209 #if defined(__GNUC__) && (__GNUC__ >= 7)
210 #pragma GCC diagnostic push
211 #pragma GCC diagnostic ignored "-Wstringop-overflow"
212 #endif
213 
214  int DoRead(char* buf, int maxsize)
215  {
216  if (EndOfFile()) return 0;
217  if (fInp) {
218  fInp->get(buf, maxsize, 0);
219  maxsize = strlen(buf);
220  } else {
221  if (maxsize > fInpStrLen) maxsize = fInpStrLen;
222  if (maxsize > 0) strncpy(buf, fInpStr, maxsize);
223  fInpStr+=maxsize;
224  fInpStrLen-=maxsize;
225  }
226  return maxsize;
227  }
228 
229 #if defined(__GNUC__) && (__GNUC__ >= 7)
230 #pragma GCC diagnostic pop
231 #endif
232 
233  bool ExpandStream(char *&curr)
234  {
235  if (EndOfFile()) return false;
236  fBufSize*=2;
237  int curlength = fMaxAddr - fBuf;
238  char* newbuf = (char*) realloc(fBuf, fBufSize);
239  if (newbuf==0) return false;
240 
241  fMaxAddr = newbuf + (fMaxAddr - fBuf);
242  fCurrent = newbuf + (fCurrent - fBuf);
243  fLimitAddr = newbuf + (fLimitAddr - fBuf);
244  curr = newbuf + (curr - fBuf);
245  fBuf = newbuf;
246 
247  int len = DoRead(fMaxAddr, fBufSize-curlength);
248  if (len==0) return false;
249  fMaxAddr += len;
250  fLimitAddr += int(len*0.75);
251  return true;
252  }
253 
254  bool ShiftStream()
255  {
256  if (fCurrent<fLimitAddr) return true; // everything ok, can continue
257  if (EndOfFile()) return true;
258  int rest_len = fMaxAddr - fCurrent;
259  memmove(fBuf, fCurrent, rest_len);
260  int read_len = DoRead(fBuf + rest_len, fBufSize - rest_len);
261 
262  fCurrent = fBuf;
263  fMaxAddr = fBuf + rest_len + read_len;
264  fLimitAddr = fBuf + int((rest_len + read_len)*0.75);
265  return true;
266  }
267 
268  int TotalPos() { return fTotalPos; }
269 
270  int CurrentLine() { return fCurrentLine; }
271 
272  bool ShiftCurrent(int sz = 1)
273  {
274  for(int n=0;n<sz;n++) {
275  if (fCurrent>=fMaxAddr) EOUT("Error remains???");
276 
277  if (*fCurrent==10) fCurrentLine++;
278  if (fCurrent>=fLimitAddr) {
279  ShiftStream();
280  if (fCurrent>=fMaxAddr) return false;
281  }
282  fCurrent++;
283  }
284  fTotalPos+=sz;
285  return true;
286  }
287 
288  bool SkipSpaces(bool tillendl = false)
289  {
290  while(fCurrent<fMaxAddr) {
291  char symb = *fCurrent;
292  if ((symb>26) && (symb!=' ')) return true;
293 
294  if (!ShiftCurrent()) return false;
295 
296  if (tillendl && (symb==10)) return true;
297  }
298  return false;
299  }
300 
301  bool CheckFor(const char* str)
302  {
303  // Check if in current position we see specified string
304  int len = strlen(str);
305  char* curr = fCurrent;
306  while (curr+len>fMaxAddr)
307  if (!ExpandStream(curr)) return false;
308  while (*str != 0)
309  if (*str++ != *curr++) return false;
310  return ShiftCurrent(len);
311  }
312 
313  int SearchFor(const char* str)
314  {
315  // Search for specified string in the stream
316  // return number of symbols before string was found, -1 if error
317  int len = strlen(str);
318 
319  char* curr = fCurrent;
320 
321  while(true) {
322  while (curr+len > fMaxAddr)
323  if (!ExpandStream(curr)) return -1;
324  const char *chk0 = curr;
325  const char *chk = str;
326  bool find = true;
327  while (*chk != 0)
328  if (*chk++ != *chk0++) { find = false; break; }
329  // if string found, shift to the next symbol after string
330  if (find) return curr - fCurrent;
331  curr++;
332  }
333  return -1;
334  }
335 
337  {
338  char symb = *fCurrent;
339  bool ok = (((symb>='a') && (symb<='z')) ||
340  ((symb>='A') && (symb<='Z')) ||
341  (symb=='_'));
342  if (!ok) return 0;
343 
344  char* curr = fCurrent;
345 
346  do {
347  curr++;
348  if (curr>=fMaxAddr)
349  if (!ExpandStream(curr)) return 0;
350  symb = *curr;
351  ok = ((symb>='a') && (symb<='z')) ||
352  ((symb>='A') && (symb<='Z')) ||
353  ((symb>='0') && (symb<='9')) ||
354  (symb==':') || (symb=='_') || (symb=='-') || (symb=='.');
355  if (!ok) return curr-fCurrent;
356  } while (curr<fMaxAddr);
357  return 0;
358  }
359 
361  {
362  char* curr = fCurrent;
363  while (curr<fMaxAddr) {
364  char symb = *curr;
365  if (symb=='<') return curr - fCurrent;
366  curr++;
367  if (curr>=fMaxAddr)
368  if (!ExpandStream(curr)) return -1;
369  }
370  return -1;
371  }
372 
373  int LocateAttributeValue(char* start)
374  {
375  char* curr = start;
376  if (curr>=fMaxAddr)
377  if (!ExpandStream(curr)) return 0;
378  if (*curr!='=') return 0;
379  curr++;
380  if (curr>=fMaxAddr)
381  if (!ExpandStream(curr)) return 0;
382  if (*curr!='"') return 0;
383  do {
384  curr++;
385  if (curr>=fMaxAddr)
386  if (!ExpandStream(curr)) return 0;
387  if (*curr=='"') return curr-start+1;
388  } while (curr<fMaxAddr);
389  return 0;
390  }
391  };
392 
393 } // namespace dabc end
394 
395 
396 //______________________________________________________________________________
397 bool dabc::Xml::HasAttr(XMLNodePointer_t xmlnode, const char* name)
398 {
399  // checks if node has attribute of specified name
400 
401  if ((xmlnode==0) || (name==0)) return false;
402  SXmlAttr_t* attr = ((SXmlNode_t*)xmlnode)->fAttr;
403  while (attr!=0) {
404  if (strcmp(SXmlAttr_t::Name(attr),name)==0) return true;
405  attr = attr->fNext;
406  }
407  return false;
408 }
409 
410 //______________________________________________________________________________
411 const char* dabc::Xml::GetAttr(XMLNodePointer_t xmlnode, const char* name)
412 {
413  // returns value of attribute for xmlnode
414 
415  if (xmlnode==0) return 0;
416  SXmlAttr_t* attr = ((SXmlNode_t*)xmlnode)->fAttr;
417  while (attr!=0) {
418  if (strcmp(SXmlAttr_t::Name(attr),name)==0)
419  return SXmlAttr_t::Name(attr) + strlen(name) + 1;
420  attr = attr->fNext;
421  }
422  return 0;
423 }
424 
425 //______________________________________________________________________________
426 int dabc::Xml::GetIntAttr(XMLNodePointer_t xmlnode, const char* name)
427 {
428  // returns value of attribute as integer
429 
430  if (xmlnode==0) return 0;
431  int res = 0;
432  const char* attr = GetAttr(xmlnode, name);
433  if (attr) sscanf(attr, "%d", &res);
434  return res;
435 }
436 
437 //______________________________________________________________________________
439  const char* name, const char* value)
440 {
441  // creates new attribute for xmlnode,
442  // namespaces are not supported for attributes
443 
444  if (xmlnode==0) return 0;
445 
446  int namelen(name != 0 ? strlen(name) : 0);
447  int valuelen(value != 0 ? strlen(value) : 0);
448  SXmlAttr_t* attr = (SXmlAttr_t*) AllocateAttr(namelen, valuelen, xmlnode);
449 
450  char* attrname = SXmlAttr_t::Name(attr);
451  if (namelen>0)
452  strncpy(attrname, name, namelen+1);
453  else
454  *attrname = 0;
455  attrname += (namelen + 1);
456  if (valuelen>0)
457  strncpy(attrname, value, valuelen+1);
458  else
459  *attrname = 0;
460 
461  return (XMLAttrPointer_t) attr;
462 }
463 
464 //______________________________________________________________________________
466  const char* name,
467  int value)
468 {
469  // create node attribute with integer value
470 
471  char sbuf[30];
472  sprintf(sbuf,"%d",value);
473  return NewAttr(xmlnode, 0, name, sbuf);
474 }
475 
476 //______________________________________________________________________________
477 void dabc::Xml::FreeAttr(XMLNodePointer_t xmlnode, const char* name)
478 {
479  // remove attribute from xmlnode
480 
481  if (xmlnode==0) return;
482  SXmlAttr_t* attr = ((SXmlNode_t*) xmlnode)->fAttr;
483  SXmlAttr_t* prev = 0;
484  while (attr!=0) {
485  if (strcmp(SXmlAttr_t::Name(attr),name)==0) {
486  if (prev!=0)
487  prev->fNext = attr->fNext;
488  else
489  ((SXmlNode_t*) xmlnode)->fAttr = attr->fNext;
490  //fNumNodes--;
491  free(attr);
492  return;
493  }
494 
495  prev = attr;
496  attr = attr->fNext;
497  }
498 }
499 
500 //______________________________________________________________________________
502 {
503  // Free all attributes of the node
504  if (xmlnode==0) return;
505 
506  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
507  SXmlAttr_t* attr = node->fAttr;
508  while (attr!=0) {
509  SXmlAttr_t* next = attr->fNext;
510  free(attr);
511  attr = next;
512  }
513  node->fAttr = 0;
514 }
515 
516 
517 //______________________________________________________________________________
519 {
520  // return first attribute in the list, namespace (if exists) will be skipped
521 
522  if (xmlnode==0) return 0;
523  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
524 
525  SXmlAttr_t* attr = node->fAttr;
526  if ((attr!=0) && (node->fNs==attr)) attr = attr->fNext;
527 
528  return (XMLAttrPointer_t) attr;
529 }
530 
531 //______________________________________________________________________________
533 {
534  // return next attribute in the list
535 
536  if (xmlattr==0) return 0;
537 
538  return (XMLAttrPointer_t) ((SXmlAttr_t*) xmlattr)->fNext;
539 }
540 
541 //______________________________________________________________________________
543 {
544  // return name of the attribute
545 
546  if (xmlattr==0) return 0;
547 
548  return SXmlAttr_t::Name(xmlattr);
549 
550 }
551 
552 //______________________________________________________________________________
554 {
555  // return value of attribute
556 
557  if (xmlattr==0) return 0;
558 
559  const char* attrname = SXmlAttr_t::Name(xmlattr);
560  return attrname + strlen(attrname) + 1;
561 }
562 
563 //______________________________________________________________________________
565  const char* name, const char* content)
566 {
567  // create new child element for parent node
568 
569  int namelen(name!=0 ? strlen(name) : 0);
570 
571  SXmlNode_t* node = (SXmlNode_t*) AllocateNode(namelen, parent);
572 
573  if (namelen>0)
574  strncpy(SXmlNode_t::Name(node), name, namelen+1);
575  else
576  *SXmlNode_t::Name(node) = 0;
577 
578  node->fNs = (SXmlAttr_t*) ns;
579  if (content!=0) {
580  int contlen = strlen(content);
581  if (contlen>0) {
582  SXmlNode_t* contnode = (SXmlNode_t*) AllocateNode(contlen+1, node);
583  char* cptr = SXmlNode_t::Name(contnode);
584  // first zero indicate that this is just content value
585  *cptr = 0;
586  cptr++;
587  strncpy(cptr, content, contlen+1);
588  }
589  }
590 
591  return (XMLNodePointer_t) node;
592 }
593 
594 //______________________________________________________________________________
595 dabc::XMLNsPointer_t dabc::Xml::NewNS(XMLNodePointer_t xmlnode, const char* reference, const char* name)
596 {
597  // create namespace attribute for xmlnode.
598  // namespace attribute will be always the first in list of node attributes
599 
600  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
601  if (name==0) name = SXmlNode_t::Name(node);
602  int namelen = strlen(name);
603  char* nsname = new char[namelen+7];
604  snprintf(nsname, namelen+7, "xmlns:%s", name);
605 
606  SXmlAttr_t* first = node->fAttr;
607  node->fAttr = 0;
608 
609  SXmlAttr_t* nsattr = (SXmlAttr_t*) NewAttr(xmlnode, 0, nsname, reference);
610 
611  node->fAttr = nsattr;
612  nsattr->fNext = first;
613 
614  node->fNs = nsattr;
615  delete[] nsname;
616  return (XMLNsPointer_t) nsattr;
617 }
618 
619 //______________________________________________________________________________
621 {
622  // return namespace attribute (if exists)
623 
624  if (xmlnode==0) return 0;
625  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
626 
627  return (XMLNsPointer_t) node->fNs;
628 }
629 
630 //______________________________________________________________________________
632 {
633  // return name id of namespace
634 
635  const char* nsname = GetAttrName((XMLAttrPointer_t)ns);
636 
637  if ((nsname!=0) && (strncmp(nsname,"xmlns:",6)==0)) nsname+=6;
638 
639  return nsname;
640 }
641 
642 //______________________________________________________________________________
644 {
645  // return reference id of namespace
646 
647  return GetAttrValue((XMLAttrPointer_t)ns);
648 }
649 
650 
651 //______________________________________________________________________________
653 {
654  // add child element to xmlnode
655 
656  if ((parent==0) || (child==0)) return;
657  SXmlNode_t* pnode = (SXmlNode_t*) parent;
658  SXmlNode_t* cnode = (SXmlNode_t*) child;
659  cnode->fParent = pnode;
660  if (pnode->fLastChild==0) {
661  pnode->fChild = cnode;
662  pnode->fLastChild = cnode;
663  } else {
664  //SXmlNode_t* ch = pnode->fChild;
665  //while (ch->fNext!=0) ch=ch->fNext;
666  pnode->fLastChild->fNext = cnode;
667  pnode->fLastChild = cnode;
668  }
669 }
670 
671 //______________________________________________________________________________
673 {
674  // add node as first child
675 
676  if ((parent==0) || (child==0)) return;
677  SXmlNode_t* pnode = (SXmlNode_t*) parent;
678  SXmlNode_t* cnode = (SXmlNode_t*) child;
679  cnode->fParent = pnode;
680 
681  cnode->fNext = pnode->fChild;
682  pnode->fChild = cnode;
683 
684  if (pnode->fLastChild==0) pnode->fLastChild = cnode;
685 }
686 
687 
688 //______________________________________________________________________________
689 bool dabc::Xml::AddComment(XMLNodePointer_t xmlnode, const char* comment)
690 {
691  // Adds comment line to the node
692 
693  if ((xmlnode==0) || (comment==0)) return false;
694 
695  int commentlen = strlen(comment);
696 
697  SXmlNode_t* node = (SXmlNode_t*) AllocateNode(commentlen, xmlnode);
698  node->fType = kXML_COMMENT;
699  strncpy(SXmlNode_t::Name(node), comment, commentlen+1);
700 
701  return true;
702 }
703 
704 //______________________________________________________________________________
705 bool dabc::Xml::AddDocComment(XMLDocPointer_t xmldoc, const char* comment)
706 {
707  // add comment line to the top of the document
708 
709  if (xmldoc==0) return false;
710 
711  XMLNodePointer_t rootnode = DocGetRootElement(xmldoc);
712  UnlinkNode(rootnode);
713 
714  bool res = AddComment(((SXmlDoc_t*)xmldoc)->fRootNode, comment);
715 
716  AddChild((XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode, rootnode);
717 
718  return res;
719 }
720 
721 //______________________________________________________________________________
722 bool dabc::Xml::AddRawLine(XMLNodePointer_t xmlnode, const char* line)
723 {
724  // Add just line into xml file
725  // Line should has correct xml syntax that later it can be decoded by xml parser
726  // For instance, it can be comment or processing instructions
727 
728  if ((xmlnode==0) || (line==0)) return false;
729 
730  int linelen = strlen(line);
731  SXmlNode_t* node = (SXmlNode_t*) AllocateNode(linelen, xmlnode);
732  node->fType = kXML_RAWLINE;
733  strncpy(SXmlNode_t::Name(node), line, linelen+1);
734 
735  return true;
736 }
737 
738 //______________________________________________________________________________
739 bool dabc::Xml::AddDocRawLine(XMLDocPointer_t xmldoc, const char* line)
740 {
741  // Add just line on the top of xml document
742  // Line should has correct xml syntax that later it can be decoded by xml parser
743 
744  XMLNodePointer_t rootnode = DocGetRootElement(xmldoc);
745  UnlinkNode(rootnode);
746 
747  bool res = AddRawLine(((SXmlDoc_t*)xmldoc)->fRootNode, line);
748 
749  AddChild((XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode, rootnode);
750 
751  return res;
752 
753 }
754 
755 
756 //______________________________________________________________________________
758  const char* href,
759  const char* type,
760  const char* title,
761  int alternate,
762  const char* media,
763  const char* charset)
764 {
765  // Adds style sheet definition to the specified node
766  // Creates <?xml-stylesheet alternate="yes" title="compact" href="small-base.css" type="text/css"?>
767  // Attributes href and type must be supplied,
768  // other attributes: title, alternate, media, charset are optional
769  // if alternate==0, attribyte alternate="no" will be created,
770  // if alternate>0, attribute alternate="yes"
771  // if alternate<0, attribute will not be created
772 
773  if ((xmlnode==0) || (href==0) || (type==0)) return false;
774 
775  const char* nodename = "xml-stylesheet";
776  int nodenamelen = strlen(nodename);
777 
778  SXmlNode_t* node = (SXmlNode_t*) AllocateNode(nodenamelen, xmlnode);
779  node->fType = kXML_PI_NODE;
780  strncpy(SXmlNode_t::Name(node), nodename, nodenamelen+1);
781 
782  if (alternate>=0)
783  NewAttr(node, 0, "alternate", (alternate>0) ? "yes" : "no");
784 
785  if (title!=0) NewAttr(node, 0, "title", title);
786 
787  NewAttr(node, 0, "href", href);
788  NewAttr(node, 0, "type", type);
789 
790  if (media!=0) NewAttr(node, 0, "media", media);
791  if (charset!=0) NewAttr(node, 0, "charset", charset);
792 
793  return true;
794 }
795 
796 
797 //______________________________________________________________________________
799  const char* href,
800  const char* type,
801  const char* title,
802  int alternate,
803  const char* media,
804  const char* charset)
805 {
806  // Add style sheet definition on the top of document
807 
808  if (xmldoc==0) return false;
809 
810  XMLNodePointer_t rootnode = DocGetRootElement(xmldoc);
811  UnlinkNode(rootnode);
812 
813  bool res = AddStyleSheet(((SXmlDoc_t*)xmldoc)->fRootNode,
814  href,type,title,alternate,media,charset);
815 
816  AddChild((XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode, rootnode);
817 
818  return res;
819 }
820 
821 //______________________________________________________________________________
823 {
824  // unlink (detach) xml node from parent
825 
826  if (xmlnode==0) return;
827  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
828 
829  SXmlNode_t* parent = node->fParent;
830 
831  if (parent==0) return;
832 
833  if (parent->fChild==node) {
834  parent->fChild = node->fNext;
835  if (parent->fLastChild==node)
836  parent->fLastChild = node->fNext;
837  } else {
838  SXmlNode_t* ch = parent->fChild;
839  while (ch->fNext!=node) ch = ch->fNext;
840  ch->fNext = node->fNext;
841  if (parent->fLastChild == node)
842  parent->fLastChild = ch;
843  }
844 }
845 
846 //______________________________________________________________________________
848 {
849  // release all memory, allocated from this node and
850  // destroyes node itself
851 
852  if (xmlnode==0) return;
853  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
854 
855  SXmlNode_t* child = node->fChild;
856  while (child!=0) {
857  SXmlNode_t* next = child->fNext;
858  FreeNode((XMLNodePointer_t)child);
859  child = next;
860  }
861 
862  SXmlAttr_t* attr = node->fAttr;
863  while (attr!=0) {
864  SXmlAttr_t* next = attr->fNext;
865  //fNumNodes--;
866  free(attr);
867  attr = next;
868  }
869 
870  free(node);
871 
872  //fNumNodes--;
873 }
874 
875 //______________________________________________________________________________
877 {
878  // combined operation. Unlink node and free used memory
879 
880  UnlinkNode(xmlnode);
881  FreeNode(xmlnode);
882 }
883 
884 //______________________________________________________________________________
886 {
887  // returns name of xmlnode
888 
889  return xmlnode==0 ? 0 : SXmlNode_t::Name(xmlnode);
890 }
891 
892 //______________________________________________________________________________
894 {
895  // get contents (if any) of xml node
896 
897  if (xmlnode==0) return 0;
898  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
899  if (node->fChild==0) return 0;
900  const char* childname = SXmlNode_t::Name(node->fChild);
901  if ((childname==0) || (*childname != 0)) return 0;
902  return childname + 1;
903 }
904 
905 //______________________________________________________________________________
907 {
908  // returns first child of xml node
909 
910  SXmlNode_t* res = xmlnode==0 ? 0 :((SXmlNode_t*) xmlnode)->fChild;
911  // skip content node
912  if ((res!=0) && (*SXmlNode_t::Name(res) == 0)) res = res->fNext;
913  return (XMLNodePointer_t) res;
914 }
915 
916 //______________________________________________________________________________
918 {
919  // returns parent of xmlnode
920 
921  return xmlnode==0 ? 0 : (XMLNodePointer_t) ((SXmlNode_t*) xmlnode)->fParent;
922 }
923 
924 //______________________________________________________________________________
926 {
927  // return next to xmlnode node
928 
929  return xmlnode==0 ? 0 : (XMLNodePointer_t) ((SXmlNode_t*) xmlnode)->fNext;
930 }
931 
932 //______________________________________________________________________________
933 void dabc::Xml::ShiftToNext(XMLNodePointer_t &xmlnode, bool tonode)
934 {
935  // shifts specified node to next
936 
937  do {
938  xmlnode = xmlnode==0 ? 0 : (XMLNodePointer_t) ((SXmlNode_t*) xmlnode)->fNext;
939  if ((xmlnode==0) || !tonode) return;
940 
941  } while (((SXmlNode_t*) xmlnode)->fType != kXML_NODE);
942 }
943 
944 //______________________________________________________________________________
946 {
947  // return true is this is node with special data like comments to data processing instructions
948 
949  return xmlnode==0 ? true : (((SXmlNode_t*) xmlnode)->fType != kXML_NODE);
950 }
951 
952 //______________________________________________________________________________
954 {
955  // Skip all current empty nodes and locate on first "true" node
956 
957  if (IsEmptyNode(xmlnode)) ShiftToNext(xmlnode);
958 }
959 
960 
961 //______________________________________________________________________________
963 {
964  // remove all childs node from xmlnode
965 
966  if (xmlnode==0) return;
967  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
968 
969  SXmlNode_t* child = node->fChild;
970  while (child!=0) {
971  SXmlNode_t* next = child->fNext;
972  FreeNode((XMLNodePointer_t)child);
973  child = next;
974  }
975 
976  node->fChild = 0;
977  node->fLastChild = 0;
978 }
979 
980 //______________________________________________________________________________
982 {
983  // creates new xml document with provided version
984 
985  SXmlDoc_t* doc = new SXmlDoc_t;
986  doc->fRootNode = (SXmlNode_t*) NewChild(0, 0, "??DummyTopNode??", 0);
987 
988  if (version!=0) {
989  XMLNodePointer_t vernode = NewChild( (XMLNodePointer_t) doc->fRootNode, 0, "xml");
990  ((SXmlNode_t*) vernode)->fType = kXML_PI_NODE;
991  NewAttr(vernode, 0, "version", version);
992  }
993 
994  doc->fDtdName = 0;
995  doc->fDtdRoot = 0;
996  return (XMLDocPointer_t) doc;
997 }
998 
999 //______________________________________________________________________________
1000 void dabc::Xml::AssignDtd(XMLDocPointer_t xmldoc, const char* dtdname, const char* rootname)
1001 {
1002  // assignes dtd filename to document
1003 
1004  if (xmldoc==0) return;
1005  SXmlDoc_t* doc = (SXmlDoc_t*) xmldoc;
1006  delete[] doc->fDtdName;
1007  doc->fDtdName = Makestr(dtdname);
1008  delete[] doc->fDtdRoot;
1009  doc->fDtdRoot = Makestr(rootname);
1010 }
1011 
1012 //______________________________________________________________________________
1014 {
1015  // frees allocated document data and deletes document itself
1016 
1017  if (xmldoc==0) return;
1018  SXmlDoc_t* doc = (SXmlDoc_t*) xmldoc;
1020  delete[] doc->fDtdName;
1021  delete[] doc->fDtdRoot;
1022  delete doc;
1023 }
1024 
1025 //______________________________________________________________________________
1026 void dabc::Xml::SaveDoc(XMLDocPointer_t xmldoc, const char* filename, int layout)
1027 {
1028  // store document content to file
1029  // if layout<=0, no any spaces or newlines will be placed between
1030  // xmlnodes. Xml file will have minimum size, but nonreadable structure
1031  // if (layout>0) each node will be started from new line,
1032  // and number of spaces will correspond to structure depth.
1033 
1034  if (xmldoc==0) return;
1035 
1036  SXmlDoc_t* doc = (SXmlDoc_t*) xmldoc;
1037 
1038  XmlOutputStream out(filename, 100000);
1039 
1041 
1042  do {
1043  SaveNode(child, &out, layout, 0);
1044  ShiftToNext(child, false);
1045  } while (child!=0);
1046 
1047 }
1048 
1049 //______________________________________________________________________________
1051 {
1052  // set main (root) node for document
1053 
1054  if (xmldoc==0) return;
1055 
1056  FreeNode(DocGetRootElement(xmldoc));
1057 
1058  AddChild((XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode, xmlnode);
1059 }
1060 
1061 //______________________________________________________________________________
1063 {
1064  // returns root node of document
1065 
1066  if (xmldoc==0) return 0;
1067 
1068  XMLNodePointer_t xmlnode = (XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode;
1069 
1070  xmlnode = GetChild(xmlnode);
1071 
1072  ShiftToNext(xmlnode);
1073 
1074  return xmlnode;
1075 }
1076 
1077 //______________________________________________________________________________
1078 dabc::XMLDocPointer_t dabc::Xml::ParseFile(const char* filename, bool showerr)
1079 {
1080  // parses content of file and tries to produce xml structures
1081 
1082  if ((filename==0) || (strlen(filename)==0)) return 0;
1083  XmlInputStream inp(true, filename, 100000);
1084  if (inp.IsBad()) { EOUT("File %s not found", filename); return 0; }
1085  return ParseStream(&inp, showerr);
1086 }
1087 
1088 //______________________________________________________________________________
1089 dabc::XMLDocPointer_t dabc::Xml::ParseString(const char* xmlstring, bool showerr)
1090 {
1091  // parses content of string and tries to produce xml structures
1092 
1093  if ((xmlstring==0) || (strlen(xmlstring)==0)) return 0;
1094  XmlInputStream inp(false, xmlstring, 100000);
1095  return ParseStream(&inp, showerr);
1096 }
1097 
1098 //______________________________________________________________________________
1100 {
1101  // parses content of the stream and tries to produce xml structures
1102 
1103  if (inp == 0) return 0;
1104 
1105  XMLDocPointer_t xmldoc = NewDoc(0);
1106 
1107  bool success = false;
1108 
1109  int resvalue = 0;
1110 
1111  do {
1112  ReadNode(((SXmlDoc_t*) xmldoc)->fRootNode, inp, resvalue);
1113 
1114  if (resvalue!=2) break;
1115 
1116  // coverity[unchecked_value] at this place result of SkipSpaces() doesn't matter - either file is finished (false) or there is some more nodes to analyse (true)
1117  if (!inp->EndOfStream()) inp->SkipSpaces();
1118 
1119  if (inp->EndOfStream()) {
1120  success = true;
1121  break;
1122  }
1123  } while (true);
1124 
1125  if (!success) {
1126  if (showerr) DisplayError(resvalue, inp->CurrentLine());
1127  FreeDoc(xmldoc);
1128  return 0;
1129  }
1130 
1131  return xmldoc;
1132 }
1133 
1134 //______________________________________________________________________________
1135 bool dabc::Xml::ValidateVersion(XMLDocPointer_t xmldoc, const char* version)
1136 {
1137  // check that first node is xml processing instruction with correct xml version number
1138 
1139  if (xmldoc==0) return false;
1140 
1141  XMLNodePointer_t vernode = GetChild((XMLNodePointer_t) ((SXmlDoc_t*) xmldoc)->fRootNode);
1142  if (vernode==0) return false;
1143 
1144  if (((SXmlNode_t*) vernode)->fType!=kXML_PI_NODE) return false;
1145  if (strcmp(GetNodeName(vernode), "xml")!=0) return false;
1146 
1147  const char* value = GetAttr(vernode,"version");
1148  if (value==0) return false;
1149  if (version==0) version = "1.0";
1150 
1151  return strcmp(version,value)==0;
1152 }
1153 
1154 //______________________________________________________________________________
1155 void dabc::Xml::SaveSingleNode(XMLNodePointer_t xmlnode, std::string* res, int layout)
1156 {
1157  // convert single xml node (and its child node) to string
1158  // if layout<=0, no any spaces or newlines will be placed between
1159  // xmlnodes. Xml file will have minimum size, but nonreadable structure
1160  // if (layout>0) each node will be started from new line,
1161  // and number of spaces will correspond to structure depth.
1162 
1163  if ((res==0) || (xmlnode==0)) return;
1164 
1165  XmlOutputStream out(res, 10000);
1166 
1167  SaveNode(xmlnode, &out, layout, 0);
1168 }
1169 
1170 //______________________________________________________________________________
1172 {
1173  // read single xml node from provided string
1174 
1175  if (src==0) return 0;
1176 
1177  XmlInputStream inp(false, src, 10000);
1178 
1179  int resvalue;
1180 
1181  XMLNodePointer_t xmlnode = ReadNode(0, &inp, resvalue);
1182 
1183  if (resvalue<=0) {
1184  DisplayError(resvalue, inp.CurrentLine());
1185  FreeNode(xmlnode);
1186  return 0;
1187  }
1188 
1189  return xmlnode;
1190 }
1191 
1192 //______________________________________________________________________________
1193 char* dabc::Xml::Makestr(const char* str)
1194 {
1195  // creates char* variable with copy of provided string
1196 
1197  if (str==0) return 0;
1198  int len = strlen(str);
1199  if (len==0) return 0;
1200  char* res = new char[len+1];
1201  strncpy(res, str, len+1);
1202  return res;
1203 }
1204 
1205 //______________________________________________________________________________
1206 char* dabc::Xml::Makenstr(const char* str, int len)
1207 {
1208  // creates char* variable with copy of len symbols from provided string
1209 
1210  if ((str==0) || (len==0)) return 0;
1211  char* res = new char[len+1];
1212  strncpy(res, str, len);
1213  *(res+len) = 0;
1214  return res;
1215 }
1216 
1217 //______________________________________________________________________________
1219 {
1220  // Allocates new xml node with specified namelength
1221 
1222  //fNumNodes++;
1223 
1224  SXmlNode_t* node = (SXmlNode_t*) malloc(sizeof(SXmlNode_t) + namelen + 1);
1225  if (!node) return nullptr;
1226 
1227  node->fType = kXML_NODE;
1228  node->fParent = 0;
1229  node->fNs = 0;
1230  node->fAttr = 0;
1231  node->fChild = 0;
1232  node->fLastChild = 0;
1233  node->fNext = 0;
1234 
1235  if (parent!=0)
1236  AddChild(parent, (XMLNodePointer_t) node);
1237 
1238  return (XMLNodePointer_t) node;
1239 }
1240 
1241 //______________________________________________________________________________
1243 {
1244  // Allocate new attribute with specified name length and value length
1245 
1246  //fNumNodes++;
1247 
1248  SXmlAttr_t* attr = (SXmlAttr_t*) malloc(sizeof(SXmlAttr_t) + namelen + 1 + valuelen + 1);
1249  if (!attr) return nullptr;
1250 
1251  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
1252 
1253  attr->fNext = 0;
1254 
1255  if (node->fAttr==0)
1256  node->fAttr = attr;
1257  else {
1258  SXmlAttr_t* d = node->fAttr;
1259  while (d->fNext!=0) d = d->fNext;
1260  d->fNext = attr;
1261  }
1262 
1263  return (XMLAttrPointer_t) attr;
1264 }
1265 
1266 //______________________________________________________________________________
1268 {
1269  // define if namespace of that name exists for xmlnode
1270 
1271  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
1272  while (node!=0) {
1273  if (node->fNs!=0) {
1274  const char* nsname = SXmlAttr_t::Name(node->fNs) + 6;
1275  if (strcmp(nsname, name)==0) return node->fNs;
1276  }
1277  node = node->fParent;
1278  }
1279  return 0;
1280 }
1281 
1282 //______________________________________________________________________________
1284 {
1285  // removes namespace extension of nodename
1286 
1287  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
1288  if (node==0) return;
1289  char* colon = strchr(SXmlNode_t::Name(node),':');
1290  if (colon==0) return;
1291 
1292  char* copyname = SXmlNode_t::Name(node);
1293 
1294  while (*colon!=0)
1295  *(copyname++) = *(++colon);
1296 }
1297 
1298 //______________________________________________________________________________
1299 void dabc::Xml::UnpackSpecialCharacters(char* target, const char* source, int srclen)
1300 {
1301  // unpack special symbols, used in xml syntax to code characters
1302  // these symbols: '<' - &lt, '>' - &gt, '&' - &amp, '"' - &quot, ' - &apos;
1303 
1304  while (srclen>0) {
1305  if (*source=='&') {
1306  if ((srclen>3) && (*(source+1)=='l') && (*(source+2)=='t') && (*(source+3)==';')) {
1307  *target++ = '<'; source+=4; srclen-=4;
1308  } else
1309  if ((srclen>3) && (*(source+1)=='g') && (*(source+2)=='t') && (*(source+3)==';')) {
1310  *target++ = '>'; source+=4; srclen-=4;
1311  } else
1312  if ((srclen>4) && (*(source+1)=='a') && (*(source+2)=='m') && (*(source+3)=='p') && (*(source+4)==';')) {
1313  *target++ = '&'; source+=5; srclen-=5;
1314  } else
1315  if ((srclen>5) && (*(source+1)=='q') && (*(source+2)=='u') && (*(source+3)=='o') && (*(source+4)=='t') && (*(source+5)==';')) {
1316  *target++ = '\"'; source+=6; srclen-=6;
1317  } else
1318  if ((srclen>5) && (*(source+1)=='a') && (*(source+2)=='p') && (*(source+3)=='o') && (*(source+4)=='s') && (*(source+5)==';')) {
1319  *target++ = '\''; source+=6; srclen-=6;
1320  } else {
1321  *target++ = *source++; srclen--;
1322  }
1323  } else {
1324  *target++ = *source++;
1325  srclen--;
1326  }
1327  }
1328  *target = 0;
1329 }
1330 
1331 //______________________________________________________________________________
1333 {
1334  // output value to output stream
1335  // if symbols '<' '&' '>' '"' appears in the string, they
1336  // will be encoded to appropriate xml symbols: &lt, &amp, &gt, &quot
1337 
1338  if (value==0) return;
1339 
1340  char* last = value;
1341  char* find = 0;
1342  while ((find=strpbrk(last,"<&>\"\'")) !=0 ) {
1343  char symb = *find;
1344  *find = 0;
1345  out->Write(last);
1346  *find = symb;
1347  last = find+1;
1348  if (symb=='<') out->Write("&lt;");
1349  else if (symb=='>') out->Write("&gt;");
1350  else if (symb=='&') out->Write("&amp;");
1351  else if (symb=='\'') out->Write("&apos;");
1352  else out->Write("&quot;");
1353  }
1354  if (*last!=0)
1355  out->Write(last);
1356 }
1357 
1358 //______________________________________________________________________________
1359 void dabc::Xml::SaveNode(XMLNodePointer_t xmlnode, XmlOutputStream* out, int layout, int level)
1360 {
1361  // stream data of xmlnode to output
1362 
1363  if (xmlnode==0) return;
1364  SXmlNode_t* node = (SXmlNode_t*) xmlnode;
1365 
1366  // this is output for content
1367  if (*SXmlNode_t::Name(node) == 0 ) {
1368  out->Write(SXmlNode_t::Name(node)+1);
1369  return;
1370  }
1371 
1372  bool issingleline = (node->fChild==0);
1373 
1374  if (layout>0) out->Put(' ', level);
1375 
1376  if (node->fType==kXML_COMMENT) {
1377  out->Write("<!--");
1378  out->Write(SXmlNode_t::Name(node));
1379  out->Write("-->");
1380  if (layout>0) out->Put('\n');
1381  return;
1382  } else
1383  if (node->fType==kXML_RAWLINE) {
1384  out->Write(SXmlNode_t::Name(node));
1385  if (layout>0) out->Put('\n');
1386  return;
1387  }
1388 
1389  out->Put('<');
1390  if (node->fType==kXML_PI_NODE) out->Put('?');
1391 
1392  // we suppose that ns is always first attribute
1393  if ((node->fNs!=0) && (node->fNs!=node->fAttr)) {
1394  out->Write(SXmlAttr_t::Name(node->fNs)+6);
1395  out->Put(':');
1396  }
1397  out->Write(SXmlNode_t::Name(node));
1398 
1399  SXmlAttr_t* attr = node->fAttr;
1400  while (attr!=0) {
1401  out->Put(' ');
1402  char* attrname = SXmlAttr_t::Name(attr);
1403  out->Write(attrname);
1404  out->Write("=\"");
1405  attrname += strlen(attrname) + 1;
1406  OutputValue(attrname, out);
1407  out->Put('\"');
1408  attr = attr->fNext;
1409  }
1410 
1411  // if single line, close node with "/>" and return
1412  if (issingleline) {
1413  if (node->fType==kXML_PI_NODE) out->Write("?>");
1414  else out->Write("/>");
1415  if (layout>0) out->Put('\n');
1416  return;
1417  }
1418 
1419  out->Put('>');
1420 
1421  // go to next line only if no content inside
1422  const char* content = GetNodeContent(xmlnode);
1423  if ((content==0) && (layout>0))
1424  out->Put('\n');
1425 
1426  if (content!=0) out->Write(content);
1427 
1428  SXmlNode_t* child = (SXmlNode_t*) GetChild(xmlnode);
1429  while (child!=0) {
1430  if (content!=0) {
1431  content = 0;
1432  if (layout>0) out->Put('\n');
1433  }
1434  SaveNode((XMLNodePointer_t) child, out, layout, level+2);
1435  child = child->fNext;
1436  }
1437 
1438  // add starting spaces
1439  if ((content==0) && (layout>0)) out->Put(' ',level);
1440 
1441  out->Write("</");
1442  // we suppose that ns is always first attribute
1443  if ((node->fNs!=0) && (node->fNs!=node->fAttr)) {
1444  out->Write(SXmlAttr_t::Name(node->fNs)+6);
1445  out->Put(':');
1446  }
1447  out->Write(SXmlNode_t::Name(node));
1448  out->Put('>');
1449  if (layout>0) out->Put('\n');
1450 }
1451 
1452 //______________________________________________________________________________
1454 {
1455  // Tries to construct xml node from input stream. Node should be
1456  // child of xmlparent node or it can be closing tag of xmlparent.
1457  // resvalue <= 0 if error
1458  // resvalue == 1 if this is endnode of parent
1459  // resvalue == 2 if this is child
1460 
1461  resvalue = 0;
1462 
1463  if (inp==0) return 0;
1464  if (!inp->SkipSpaces()) { resvalue = -1; return 0; }
1465  SXmlNode_t* parent = (SXmlNode_t*) xmlparent;
1466 
1467  SXmlNode_t* node = 0;
1468 
1469  // process comments before we start to analyze any node symbols
1470  while (inp->CheckFor("<!--")) {
1471  int commentlen = inp->SearchFor("-->");
1472  if (commentlen < 0) { resvalue = -10; return 0; }
1473 
1474  if (!inp->SkipComments()) {
1475  node = (SXmlNode_t*) AllocateNode(commentlen, xmlparent);
1476  char* nameptr = SXmlNode_t::Name(node);
1477  node->fType = kXML_COMMENT;
1478  strncpy(nameptr, inp->fCurrent, commentlen); // here copy only content, there is no padding 0 at the end
1479  nameptr+=commentlen;
1480  *nameptr = 0; // here we add padding 0 to get normal string
1481  }
1482 
1483  if (!inp->ShiftCurrent(commentlen+3)) { resvalue = -1; return node; }
1484  if (!inp->SkipSpaces() && !inp->EndOfStream()) { resvalue = -1; return node; }
1485 
1486  resvalue = 2;
1487  return node;
1488  }
1489 
1490  if (*inp->fCurrent!='<') {
1491  // here should be reading of element content
1492  // only one entry for content is supported, only before any other childs
1493  if ((parent==0) || (parent->fChild!=0)) { resvalue = -2; return 0; }
1494  int contlen = inp->LocateContent();
1495  if (contlen<0) return 0;
1496 
1497  SXmlNode_t* contnode = (SXmlNode_t*) AllocateNode(contlen+1, xmlparent);
1498  char* contptr = SXmlNode_t::Name(contnode);
1499  *contptr = 0;
1500  contptr++;
1501  UnpackSpecialCharacters(contptr, inp->fCurrent, contlen);
1502  if (!inp->ShiftCurrent(contlen)) return 0;
1503  resvalue = 2;
1504  return contnode;
1505  } else
1506  // skip "<" symbol
1507  if (!inp->ShiftCurrent()) return 0;
1508 
1509  if (*inp->fCurrent=='/') {
1510  // this is a starting of closing node
1511  if (!inp->ShiftCurrent()) return 0;
1512  if (!inp->SkipSpaces()) return 0;
1513  int len = inp->LocateIdentifier();
1514  if (len<=0) { resvalue = -3; return 0; }
1515 
1516  if (parent==0) { resvalue = -4; return 0; }
1517 
1518  if (strncmp(SXmlNode_t::Name(parent), inp->fCurrent, len)!=0) {
1519  resvalue = -5;
1520  return 0;
1521  }
1522 
1523  if (!inp->ShiftCurrent(len)) return 0;
1524 
1525  if (!inp->SkipSpaces()) return 0;
1526  if (*inp->fCurrent!='>') return 0;
1527  if (!inp->ShiftCurrent()) return 0;
1528 
1529  if (parent->fNs!=0)
1531 
1532  inp->SkipSpaces(true); // locate start of next string
1533  resvalue = 1;
1534  return 0;
1535  }
1536 
1537  EXmlNodeType nodetype = kXML_NODE;
1538  bool canhaschilds = true;
1539  char endsymbol = '/';
1540 
1541  // this is case of processing instructions node
1542  if (*inp->fCurrent=='?') {
1543  if (!inp->ShiftCurrent()) return 0;
1544  nodetype = kXML_PI_NODE;
1545  canhaschilds = false;
1546  endsymbol = '?';
1547  }
1548 
1549  if (!inp->SkipSpaces()) return 0;
1550  int len = inp->LocateIdentifier();
1551  if (len<=0) return 0;
1552  node = (SXmlNode_t*) AllocateNode(len, xmlparent);
1553  char* nameptr = SXmlNode_t::Name(node);
1554  node->fType = nodetype;
1555 
1556  strncpy(nameptr, inp->fCurrent, len); // here copied content without padding 0
1557  nameptr+=len;
1558  *nameptr = 0; // add 0 to the end
1559 
1560  char* colon = strchr(SXmlNode_t::Name(node),':');
1561  if ((colon!=0) && (parent!=0)) {
1562  *colon = 0;
1563  node->fNs = (SXmlAttr_t*) FindNs(xmlparent, SXmlNode_t::Name(node));
1564  *colon =':';
1565  }
1566 
1567  if (!inp->ShiftCurrent(len)) return 0;
1568 
1569  do {
1570  if (!inp->SkipSpaces()) return 0;
1571 
1572  char nextsymb = *inp->fCurrent;
1573 
1574  if (nextsymb==endsymbol) { // this is end of short node like <node ... />
1575  if (!inp->ShiftCurrent()) return 0;
1576  if (*inp->fCurrent=='>') {
1577  if (!inp->ShiftCurrent()) return 0;
1578 
1579  if (node->fNs!=0)
1581 
1582  inp->SkipSpaces(true); // locate start of next string
1583  resvalue = 2;
1584  return node;
1585  } else return 0;
1586  } else
1587  if (nextsymb=='>') { // this is end of parent node, lets find all childs
1588  if (!canhaschilds) { resvalue = -11; return 0; }
1589 
1590  if (!inp->ShiftCurrent()) return 0;
1591 
1592  do {
1593  ReadNode(node, inp, resvalue);
1594  } while (resvalue==2);
1595 
1596  if (resvalue==1) {
1597  resvalue = 2;
1598  return node;
1599  } else return 0;
1600  } else {
1601  int attrlen = inp->LocateIdentifier();
1602  if (attrlen<=0) { resvalue = -6; return 0; }
1603 
1604  char* valuestart = inp->fCurrent+attrlen;
1605 
1606  int valuelen = inp->LocateAttributeValue(valuestart);
1607  if (valuelen<3) { resvalue = -7; return 0; }
1608 
1609  SXmlAttr_t* attr = (SXmlAttr_t*) AllocateAttr(attrlen, valuelen-3, (XMLNodePointer_t) node);
1610 
1611  char* attrname = SXmlAttr_t::Name(attr);
1612  strncpy(attrname, inp->fCurrent, attrlen);
1613  attrname+=attrlen;
1614  *attrname = 0;
1615  attrname++;
1616  UnpackSpecialCharacters(attrname, valuestart+2, valuelen-3);
1617 
1618  if (!inp->ShiftCurrent(attrlen+valuelen)) return 0;
1619 
1620  attrname = SXmlAttr_t::Name(attr);
1621 
1622  if ((strlen(attrname)>6) && (strstr(attrname,"xmlns:")==attrname)) {
1623  if (strcmp(SXmlNode_t::Name(node), attrname + 6)!=0) {
1624  resvalue = -8;
1625  //return 0;
1626  }
1627  if (node->fNs!=0) {
1628  resvalue = -9;
1629  //return 0;
1630  }
1631  node->fNs = attr;
1632  }
1633  }
1634  } while (true);
1635 
1636  return nullptr;
1637 }
1638 
1639 //______________________________________________________________________________
1640 void dabc::Xml::DisplayError(int error, int linenumber)
1641 {
1642  // Displays xml parsing error
1643  switch(error) {
1644  case -11: EOUT("Node cannot be closed with > symbol at line %d, for instance <?xml ... ?> node", linenumber); break;
1645  case -10: EOUT("Error in xml comments definition at line %d, must be <!-- comments -->", linenumber); break;
1646  case -9: EOUT("Multiple name space definitions not allowed, line %d", linenumber); break;
1647  case -8: EOUT("Invalid namespace specification, line %d", linenumber); break;
1648  case -7: EOUT("Invalid attribute value, line %d", linenumber); break;
1649  case -6: EOUT("Invalid identifier for node attribute, line %d", linenumber); break;
1650  case -5: EOUT("Mismatch between open and close nodes, line %d", linenumber); break;
1651  case -4: EOUT("Unexpected close node, line %d", linenumber); break;
1652  case -3: EOUT("Valid identifier for close node is missing, line %d", linenumber); break;
1653  case -2: EOUT("No multiple content entries allowed, line %d", linenumber); break;
1654  case -1: EOUT("Unexpected end of xml file"); break;
1655  default: EOUT("XML syntax error at line %d", linenumber); break;
1656  }
1657 }
1658 
bool ShiftCurrent(int sz=1)
Definition: XmlEngine.cxx:272
int LocateAttributeValue(char *start)
Definition: XmlEngine.cxx:373
bool ExpandStream(char *&curr)
Definition: XmlEngine.cxx:233
std::istream * fInp
Definition: XmlEngine.cxx:150
bool CheckFor(const char *str)
Definition: XmlEngine.cxx:301
bool SkipSpaces(bool tillendl=false)
Definition: XmlEngine.cxx:288
int DoRead(char *buf, int maxsize)
Definition: XmlEngine.cxx:214
bool SkipComments() const
Definition: XmlEngine.cxx:202
XmlInputStream(bool isfilename, const char *filename, int ibufsize)
Definition: XmlEngine.cxx:167
virtual ~XmlInputStream()
Definition: XmlEngine.cxx:194
int SearchFor(const char *str)
Definition: XmlEngine.cxx:313
const char * fInpStr
Definition: XmlEngine.cxx:151
void Put(char symb, int cnt=1)
Definition: XmlEngine.cxx:131
XmlOutputStream(const char *filename, int bufsize=20000)
Definition: XmlEngine.cxx:71
std::string * fOutStr
Definition: XmlEngine.cxx:64
void Init(int bufsize)
Definition: XmlEngine.cxx:85
void OutputChar(char symb)
Definition: XmlEngine.cxx:111
virtual ~XmlOutputStream()
Definition: XmlEngine.cxx:93
void Write(const char *str)
Definition: XmlEngine.cxx:117
std::ostream * fOut
Definition: XmlEngine.cxx:63
XmlOutputStream(std::string *outstr, int bufsize=20000)
Definition: XmlEngine.cxx:78
#define EOUT(args ...)
Definition: logging.h:150
XMLNsPointer_t FindNs(XMLNodePointer_t xmlnode, const char *nsname)
Definition: XmlEngine.cxx:1267
int GetIntAttr(XMLNodePointer_t node, const char *name)
Definition: XmlEngine.cxx:426
bool ValidateVersion(XMLDocPointer_t doc, const char *version=nullptr)
Definition: XmlEngine.cxx:1135
void AssignDtd(XMLDocPointer_t xmldoc, const char *dtdname, const char *rootname)
Definition: XmlEngine.cxx:1000
void UnpackSpecialCharacters(char *target, const char *source, int srclen)
Definition: XmlEngine.cxx:1299
XMLDocPointer_t ParseFile(const char *filename, bool showerr=true)
Definition: XmlEngine.cxx:1078
void SaveDoc(XMLDocPointer_t xmldoc, const char *filename, int layout=1)
Definition: XmlEngine.cxx:1026
void FreeAttr(XMLNodePointer_t xmlnode, const char *name)
Definition: XmlEngine.cxx:477
bool HasAttr(XMLNodePointer_t xmlnode, const char *name)
Definition: XmlEngine.cxx:397
bool AddDocRawLine(XMLDocPointer_t xmldoc, const char *line)
Definition: XmlEngine.cxx:739
void AddChildFirst(XMLNodePointer_t parent, XMLNodePointer_t child)
Definition: XmlEngine.cxx:672
XMLAttrPointer_t GetFirstAttr(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:518
bool AddRawLine(XMLNodePointer_t parent, const char *line)
Definition: XmlEngine.cxx:722
XMLNodePointer_t DocGetRootElement(XMLDocPointer_t xmldoc)
Definition: XmlEngine.cxx:1062
void UnlinkFreeNode(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:876
const char * GetAttrValue(XMLAttrPointer_t xmlattr)
Definition: XmlEngine.cxx:553
XMLNodePointer_t GetNext(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:925
XMLNodePointer_t GetParent(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:917
const char * GetAttr(XMLNodePointer_t xmlnode, const char *name)
Definition: XmlEngine.cxx:411
void SaveNode(XMLNodePointer_t xmlnode, XmlOutputStream *out, int layout, int level)
Definition: XmlEngine.cxx:1359
void UnlinkNode(XMLNodePointer_t node)
Definition: XmlEngine.cxx:822
void AddChild(XMLNodePointer_t parent, XMLNodePointer_t child)
Definition: XmlEngine.cxx:652
void FreeNode(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:847
XMLAttrPointer_t NewAttr(XMLNodePointer_t xmlnode, XMLNsPointer_t, const char *name, const char *value)
Definition: XmlEngine.cxx:438
XMLAttrPointer_t NewIntAttr(XMLNodePointer_t xmlnode, const char *name, int value)
Definition: XmlEngine.cxx:465
XMLDocPointer_t ParseString(const char *xmlstring, bool showerr=true)
Definition: XmlEngine.cxx:1089
bool AddDocStyleSheet(XMLDocPointer_t xmldoc, const char *href, const char *type="text/css", const char *title=nullptr, int alternate=-1, const char *media=nullptr, const char *charset=nullptr)
Definition: XmlEngine.cxx:798
void CleanNode(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:962
const char * GetNodeName(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:885
XMLNodePointer_t GetChild(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:906
const char * GetNodeContent(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:893
XMLNsPointer_t NewNS(XMLNodePointer_t xmlnode, const char *reference, const char *name=nullptr)
Definition: XmlEngine.cxx:595
XMLNodePointer_t NewChild(XMLNodePointer_t parent, XMLNsPointer_t ns, const char *name, const char *content=nullptr)
Definition: XmlEngine.cxx:564
XMLAttrPointer_t AllocateAttr(int namelen, int valuelen, XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:1242
XMLNodePointer_t ReadSingleNode(const char *src)
Definition: XmlEngine.cxx:1171
XMLNodePointer_t ReadNode(XMLNodePointer_t xmlparent, XmlInputStream *inp, int &resvalue)
Definition: XmlEngine.cxx:1453
void FreeDoc(XMLDocPointer_t xmldoc)
Definition: XmlEngine.cxx:1013
const char * GetNSReference(XMLNsPointer_t ns)
Definition: XmlEngine.cxx:643
void FreeAllAttr(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:501
XMLNsPointer_t GetNS(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:620
const char * GetAttrName(XMLAttrPointer_t xmlattr)
Definition: XmlEngine.cxx:542
char * Makestr(const char *str)
Definition: XmlEngine.cxx:1193
void ShiftToNext(XMLNodePointer_t &xmlnode, bool tonode=true)
Definition: XmlEngine.cxx:933
bool IsEmptyNode(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:945
void SaveSingleNode(XMLNodePointer_t xmlnode, std::string *res, int layout=1)
Definition: XmlEngine.cxx:1155
bool AddComment(XMLNodePointer_t parent, const char *comment)
Definition: XmlEngine.cxx:689
XMLAttrPointer_t GetNextAttr(XMLAttrPointer_t xmlattr)
Definition: XmlEngine.cxx:532
void DisplayError(int error, int linenumber)
Definition: XmlEngine.cxx:1640
void SkipEmpty(XMLNodePointer_t &xmlnode)
Definition: XmlEngine.cxx:953
XMLNodePointer_t AllocateNode(int namelen, XMLNodePointer_t parent)
Definition: XmlEngine.cxx:1218
bool AddStyleSheet(XMLNodePointer_t parent, const char *href, const char *type="text/css", const char *title=nullptr, int alternate=-1, const char *media=nullptr, const char *charset=nullptr)
Definition: XmlEngine.cxx:757
void TruncateNsExtension(XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:1283
const char * GetNSName(XMLNsPointer_t ns)
Definition: XmlEngine.cxx:631
char * Makenstr(const char *start, int len)
Definition: XmlEngine.cxx:1206
XMLDocPointer_t NewDoc(const char *version="1.0")
Definition: XmlEngine.cxx:981
void OutputValue(char *value, XmlOutputStream *out)
Definition: XmlEngine.cxx:1332
bool AddDocComment(XMLDocPointer_t xmldoc, const char *comment)
Definition: XmlEngine.cxx:705
void DocSetRootElement(XMLDocPointer_t xmldoc, XMLNodePointer_t xmlnode)
Definition: XmlEngine.cxx:1050
XMLDocPointer_t ParseStream(XmlInputStream *input, bool showerr)
Definition: XmlEngine.cxx:1099
Event manipulation API.
Definition: api.h:23
void * XMLAttrPointer_t
Definition: XmlEngine.h:27
void * XMLNodePointer_t
Definition: XmlEngine.h:25
EXmlNodeType
Definition: XmlEngine.cxx:33
@ kXML_PI_NODE
Definition: XmlEngine.cxx:36
@ kXML_COMMENT
Definition: XmlEngine.cxx:35
@ kXML_RAWLINE
Definition: XmlEngine.cxx:37
@ kXML_NODE
Definition: XmlEngine.cxx:34
void * XMLNsPointer_t
Definition: XmlEngine.h:26
void * XMLDocPointer_t
Definition: XmlEngine.h:28
SXmlAttr_t * fNext
Definition: XmlEngine.cxx:27
static char * Name(void *arg)
Definition: XmlEngine.cxx:30
SXmlNode_t * fRootNode
Definition: XmlEngine.cxx:54
SXmlNode_t * fParent
Definition: XmlEngine.cxx:47
SXmlNode_t * fLastChild
Definition: XmlEngine.cxx:46
static char * Name(void *arg)
Definition: XmlEngine.cxx:50
SXmlAttr_t * fNs
Definition: XmlEngine.cxx:43
EXmlNodeType fType
Definition: XmlEngine.cxx:41
SXmlNode_t * fNext
Definition: XmlEngine.cxx:44
SXmlAttr_t * fAttr
Definition: XmlEngine.cxx:42
SXmlNode_t * fChild
Definition: XmlEngine.cxx:45