TXMLEngine.cxx

Go to the documentation of this file.
00001 // @(#)root/xml:$Id: TXMLEngine.cxx 36636 2010-11-12 17:04:40Z pcanal $
00002 // Author: Sergey Linev  10.05.2004
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //________________________________________________________________________
00013 //
00014 //  TXMLEngine class is used to write and read ROOT XML files - TXMLFile.
00015 //  It does not conform to complete xml standard and cannot be used
00016 //  as parser for arbitrary XML files. For such cases TXMLParser should
00017 //  be used. This class was introduced to exclude dependency from
00018 //  external libraries (like libxml2) and improve speed / memory consumption.
00019 //
00020 //________________________________________________________________________
00021 
00022 #include "TXMLEngine.h"
00023 
00024 #include "Riostream.h"
00025 #include "TString.h"
00026 #include <stdlib.h>
00027 #include <string.h>
00028 
00029 ClassImp(TXMLEngine);
00030 
00031 struct SXmlAttr_t {
00032    SXmlAttr_t  *fNext;
00033    // after structure itself memory for attribute name is preserved
00034    // if first byte is 0, this is special attribute
00035    static inline char* Name(void* arg) { return (char*)arg + sizeof(SXmlAttr_t); }
00036 };
00037 
00038 enum EXmlNodeType {
00039   kXML_NODE = 1,       // normal node with childs
00040   kXML_COMMENT = 2,    // comment (stored as value of node fName)
00041   kXML_PI_NODE = 3,    // processing instructions node (like <?name  attr="" ?>
00042   kXML_RAWLINE = 4     // just one line of xml code
00043 };
00044 
00045 struct SXmlNode_t {
00046    EXmlNodeType fType;    //  this is node type - node, comment, processing instruction and so on
00047    SXmlAttr_t  *fAttr;    // first attribute 
00048    SXmlAttr_t  *fNs;      // name space definition (if any)
00049    SXmlNode_t  *fNext;    // next node on the same level of hierarchy 
00050    SXmlNode_t  *fChild;   // first child node
00051    SXmlNode_t  *fLastChild; // last child node
00052    SXmlNode_t  *fParent;   // parent node
00053    // consequent bytes after structure are node name
00054    // if first byte is 0, next is node content
00055    static inline char* Name(void* arg) { return (char*)arg + sizeof(SXmlNode_t); }
00056 };
00057 
00058 #define XML_NODE_NAME(arg) (
00059 
00060 
00061 struct SXmlDoc_t {
00062    SXmlNode_t  *fRootNode;
00063    char        *fDtdName;
00064    char        *fDtdRoot;
00065 };
00066 
00067 class TXMLOutputStream {
00068 protected:
00069 
00070    std::ostream  *fOut;
00071    TString       *fOutStr;
00072    char          *fBuf;
00073    char          *fCurrent;
00074    char          *fMaxAddr;
00075    char          *fLimitAddr;
00076 
00077 public:
00078    TXMLOutputStream(const char* filename, Int_t bufsize = 20000)
00079    {
00080       fOut = new std::ofstream(filename);
00081       fOutStr = 0;
00082       Init(bufsize);
00083    }
00084 
00085    TXMLOutputStream(TString* outstr, Int_t bufsize = 20000)
00086    {
00087       fOut = 0;
00088       fOutStr = outstr;
00089       Init(bufsize);
00090    }
00091    
00092    void Init(Int_t bufsize)
00093    {
00094       fBuf = (char*) malloc(bufsize);
00095       fCurrent = fBuf;
00096       fMaxAddr = fBuf + bufsize;
00097       fLimitAddr = fBuf + int(bufsize*0.75);
00098    }
00099 
00100    virtual ~TXMLOutputStream()
00101    {
00102       if (fCurrent!=fBuf) OutputCurrent();
00103       delete fOut;
00104    }
00105 
00106    void OutputCurrent()
00107    {
00108       if (fCurrent!=fBuf) {
00109          if (fOut!=0)
00110             fOut->write(fBuf, fCurrent-fBuf);
00111          else if (fOutStr!=0) 
00112             fOutStr->Append(fBuf, fCurrent-fBuf);
00113       }
00114       fCurrent = fBuf;
00115    }
00116    
00117    void OutputChar(char symb) 
00118    {
00119       if (fOut!=0) fOut->put(symb); else
00120       if (fOutStr!=0) fOutStr->Append(symb);
00121    }
00122 
00123    void Write(const char* str)
00124    {
00125       int len = strlen(str);
00126       if (fCurrent+len>=fMaxAddr) {
00127          OutputCurrent();
00128          fOut->write(str,len);
00129       } else {
00130          while (*str)
00131            *fCurrent++ = *str++;
00132          if (fCurrent>fLimitAddr)
00133             OutputCurrent();
00134       }
00135    }
00136 
00137    void Put(char symb, Int_t cnt=1)
00138    {
00139       if (fCurrent+cnt>=fMaxAddr)
00140          OutputCurrent();
00141       if (fCurrent+cnt>=fMaxAddr)
00142          for(int n=0;n<cnt;n++)
00143             OutputChar(symb);
00144       else {
00145          for(int n=0;n<cnt;n++)
00146             *fCurrent++ = symb;
00147          if (fCurrent>fLimitAddr)
00148             OutputCurrent();
00149       }
00150    }
00151 };
00152 
00153 class TXMLInputStream {
00154 protected:
00155 
00156    std::istream  *fInp;
00157    const char    *fInpStr;
00158    Int_t          fInpStrLen;    
00159    
00160    char          *fBuf;
00161    Int_t          fBufSize;
00162 
00163    char          *fMaxAddr;
00164    char          *fLimitAddr;
00165 
00166    Int_t          fTotalPos;
00167    Int_t          fCurrentLine;
00168    
00169 public:
00170 
00171    char           *fCurrent;
00172 
00173    TXMLInputStream(bool isfilename, const char* filename, Int_t ibufsize)
00174    {
00175       if (isfilename) {
00176          fInp = new std::ifstream(filename);
00177          fInpStr = 0;
00178          fInpStrLen = 0;
00179       } else {
00180          fInp = 0;
00181          fInpStr = filename;
00182          fInpStrLen = filename==0 ? 0 : strlen(filename);
00183       }
00184    
00185       fBufSize = ibufsize;
00186       fBuf = (char*) malloc(fBufSize);
00187 
00188       fCurrent = 0;
00189       fMaxAddr = 0;
00190 
00191       int len = DoRead(fBuf, fBufSize);
00192       fCurrent = fBuf;
00193       fMaxAddr = fBuf+len;
00194       fLimitAddr = fBuf + int(len*0.75);
00195 
00196       fTotalPos = 0;
00197       fCurrentLine = 1;
00198    }
00199 
00200    virtual ~TXMLInputStream()
00201    {
00202       delete fInp; fInp = 0;
00203       free(fBuf); fBuf = 0;
00204    }
00205 
00206    inline Bool_t EndOfFile() { return (fInp!=0) ? fInp->eof() : (fInpStrLen<=0); }
00207    
00208    inline Bool_t EndOfStream() { return EndOfFile() && (fCurrent>=fMaxAddr); }
00209 
00210    int DoRead(char* buf, int maxsize)
00211    {
00212       if (EndOfFile()) return 0;
00213       if (fInp!=0) {
00214          fInp->get(buf, maxsize, 0);
00215          maxsize = strlen(buf);
00216       } else {
00217          if (maxsize>fInpStrLen) maxsize = fInpStrLen;
00218          strncpy(buf, fInpStr, maxsize);
00219          fInpStr+=maxsize;
00220          fInpStrLen-=maxsize;
00221       }
00222       return maxsize;
00223    }
00224 
00225    Bool_t ExpandStream()
00226    {
00227       if (EndOfFile()) return kFALSE;
00228       fBufSize*=2;
00229       int curlength = fMaxAddr - fBuf;
00230       char* newbuf = (char*) realloc(fBuf, fBufSize);
00231       if (newbuf==0) return kFALSE;
00232       
00233       fMaxAddr = newbuf + (fMaxAddr - fBuf);
00234       fCurrent = newbuf + (fCurrent - fBuf);
00235       fLimitAddr = newbuf + (fLimitAddr - fBuf);
00236       fBuf = newbuf;
00237       
00238       int len = DoRead(fMaxAddr, fBufSize-curlength);
00239       if (len==0) return kFALSE;
00240       fMaxAddr += len;
00241       fLimitAddr += int(len*0.75);
00242       return kTRUE;
00243    }
00244 
00245    Bool_t ShiftStream()
00246    {
00247       if (fCurrent<fLimitAddr) return kTRUE; // everything ok, can cntinue
00248       if (EndOfFile()) return kTRUE;
00249       int rest_len = fMaxAddr - fCurrent;
00250       memmove(fBuf, fCurrent, rest_len); 
00251       int read_len = DoRead(fBuf + rest_len, fBufSize - rest_len);
00252 
00253       fCurrent = fBuf;
00254       fMaxAddr = fBuf + rest_len + read_len;
00255       fLimitAddr = fBuf + int((rest_len + read_len)*0.75);
00256       return kTRUE;
00257    }
00258 
00259    Int_t  TotalPos() { return fTotalPos; }
00260 
00261    Int_t CurrentLine() { return fCurrentLine; }
00262 
00263    Bool_t ShiftCurrent(Int_t sz = 1)
00264    {
00265       for(int n=0;n<sz;n++) {
00266          if (*fCurrent==10) fCurrentLine++;
00267          if (fCurrent>=fLimitAddr) {
00268             ShiftStream();
00269             if (fCurrent>=fMaxAddr) return kFALSE;
00270          }
00271          fCurrent++;
00272       }
00273       fTotalPos+=sz;
00274       return kTRUE;
00275    }
00276 
00277    Bool_t SkipSpaces(Bool_t tillendl = kFALSE)
00278    {
00279       do {
00280          char symb = *fCurrent;
00281          if ((symb>26) && (symb!=' ')) return kTRUE;
00282 
00283          if (!ShiftCurrent()) return kFALSE;
00284 
00285          if (tillendl && (symb==10)) return kTRUE;
00286       } while (fCurrent<fMaxAddr);
00287       return kFALSE;
00288    }
00289 
00290    Bool_t CheckFor(const char* str)
00291    {
00292       // Check if in current position we see specified string 
00293       int len = strlen(str);
00294       while (fCurrent+len>fMaxAddr)
00295          if (!ExpandStream()) return kFALSE;
00296       char* curr = fCurrent;
00297       while (*str != 0)
00298          if (*str++ != *curr++) return kFALSE;
00299       return ShiftCurrent(len);
00300    }
00301 
00302    Int_t SearchFor(const char* str)
00303    {
00304       // Serach for specified string in the stream
00305       // return number of symbols before string was found, -1 if error
00306       int len = strlen(str);
00307      
00308       char* curr = fCurrent;
00309 
00310       do {
00311          curr++; 
00312          while (curr+len>fMaxAddr)
00313             if (!ExpandStream()) return -1;
00314          char* chk0 = curr;
00315          const char* chk = str;
00316          Bool_t find = kTRUE;
00317          while (*chk != 0)
00318             if (*chk++ != *chk0++) { find = kFALSE; break; }
00319          // if string found, shift to the next symbol after string   
00320          if (find) return curr - fCurrent;
00321       } while (curr<fMaxAddr);
00322       return -1;
00323    }
00324 
00325    Int_t LocateIdentifier()
00326    {
00327       char symb = *fCurrent;
00328       Bool_t ok = (((symb>='a') && (symb<='z')) ||
00329                   ((symb>='A') && (symb<='Z')) ||
00330                   (symb=='_'));
00331       if (!ok) return 0;
00332 
00333       char* curr = fCurrent;
00334 
00335       do {
00336          curr++;
00337          if (curr>=fMaxAddr)
00338             if (!ExpandStream()) return 0;
00339          symb = *curr;
00340          ok = ((symb>='a') && (symb<='z')) ||
00341                ((symb>='A') && (symb<='Z')) ||
00342                ((symb>='0') && (symb<='9')) ||
00343                (symb==':') || (symb=='_') || (symb=='-');
00344          if (!ok) return curr-fCurrent;
00345       } while (curr<fMaxAddr);
00346       return 0;
00347    }
00348 
00349    Int_t LocateContent()
00350    {
00351       char* curr = fCurrent;
00352       while (curr<fMaxAddr) {
00353          char symb = *curr;
00354          if (symb=='<') return curr - fCurrent;
00355          curr++;
00356          if (curr>=fMaxAddr)
00357             if (!ExpandStream()) return -1;
00358       }
00359       return -1;
00360    }
00361 
00362    Int_t LocateAttributeValue(char* start)
00363    {
00364       char* curr = start;
00365       if (curr>=fMaxAddr)
00366          if (!ExpandStream()) return 0;
00367       if (*curr!='=') return 0;
00368       curr++;
00369       if (curr>=fMaxAddr)
00370          if (!ExpandStream()) return 0;
00371       if (*curr!='"') return 0;
00372       do {
00373          curr++;
00374          if (curr>=fMaxAddr)
00375             if (!ExpandStream()) return 0;
00376          if (*curr=='"') return curr-start+1;
00377       } while (curr<fMaxAddr);
00378       return 0;
00379    }
00380 };
00381 
00382 //______________________________________________________________________________
00383 TXMLEngine::TXMLEngine()
00384 {
00385    // default (normal) constructor of TXMLEngine class
00386    fSkipComments = kFALSE;
00387 }
00388 
00389 
00390 //______________________________________________________________________________
00391 TXMLEngine::~TXMLEngine()
00392 {
00393    // destructor for TXMLEngine object
00394 
00395 }
00396 
00397 //______________________________________________________________________________
00398 Bool_t TXMLEngine::HasAttr(XMLNodePointer_t xmlnode, const char* name)
00399 {
00400    // checks if node has attribute of specified name
00401 
00402    if ((xmlnode==0) || (name==0)) return kFALSE;
00403    SXmlAttr_t* attr = ((SXmlNode_t*)xmlnode)->fAttr;
00404    while (attr!=0) {
00405       if (strcmp(SXmlAttr_t::Name(attr),name)==0) return kTRUE;
00406       attr = attr->fNext;
00407    }
00408    return kFALSE;
00409 }
00410 
00411 //______________________________________________________________________________
00412 const char* TXMLEngine::GetAttr(XMLNodePointer_t xmlnode, const char* name)
00413 {
00414    // returns value of attribute for xmlnode
00415 
00416    if (xmlnode==0) return 0;
00417    SXmlAttr_t* attr = ((SXmlNode_t*)xmlnode)->fAttr;
00418    while (attr!=0) {
00419       if (strcmp(SXmlAttr_t::Name(attr),name)==0)
00420          return SXmlAttr_t::Name(attr) + strlen(name) + 1;
00421       attr = attr->fNext;
00422    }
00423    return 0;
00424 }
00425 
00426 //______________________________________________________________________________
00427 Int_t TXMLEngine::GetIntAttr(XMLNodePointer_t xmlnode, const char* name)
00428 {
00429    // returns value of attribute as integer
00430 
00431    if (xmlnode==0) return 0;
00432    Int_t res = 0;
00433    const char* attr = GetAttr(xmlnode, name);
00434    if (attr) sscanf(attr, "%d", &res);
00435    return res;
00436 }
00437 
00438 //______________________________________________________________________________
00439 XMLAttrPointer_t TXMLEngine::NewAttr(XMLNodePointer_t xmlnode, XMLNsPointer_t,
00440                                      const char* name, const char* value)
00441 {
00442    // creates new attribute for xmlnode,
00443    // namespaces are not supported for attributes
00444 
00445    if (xmlnode==0) return 0;
00446 
00447    int namelen(name != 0 ? strlen(name) : 0);
00448    int valuelen(value != 0 ? strlen(value) : 0);
00449    SXmlAttr_t* attr = (SXmlAttr_t*) AllocateAttr(namelen, valuelen, xmlnode);
00450 
00451    char* attrname = SXmlAttr_t::Name(attr);
00452    if (namelen>0)
00453       strncpy(attrname, name, namelen+1);
00454    else
00455       *attrname = 0;
00456    attrname += (namelen + 1);
00457    if (valuelen>0)
00458       strncpy(attrname, value, valuelen+1);
00459    else
00460       *attrname = 0;
00461 
00462    return (XMLAttrPointer_t) attr;
00463 }
00464 
00465 //______________________________________________________________________________
00466 XMLAttrPointer_t TXMLEngine::NewIntAttr(XMLNodePointer_t xmlnode,
00467                                       const char* name,
00468                                       Int_t value)
00469 {
00470    // create node attribute with integer value
00471 
00472    char sbuf[30];
00473    sprintf(sbuf,"%d",value);
00474    return NewAttr(xmlnode, 0, name, sbuf);
00475 }
00476 
00477 //______________________________________________________________________________
00478 void TXMLEngine::FreeAttr(XMLNodePointer_t xmlnode, const char* name)
00479 {
00480    // remove attribute from xmlnode
00481 
00482    if (xmlnode==0) return;
00483    SXmlAttr_t* attr = ((SXmlNode_t*) xmlnode)->fAttr;
00484    SXmlAttr_t* prev = 0;
00485    while (attr!=0) {
00486       if (strcmp(SXmlAttr_t::Name(attr),name)==0) {
00487          if (prev!=0)
00488             prev->fNext = attr->fNext;
00489          else
00490             ((SXmlNode_t*) xmlnode)->fAttr = attr->fNext;
00491          //fNumNodes--;
00492          free(attr);
00493          return;
00494       }
00495 
00496       prev = attr;
00497       attr = attr->fNext;
00498    }
00499 }
00500 
00501 //______________________________________________________________________________
00502 void TXMLEngine::FreeAllAttr(XMLNodePointer_t xmlnode)
00503 {
00504    // Free all attributes of the node
00505    if (xmlnode==0) return;
00506    
00507    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
00508    SXmlAttr_t* attr = node->fAttr;
00509    while (attr!=0) {
00510       SXmlAttr_t* next = attr->fNext;
00511       free(attr);
00512       attr = next;
00513    }
00514    node->fAttr = 0;
00515 }
00516 
00517 
00518 //______________________________________________________________________________
00519 XMLAttrPointer_t TXMLEngine::GetFirstAttr(XMLNodePointer_t xmlnode)
00520 {
00521    // return first attribute in the list, namespace (if exists) will be skiped
00522    
00523    if (xmlnode==0) return 0;
00524    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
00525 
00526    SXmlAttr_t* attr = node->fAttr;
00527    if ((attr!=0) && (node->fNs==attr)) attr = attr->fNext;
00528    
00529    return (XMLAttrPointer_t) attr;
00530 }
00531 
00532 //______________________________________________________________________________
00533 XMLAttrPointer_t TXMLEngine::GetNextAttr(XMLAttrPointer_t xmlattr)
00534 {
00535    // return next attribute in the list
00536    
00537    if (xmlattr==0) return 0;
00538    
00539    return (XMLAttrPointer_t) ((SXmlAttr_t*) xmlattr)->fNext;
00540 }
00541 
00542 //______________________________________________________________________________
00543 const char* TXMLEngine::GetAttrName(XMLAttrPointer_t xmlattr)
00544 {
00545    // return name of the attribute
00546 
00547    if (xmlattr==0) return 0;
00548 
00549    return SXmlAttr_t::Name(xmlattr);
00550    
00551 }
00552 
00553 //______________________________________________________________________________
00554 const char* TXMLEngine::GetAttrValue(XMLAttrPointer_t xmlattr)
00555 {
00556    // return value of attribute
00557    
00558    if (xmlattr==0) return 0;
00559    
00560    const char* attrname = SXmlAttr_t::Name(xmlattr);
00561    return attrname + strlen(attrname) + 1;
00562 }
00563 
00564 //______________________________________________________________________________
00565 XMLNodePointer_t TXMLEngine::NewChild(XMLNodePointer_t parent, XMLNsPointer_t ns,
00566                                       const char* name, const char* content)
00567 {
00568    // create new child element for parent node
00569 
00570    int namelen(name!=0 ? strlen(name) : 0);
00571 
00572    SXmlNode_t* node = (SXmlNode_t*) AllocateNode(namelen, parent);
00573 
00574    if (namelen>0)
00575       strncpy(SXmlNode_t::Name(node), name, namelen+1);
00576    else
00577       *SXmlNode_t::Name(node) = 0;
00578 
00579    node->fNs = (SXmlAttr_t*) ns;
00580    if (content!=0) {
00581       int contlen = strlen(content);
00582       if (contlen>0) {
00583          SXmlNode_t* contnode = (SXmlNode_t*) AllocateNode(contlen+1, node);
00584          char* cptr = SXmlNode_t::Name(contnode);
00585          // first zero indicate that this is just content value
00586          *cptr = 0;
00587          cptr++;
00588          strncpy(cptr, content, contlen+1);
00589       }
00590    }
00591 
00592    return (XMLNodePointer_t) node;
00593 }
00594 
00595 //______________________________________________________________________________
00596 XMLNsPointer_t TXMLEngine::NewNS(XMLNodePointer_t xmlnode, const char* reference, const char* name)
00597 {
00598    // create namespace attribute for xmlnode.
00599    // namespace attribute will be always the first in list of node attributes
00600 
00601    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
00602    if (name==0) name = SXmlNode_t::Name(node);
00603    int namelen = strlen(name);
00604    char* nsname = new char[namelen+7];
00605    snprintf(nsname, namelen+7, "xmlns:%s", name);
00606 
00607    SXmlAttr_t* first = node->fAttr;
00608    node->fAttr = 0;
00609 
00610    SXmlAttr_t* nsattr = (SXmlAttr_t*) NewAttr(xmlnode, 0, nsname, reference);
00611 
00612    node->fAttr = nsattr;
00613    nsattr->fNext = first;
00614 
00615    node->fNs = nsattr;
00616    delete[] nsname;
00617    return (XMLNsPointer_t) nsattr;
00618 }
00619 
00620 //______________________________________________________________________________
00621 XMLNsPointer_t TXMLEngine::GetNS(XMLNodePointer_t xmlnode)
00622 {
00623    // return namespace attribute  (if exists)
00624    
00625    if (xmlnode==0) return 0;
00626    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
00627 
00628    return (XMLNsPointer_t) node->fNs;
00629 }
00630 
00631 //______________________________________________________________________________
00632 const char* TXMLEngine::GetNSName(XMLNsPointer_t ns)
00633 {
00634    // return name id of namespace
00635    
00636    const char* nsname = GetAttrName((XMLAttrPointer_t)ns);
00637    
00638    if ((nsname!=0) && (strncmp(nsname,"xmlns:",6)==0)) nsname+=6;
00639    
00640    return nsname;
00641 }
00642 
00643 //______________________________________________________________________________
00644 const char* TXMLEngine::GetNSReference(XMLNsPointer_t ns)
00645 {
00646    // return reference id of namespace
00647    
00648    return GetAttrValue((XMLAttrPointer_t)ns);
00649 }
00650 
00651 
00652 //______________________________________________________________________________
00653 void TXMLEngine::AddChild(XMLNodePointer_t parent, XMLNodePointer_t child)
00654 {
00655    // add child element to xmlnode
00656 
00657    if ((parent==0) || (child==0)) return;
00658    SXmlNode_t* pnode = (SXmlNode_t*) parent;
00659    SXmlNode_t* cnode = (SXmlNode_t*) child;
00660    cnode->fParent = pnode;
00661    if (pnode->fLastChild==0) {
00662       pnode->fChild = cnode;
00663       pnode->fLastChild = cnode;
00664    } else {
00665       //SXmlNode_t* ch = pnode->fChild;
00666       //while (ch->fNext!=0) ch=ch->fNext;
00667       pnode->fLastChild->fNext = cnode;
00668       pnode->fLastChild = cnode;
00669    }
00670 }
00671 
00672 //______________________________________________________________________________
00673 void TXMLEngine::AddChildFirst(XMLNodePointer_t parent, XMLNodePointer_t child)
00674 {
00675    // add node as first child 
00676    
00677    if ((parent==0) || (child==0)) return;
00678    SXmlNode_t* pnode = (SXmlNode_t*) parent;
00679    SXmlNode_t* cnode = (SXmlNode_t*) child;
00680    cnode->fParent = pnode;
00681    
00682    cnode->fNext = pnode->fChild;
00683    pnode->fChild = cnode;
00684    
00685    if (pnode->fLastChild==0) pnode->fLastChild = cnode;
00686 }
00687 
00688 
00689 //______________________________________________________________________________
00690 Bool_t TXMLEngine::AddComment(XMLNodePointer_t xmlnode, const char* comment)
00691 {
00692    // Adds comment line to the node
00693    
00694    if ((xmlnode==0) || (comment==0)) return kFALSE;
00695    
00696    int commentlen = strlen(comment);
00697 
00698    SXmlNode_t* node = (SXmlNode_t*) AllocateNode(commentlen, xmlnode);
00699    node->fType = kXML_COMMENT;
00700    strncpy(SXmlNode_t::Name(node), comment, commentlen+1);
00701    
00702    return kTRUE;
00703 }
00704 
00705 //______________________________________________________________________________
00706 Bool_t TXMLEngine::AddDocComment(XMLDocPointer_t xmldoc, const char* comment)
00707 {
00708    // add comment line to the top of the document
00709    
00710    if (xmldoc==0) return kFALSE;
00711    
00712    XMLNodePointer_t rootnode = DocGetRootElement(xmldoc);
00713    UnlinkNode(rootnode);
00714    
00715    bool res = AddComment(((SXmlDoc_t*)xmldoc)->fRootNode, comment);
00716    
00717    AddChild((XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode, rootnode);
00718     
00719    return res; 
00720 }
00721 
00722 //______________________________________________________________________________
00723 Bool_t TXMLEngine::AddRawLine(XMLNodePointer_t xmlnode, const char* line)
00724 {
00725    // Add just line into xml file
00726    // Line should has correct xml syntax that later it can be decoded by xml parser 
00727    // For instance, it can be comment or processing instructions
00728 
00729    if ((xmlnode==0) || (line==0)) return kFALSE;
00730    
00731    int linelen = strlen(line);
00732    SXmlNode_t* node = (SXmlNode_t*) AllocateNode(linelen, xmlnode);
00733    node->fType = kXML_RAWLINE;
00734    strncpy(SXmlNode_t::Name(node), line, linelen+1);
00735    
00736    return kTRUE;
00737 }
00738 
00739 //______________________________________________________________________________
00740 Bool_t TXMLEngine::AddDocRawLine(XMLDocPointer_t xmldoc, const char* line)
00741 {
00742    // Add just line on the top of xml document
00743    // Line should has correct xml syntax that later it can be decoded by xml parser 
00744 
00745    XMLNodePointer_t rootnode = DocGetRootElement(xmldoc);
00746    UnlinkNode(rootnode);
00747    
00748    bool res = AddRawLine(((SXmlDoc_t*)xmldoc)->fRootNode, line);
00749    
00750    AddChild((XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode, rootnode);
00751     
00752    return res; 
00753 
00754 }
00755 
00756 
00757 //______________________________________________________________________________
00758 Bool_t TXMLEngine::AddStyleSheet(XMLNodePointer_t xmlnode, 
00759                                  const char* href, 
00760                                  const char* type,
00761                                  const char* title,
00762                                  int alternate,
00763                                  const char* media,
00764                                  const char* charset)
00765 {
00766    // Adds style sheet definition to the specified node
00767    // Creates <?xml-stylesheet alternate="yes" title="compact" href="small-base.css" type="text/css"?>
00768    // Attributes href and type must be supplied, 
00769    //  other attributes: title, alternate, media, charset are optional
00770    // if alternate==0, attribyte alternate="no" will be created,
00771    // if alternate>0, attribute alternate="yes"
00772    // if alternate<0, attribute will not be created
00773 
00774    if ((xmlnode==0) || (href==0) || (type==0)) return kFALSE;
00775    
00776    const char* nodename = "xml-stylesheet";
00777    int nodenamelen = strlen(nodename);
00778    
00779    SXmlNode_t* node = (SXmlNode_t*) AllocateNode(nodenamelen, xmlnode);
00780    node->fType = kXML_PI_NODE;
00781    strncpy(SXmlNode_t::Name(node), nodename, nodenamelen+1);
00782    
00783    if (alternate>=0)
00784      NewAttr(node, 0, "alternate", (alternate>0) ? "yes" : "no");
00785      
00786    if (title!=0) NewAttr(node, 0, "title", title); 
00787    
00788    NewAttr(node, 0, "href", href);
00789    NewAttr(node, 0, "type", type);
00790 
00791    if (media!=0) NewAttr(node, 0, "media", media); 
00792    if (charset!=0) NewAttr(node, 0, "charset", charset); 
00793 
00794    return kTRUE;
00795 }                                 
00796 
00797 
00798 //______________________________________________________________________________
00799 Bool_t TXMLEngine::AddDocStyleSheet(XMLDocPointer_t xmldoc, 
00800                                     const char* href, 
00801                                     const char* type,
00802                                     const char* title,
00803                                     int alternate,
00804                                     const char* media,
00805                                     const char* charset)
00806 {
00807    // Add style sheet definition on the top of document 
00808 
00809    if (xmldoc==0) return kFALSE;
00810    
00811    XMLNodePointer_t rootnode = DocGetRootElement(xmldoc);
00812    UnlinkNode(rootnode);
00813    
00814    bool res = AddStyleSheet(((SXmlDoc_t*)xmldoc)->fRootNode, 
00815                             href,type,title,alternate,media,charset);
00816    
00817    AddChild((XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode, rootnode);
00818     
00819    return res; 
00820 }
00821 
00822 //______________________________________________________________________________
00823 void TXMLEngine::UnlinkNode(XMLNodePointer_t xmlnode)
00824 {
00825    // unlink (dettach) xml node from parent
00826 
00827    if (xmlnode==0) return;
00828    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
00829 
00830    SXmlNode_t* parent = node->fParent;
00831 
00832    if (parent==0) return;
00833 
00834    if (parent->fChild==node) {
00835       parent->fChild = node->fNext;
00836       if (parent->fLastChild==node)
00837          parent->fLastChild = node->fNext;
00838    } else {
00839       SXmlNode_t* ch = parent->fChild;
00840       while (ch->fNext!=node) ch = ch->fNext;
00841       ch->fNext = node->fNext;
00842       if (parent->fLastChild == node)
00843          parent->fLastChild = ch;
00844    }
00845 }
00846 
00847 //______________________________________________________________________________
00848 void TXMLEngine::FreeNode(XMLNodePointer_t xmlnode)
00849 {
00850    // release all memory, allocated fro this node and
00851    // destroyes node itself
00852 
00853    if (xmlnode==0) return;
00854    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
00855 
00856    SXmlNode_t* child = node->fChild;
00857    while (child!=0) {
00858       SXmlNode_t* next = child->fNext;
00859       FreeNode((XMLNodePointer_t)child);
00860       child = next;
00861    }
00862 
00863    SXmlAttr_t* attr = node->fAttr;
00864    while (attr!=0) {
00865       SXmlAttr_t* next = attr->fNext;
00866       //fNumNodes--;
00867       free(attr);
00868       attr = next;
00869    }
00870 
00871    free(node);
00872 
00873    //fNumNodes--;
00874 }
00875 
00876 //______________________________________________________________________________
00877 void TXMLEngine::UnlinkFreeNode(XMLNodePointer_t xmlnode)
00878 {
00879    // combined operation. Unlink node and free used memory
00880 
00881    UnlinkNode(xmlnode);
00882    FreeNode(xmlnode);
00883 }
00884 
00885 //______________________________________________________________________________
00886 const char* TXMLEngine::GetNodeName(XMLNodePointer_t xmlnode)
00887 {
00888    // returns name of xmlnode
00889 
00890    return xmlnode==0 ? 0 : SXmlNode_t::Name(xmlnode);
00891 }
00892 
00893 //______________________________________________________________________________
00894 const char* TXMLEngine::GetNodeContent(XMLNodePointer_t xmlnode)
00895 {
00896    // get contents (if any) of xml node
00897 
00898    if (xmlnode==0) return 0;
00899    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
00900    if (node->fChild==0) return 0;
00901    const char* childname = SXmlNode_t::Name(node->fChild);
00902    if ((childname==0) || (*childname != 0)) return 0;
00903    return childname + 1;
00904 }
00905 
00906 //______________________________________________________________________________
00907 XMLNodePointer_t TXMLEngine::GetChild(XMLNodePointer_t xmlnode)
00908 {
00909    // returns first child of xml node
00910 
00911    SXmlNode_t* res = xmlnode==0 ? 0 :((SXmlNode_t*) xmlnode)->fChild;
00912    // skip content node
00913    if ((res!=0) && (*SXmlNode_t::Name(res) == 0)) res = res->fNext;
00914    return (XMLNodePointer_t) res;
00915 }
00916 
00917 //______________________________________________________________________________
00918 XMLNodePointer_t TXMLEngine::GetParent(XMLNodePointer_t xmlnode)
00919 {
00920    // returns parent of xmlnode
00921 
00922    return xmlnode==0 ? 0 : (XMLNodePointer_t) ((SXmlNode_t*) xmlnode)->fParent;
00923 }
00924 
00925 //______________________________________________________________________________
00926 XMLNodePointer_t TXMLEngine::GetNext(XMLNodePointer_t xmlnode)
00927 {
00928    // return next to xmlnode node
00929 
00930    return xmlnode==0 ? 0 : (XMLNodePointer_t) ((SXmlNode_t*) xmlnode)->fNext;
00931 }
00932 
00933 //______________________________________________________________________________
00934 void TXMLEngine::ShiftToNext(XMLNodePointer_t &xmlnode, bool tonode)
00935 {
00936    // shifts specified node to next
00937 
00938    do {
00939       xmlnode = xmlnode==0 ? 0 : (XMLNodePointer_t) ((SXmlNode_t*) xmlnode)->fNext;
00940       if ((xmlnode==0) || !tonode) return;
00941       
00942    } while (((SXmlNode_t*) xmlnode)->fType != kXML_NODE);
00943 }
00944 
00945 //______________________________________________________________________________
00946 Bool_t TXMLEngine::IsEmptyNode(XMLNodePointer_t xmlnode)
00947 {
00948    // return kTRUE is this is node with special data like comments to data processing instructions 
00949    
00950    return xmlnode==0 ? kTRUE : (((SXmlNode_t*) xmlnode)->fType != kXML_NODE);
00951 }
00952 
00953 //______________________________________________________________________________
00954 void TXMLEngine::SkipEmpty(XMLNodePointer_t &xmlnode)
00955 {
00956    // Skip all current empty nodes and locate on first "true" node
00957    
00958    if (IsEmptyNode(xmlnode)) ShiftToNext(xmlnode);
00959 }
00960 
00961 
00962 //______________________________________________________________________________
00963 void TXMLEngine::CleanNode(XMLNodePointer_t xmlnode)
00964 {
00965    // remove all childs node from xmlnode
00966 
00967    if (xmlnode==0) return;
00968    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
00969 
00970    SXmlNode_t* child = node->fChild;
00971    while (child!=0) {
00972       SXmlNode_t* next = child->fNext;
00973       FreeNode((XMLNodePointer_t)child);
00974       child = next;
00975    }
00976 
00977    node->fChild = 0;
00978    node->fLastChild = 0;
00979 }
00980 
00981 //______________________________________________________________________________
00982 XMLDocPointer_t TXMLEngine::NewDoc(const char* version)
00983 {
00984    // creates new xml document with provided version
00985 
00986    SXmlDoc_t* doc = new SXmlDoc_t;
00987    doc->fRootNode = (SXmlNode_t*) NewChild(0, 0, "??DummyTopNode??", 0);
00988    
00989    if (version!=0) {
00990       XMLNodePointer_t vernode = NewChild( (XMLNodePointer_t) doc->fRootNode, 0, "xml");
00991       ((SXmlNode_t*) vernode)->fType = kXML_PI_NODE;
00992       NewAttr(vernode, 0, "version", version);
00993    }
00994    
00995    doc->fDtdName = 0;
00996    doc->fDtdRoot = 0;
00997    return (XMLDocPointer_t) doc;
00998 }
00999 
01000 //______________________________________________________________________________
01001 void TXMLEngine::AssignDtd(XMLDocPointer_t xmldoc, const char* dtdname, const char* rootname)
01002 {
01003    // assignes dtd filename to document
01004 
01005    if (xmldoc==0) return;
01006    SXmlDoc_t* doc = (SXmlDoc_t*) xmldoc;
01007    delete[] doc->fDtdName;
01008    doc->fDtdName = Makestr(dtdname);
01009    delete[] doc->fDtdRoot;
01010    doc->fDtdRoot = Makestr(rootname);
01011 }
01012 
01013 //______________________________________________________________________________
01014 void TXMLEngine::FreeDoc(XMLDocPointer_t xmldoc)
01015 {
01016    // frees allocated document data and deletes document itself
01017 
01018    if (xmldoc==0) return;
01019    SXmlDoc_t* doc = (SXmlDoc_t*) xmldoc;
01020    FreeNode((XMLNodePointer_t) doc->fRootNode);
01021    delete[] doc->fDtdName;
01022    delete[] doc->fDtdRoot;
01023    delete doc;
01024 }
01025 
01026 //______________________________________________________________________________
01027 void TXMLEngine::SaveDoc(XMLDocPointer_t xmldoc, const char* filename, Int_t layout)
01028 {
01029    // store document content to file
01030    // if layout<=0, no any spaces or newlines will be placed between
01031    // xmlnodes. Xml file will have minimum size, but nonreadable structure
01032    // if (layout>0) each node will be started from new line,
01033    // and number of spaces will correspond to structure depth.
01034 
01035    if (xmldoc==0) return;
01036 
01037    SXmlDoc_t* doc = (SXmlDoc_t*) xmldoc;
01038 
01039    TXMLOutputStream out(filename, 100000);
01040    
01041    XMLNodePointer_t child = GetChild((XMLNodePointer_t) doc->fRootNode);
01042    
01043    do {
01044       SaveNode(child, &out, layout, 0);
01045       ShiftToNext(child, false);
01046    } while (child!=0);    
01047    
01048 }
01049 
01050 //______________________________________________________________________________
01051 void TXMLEngine::DocSetRootElement(XMLDocPointer_t xmldoc, XMLNodePointer_t xmlnode)
01052 {
01053    // set main (root) node for document
01054 
01055    if (xmldoc==0) return;
01056    
01057    FreeNode(DocGetRootElement(xmldoc));
01058    
01059    AddChild((XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode, xmlnode);
01060 }
01061 
01062 //______________________________________________________________________________
01063 XMLNodePointer_t TXMLEngine::DocGetRootElement(XMLDocPointer_t xmldoc)
01064 {
01065    // returns root node of document
01066 
01067    if (xmldoc==0) return 0;
01068    
01069    XMLNodePointer_t xmlnode = (XMLNodePointer_t) ((SXmlDoc_t*)xmldoc)->fRootNode;
01070    
01071    xmlnode = GetChild(xmlnode);
01072    
01073    ShiftToNext(xmlnode);
01074    
01075    return xmlnode;
01076 }
01077 
01078 //______________________________________________________________________________
01079 XMLDocPointer_t TXMLEngine::ParseFile(const char* filename)
01080 {
01081    // parses content of file and tries to produce xml structures
01082 
01083    if ((filename==0) || (strlen(filename)==0)) return 0;
01084    TXMLInputStream inp(true, filename, 100000);
01085    return ParseStream(&inp);
01086 }
01087 
01088 //______________________________________________________________________________
01089 XMLDocPointer_t TXMLEngine::ParseString(const char* xmlstring)
01090 {
01091    // parses content of string and tries to produce xml structures
01092 
01093    if ((xmlstring==0) || (strlen(xmlstring)==0)) return 0;
01094    TXMLInputStream inp(false, xmlstring, 2*strlen(xmlstring) );
01095    return ParseStream(&inp);
01096 }
01097 
01098 //______________________________________________________________________________
01099 XMLDocPointer_t TXMLEngine::ParseStream(TXMLInputStream* inp)
01100 {
01101    // parses content of the stream and tries to produce xml structures
01102 
01103    if (inp == 0) return 0;
01104    
01105    XMLDocPointer_t xmldoc = NewDoc(0);
01106    
01107    bool success = false;
01108    
01109    Int_t resvalue = 0;
01110    
01111    do {
01112       ReadNode(((SXmlDoc_t*) xmldoc)->fRootNode, inp, resvalue);
01113       
01114       if (resvalue!=2) break;
01115 
01116       // 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)
01117       if (!inp->EndOfStream()) inp->SkipSpaces();
01118 
01119       if (inp->EndOfStream()) {
01120          success = true; 
01121          break;
01122       }
01123    } while (true);
01124    
01125    if (!success) {
01126       DisplayError(resvalue, inp->CurrentLine());
01127       FreeDoc(xmldoc);
01128       return 0;
01129    }
01130    
01131    return xmldoc;
01132 }
01133 
01134 //______________________________________________________________________________
01135 Bool_t TXMLEngine::ValidateVersion(XMLDocPointer_t xmldoc, const char* version)
01136 {
01137    // check that first node is xml processing instruction with correct xml version number
01138     
01139    if (xmldoc==0) return kFALSE;
01140 
01141    XMLNodePointer_t vernode = GetChild((XMLNodePointer_t) ((SXmlDoc_t*) xmldoc)->fRootNode);
01142    if (vernode==0) return kFALSE;
01143    
01144    if (((SXmlNode_t*) vernode)->fType!=kXML_PI_NODE) return kFALSE;
01145    if (strcmp(GetNodeName(vernode), "xml")!=0) return kFALSE;
01146    
01147    const char* value = GetAttr(vernode,"version");
01148    if (value==0) return kFALSE; 
01149    if (version==0) version = "1.0";
01150    
01151    return strcmp(version,value)==0;
01152 }
01153 
01154 //______________________________________________________________________________
01155 void TXMLEngine::SaveSingleNode(XMLNodePointer_t xmlnode, TString* res, Int_t layout)
01156 {
01157    // convert single xml node (and its child node) to string 
01158    // if layout<=0, no any spaces or newlines will be placed between
01159    // xmlnodes. Xml file will have minimum size, but nonreadable structure
01160    // if (layout>0) each node will be started from new line,
01161    // and number of spaces will correspond to structure depth.
01162    
01163    if ((res==0) || (xmlnode==0)) return; 
01164    
01165    TXMLOutputStream out(res, 10000);
01166 
01167    SaveNode(xmlnode, &out, layout, 0);
01168 }
01169 
01170 //______________________________________________________________________________
01171 XMLNodePointer_t TXMLEngine::ReadSingleNode(const char* src)
01172 {
01173    // read single xml node from provided string
01174     
01175    if (src==0) return 0;
01176    
01177    TXMLInputStream inp(false, src, 10000);
01178 
01179    Int_t resvalue;
01180 
01181    XMLNodePointer_t xmlnode = ReadNode(0, &inp, resvalue);
01182 
01183    if (resvalue<=0) {
01184       DisplayError(resvalue, inp.CurrentLine());
01185       FreeNode(xmlnode);
01186       return 0;
01187    }
01188    
01189    return xmlnode; 
01190 }
01191 
01192 //______________________________________________________________________________
01193 char* TXMLEngine::Makestr(const char* str)
01194 {
01195    // creates char* variable with copy of provided string
01196 
01197    if (str==0) return 0;
01198    int len = strlen(str);
01199    if (len==0) return 0;
01200    char* res = new char[len+1];
01201    strncpy(res, str, len+1);
01202    return res;
01203 }
01204 
01205 //______________________________________________________________________________
01206 char* TXMLEngine::Makenstr(const char* str, int len)
01207 {
01208    // creates char* variable with copy of len symbols from provided string
01209 
01210    if ((str==0) || (len==0)) return 0;
01211    char* res = new char[len+1];
01212    strncpy(res, str, len);
01213    *(res+len) = 0;
01214    return res;
01215 }
01216 
01217 //______________________________________________________________________________
01218 XMLNodePointer_t TXMLEngine::AllocateNode(int namelen, XMLNodePointer_t parent)
01219 {
01220    // Allocates new xml node with specified namelength
01221 
01222    //fNumNodes++;
01223 
01224    SXmlNode_t* node = (SXmlNode_t*) malloc(sizeof(SXmlNode_t) + namelen + 1);
01225 
01226    node->fType = kXML_NODE;
01227    node->fParent = 0;
01228    node->fNs = 0;
01229    node->fAttr = 0;
01230    node->fChild = 0;
01231    node->fLastChild = 0;
01232    node->fNext = 0;
01233 
01234    if (parent!=0)
01235       AddChild(parent, (XMLNodePointer_t) node);
01236 
01237    return (XMLNodePointer_t) node;
01238 }
01239 
01240 //______________________________________________________________________________
01241 XMLAttrPointer_t TXMLEngine::AllocateAttr(int namelen, int valuelen, XMLNodePointer_t xmlnode)
01242 {
01243    // Allocate new attribute with specified name length and value length
01244 
01245    //fNumNodes++;
01246 
01247    SXmlAttr_t* attr = (SXmlAttr_t*) malloc(sizeof(SXmlAttr_t) + namelen + 1 + valuelen + 1);
01248 
01249    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
01250 
01251    attr->fNext = 0;
01252 
01253    if (node->fAttr==0)
01254       node->fAttr = attr;
01255    else {
01256       SXmlAttr_t* d = node->fAttr;
01257       while (d->fNext!=0) d = d->fNext;
01258       d->fNext = attr;
01259    }
01260 
01261    return (XMLAttrPointer_t) attr;
01262 }
01263 
01264 //______________________________________________________________________________
01265 XMLNsPointer_t TXMLEngine::FindNs(XMLNodePointer_t xmlnode, const char* name)
01266 {
01267    // define if namespace of that name exists for xmlnode
01268 
01269    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
01270    while (node!=0) {
01271       if (node->fNs!=0) {
01272          const char* nsname = SXmlAttr_t::Name(node->fNs) + 6;
01273          if (strcmp(nsname, name)==0) return node->fNs;
01274       }
01275       node = node->fParent;
01276    }
01277    return 0;
01278 }
01279 
01280 //______________________________________________________________________________
01281 void TXMLEngine::TruncateNsExtension(XMLNodePointer_t xmlnode)
01282 {
01283    // removes namespace extension of nodename
01284 
01285    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
01286    if (node==0) return;
01287    char* colon = strchr(SXmlNode_t::Name(node),':');
01288    if (colon==0) return;
01289 
01290    char* copyname = SXmlNode_t::Name(node);
01291 
01292    while (*colon!=0)
01293      *(copyname++) = *(++colon);
01294 }
01295 
01296 //______________________________________________________________________________
01297 void TXMLEngine::UnpackSpecialCharacters(char* target, const char* source, int srclen)
01298 {
01299    // unpack special symbols, used in xml syntax to code characters
01300    // these symbols: '<' - &lt, '>' - &gt, '&' - &amp, '"' - &quot
01301 
01302    while (srclen>0) {
01303       if (*source=='&') {
01304          if ((*(source+1)=='l') && (*(source+2)=='t') && (*(source+3)==';')) {
01305             *target++ = '<'; source+=4; srclen-=4;
01306          } else
01307          if ((*(source+1)=='g') && (*(source+2)=='t') && (*(source+3)==';')) {
01308             *target++ = '>'; source+=4; srclen-=4;
01309          } else
01310          if ((*(source+1)=='a') && (*(source+2)=='m') && (*(source+3)=='p') && (*(source+4)==';')) {
01311             *target++ = '&'; source+=5; srclen-=5;
01312          } else
01313          if ((*(source+1)=='q') && (*(source+2)=='u') && (*(source+3)=='o') && (*(source+4)=='t') && (*(source+5)==';')) {
01314             *target++ = '\"'; source+=6; srclen-=6;
01315          } else {
01316             *target++ = *source++; srclen--;
01317          }
01318       } else {
01319          *target++ = *source++;
01320          srclen--;
01321       }
01322    }
01323    *target = 0;
01324 }
01325 
01326 //______________________________________________________________________________
01327 void TXMLEngine::OutputValue(char* value, TXMLOutputStream* out)
01328 {
01329    // output value to output stream
01330    // if symbols '<' '&' '>' '"' appears in the string, they
01331    // will be encoded to appropriate xml symbols: &lt, &amp, &gt, &quot
01332 
01333    if (value==0) return;
01334 
01335    char* last = value;
01336    char* find = 0;
01337    while ((find=strpbrk(last,"<&>\"")) !=0 ) {
01338       char symb = *find;
01339       *find = 0;
01340       out->Write(last);
01341       *find = symb;
01342       last = find+1;
01343       if (symb=='<')      out->Write("&lt;"); 
01344       else if (symb=='>') out->Write("&gt;"); 
01345       else if (symb=='&') out->Write("&amp;"); 
01346       else                out->Write("&quot;");
01347    }
01348    if (*last!=0)
01349       out->Write(last);
01350 }
01351 
01352 //______________________________________________________________________________
01353 void TXMLEngine::SaveNode(XMLNodePointer_t xmlnode, TXMLOutputStream* out, Int_t layout, Int_t level)
01354 {
01355    // stream data of xmlnode to output
01356 
01357    if (xmlnode==0) return;
01358    SXmlNode_t* node = (SXmlNode_t*) xmlnode;
01359 
01360    // this is output for content
01361    if (*SXmlNode_t::Name(node) == 0 ) {
01362       out->Write(SXmlNode_t::Name(node)+1);
01363       return;
01364    }
01365    
01366    Bool_t issingleline = (node->fChild==0);
01367 
01368    if (layout>0) out->Put(' ', level);
01369 
01370    if (node->fType==kXML_COMMENT) {
01371       out->Write("<!--");
01372       out->Write(SXmlNode_t::Name(node));
01373       out->Write("-->");
01374       if (layout>0) out->Put('\n');
01375       return;
01376    } else
01377    if (node->fType==kXML_RAWLINE) {
01378       out->Write(SXmlNode_t::Name(node));
01379       if (layout>0) out->Put('\n');
01380       return; 
01381    }
01382 
01383    out->Put('<');
01384    if (node->fType==kXML_PI_NODE) out->Put('?');
01385    
01386    // we suppose that ns is always first attribute
01387    if ((node->fNs!=0) && (node->fNs!=node->fAttr)) {
01388       out->Write(SXmlAttr_t::Name(node->fNs)+6);
01389       out->Put(':');
01390    }
01391    out->Write(SXmlNode_t::Name(node));
01392 
01393    SXmlAttr_t* attr = node->fAttr;
01394    while (attr!=0) {
01395       out->Put(' ');
01396       char* attrname = SXmlAttr_t::Name(attr);
01397       out->Write(attrname);
01398       out->Write("=\"");
01399       attrname += strlen(attrname) + 1;
01400       OutputValue(attrname, out);
01401       out->Put('\"');
01402       attr = attr->fNext;
01403    }
01404 
01405    // if single line, close node with "/>" and return
01406    if (issingleline) {
01407       if (node->fType==kXML_PI_NODE) out->Write("?>");
01408                               else out->Write("/>");
01409       if (layout>0) out->Put('\n');
01410       return;
01411    }
01412    
01413    out->Put('>');
01414    
01415    // go to next line only if no content inside
01416    const char* content = GetNodeContent(xmlnode);
01417    if ((content==0) && (layout>0)) 
01418       out->Put('\n');
01419 
01420    if (content!=0) out->Write(content);
01421       
01422    SXmlNode_t* child = (SXmlNode_t*) GetChild(xmlnode);
01423    while (child!=0) {
01424       if (content!=0) {
01425          content = 0;
01426          if (layout>0) out->Put('\n');
01427       }
01428       SaveNode((XMLNodePointer_t) child, out, layout, level+2);
01429       child = child->fNext;
01430    }
01431 
01432    // add starting spaces 
01433    if ((content==0) && (layout>0)) out->Put(' ',level);
01434    
01435    out->Write("</");
01436    // we suppose that ns is always first attribute
01437    if ((node->fNs!=0) && (node->fNs!=node->fAttr)) {
01438       out->Write(SXmlAttr_t::Name(node->fNs)+6);
01439       out->Put(':');
01440    }
01441    out->Write(SXmlNode_t::Name(node));
01442    out->Put('>');
01443    if (layout>0) out->Put('\n');
01444 }
01445 
01446 //______________________________________________________________________________
01447 XMLNodePointer_t TXMLEngine::ReadNode(XMLNodePointer_t xmlparent, TXMLInputStream* inp, Int_t& resvalue)
01448 {
01449    // Tries to construct xml node from input stream. Node should be
01450    // child of xmlparent node or it can be closing tag of xmlparent.
01451    // resvalue <= 0 if error
01452    // resvalue == 1 if this is endnode of parent
01453    // resvalue == 2 if this is child
01454 
01455    resvalue = 0;
01456 
01457    if (inp==0) return 0;
01458    if (!inp->SkipSpaces()) { resvalue = -1; return 0; }
01459    SXmlNode_t* parent = (SXmlNode_t*) xmlparent;
01460 
01461    SXmlNode_t* node = 0;
01462 
01463    // process comments before we start to analyse any node symbols   
01464    while (inp->CheckFor("<!--")) {
01465       Int_t commentlen = inp->SearchFor("-->");
01466       if (commentlen<=0) { resvalue = -10; return 0; }
01467 
01468       if (!fSkipComments) {
01469          node = (SXmlNode_t*) AllocateNode(commentlen, xmlparent);
01470          char* nameptr = SXmlNode_t::Name(node);
01471          node->fType = kXML_COMMENT;
01472          strncpy(nameptr, inp->fCurrent, commentlen); // here copy only content, there is no padding 0 at the end
01473          nameptr+=commentlen;
01474          *nameptr = 0; // here we add padding 0 to get normal string
01475       }
01476 
01477       if (!inp->ShiftCurrent(commentlen+3)) { resvalue = -1; return node; }
01478       if (!inp->SkipSpaces()) { resvalue = -1; return node; }
01479 
01480       resvalue = 2;
01481       return node;
01482    }
01483 
01484    if (*inp->fCurrent!='<') {
01485       // here should be reading of element content
01486       // only one entry for content is supported, only before any other childs
01487       if ((parent==0) || (parent->fChild!=0)) { resvalue = -2; return 0; }
01488       int contlen = inp->LocateContent();
01489       if (contlen<0) return 0;
01490 
01491       SXmlNode_t* contnode = (SXmlNode_t*) AllocateNode(contlen+1, xmlparent);
01492       char* contptr = SXmlNode_t::Name(contnode);
01493       *contptr = 0;
01494       contptr++;
01495       UnpackSpecialCharacters(contptr, inp->fCurrent, contlen);
01496       if (!inp->ShiftCurrent(contlen)) return 0;
01497       resvalue = 2;
01498       return contnode;
01499    } else
01500       // skip "<" symbol
01501       if (!inp->ShiftCurrent()) return 0;
01502 
01503    if (*inp->fCurrent=='/') {
01504       // this is a starting of closing node
01505       if (!inp->ShiftCurrent()) return 0;
01506       if (!inp->SkipSpaces()) return 0;
01507       Int_t len = inp->LocateIdentifier();
01508       if (len<=0) { resvalue = -3; return 0; }
01509 
01510       if (parent==0) { resvalue = -4; return 0; }
01511 
01512       if (strncmp(SXmlNode_t::Name(parent), inp->fCurrent, len)!=0) {
01513          resvalue = -5;
01514          return 0;
01515       }
01516 
01517       if (!inp->ShiftCurrent(len)) return 0;
01518 
01519       if (!inp->SkipSpaces())   return 0;
01520       if (*inp->fCurrent!='>')  return 0;
01521       if (!inp->ShiftCurrent()) return 0;
01522 
01523       if (parent->fNs!=0)
01524          TruncateNsExtension((XMLNodePointer_t)parent);
01525 
01526       inp->SkipSpaces(kTRUE); // locate start of next string
01527       resvalue = 1;
01528       return 0;
01529    }
01530    
01531    EXmlNodeType nodetype = kXML_NODE;
01532    bool canhaschilds = true;
01533    char endsymbol = '/';
01534    
01535    // this is case of processing instructions node
01536    if (*inp->fCurrent=='?') {
01537       if (!inp->ShiftCurrent()) return 0;
01538       nodetype = kXML_PI_NODE;
01539       canhaschilds = false;
01540       endsymbol = '?';
01541    }
01542 
01543    if (!inp->SkipSpaces()) return 0;
01544    Int_t len = inp->LocateIdentifier();
01545    if (len<=0) return 0;
01546    node = (SXmlNode_t*) AllocateNode(len, xmlparent);
01547    char* nameptr = SXmlNode_t::Name(node);
01548    node->fType = nodetype;
01549 
01550    strncpy(nameptr, inp->fCurrent, len); // here copied content without padding 0
01551    nameptr+=len;
01552    *nameptr = 0; // add 0 to the end
01553    
01554    char* colon = strchr(SXmlNode_t::Name(node),':');
01555    if ((colon!=0) && (parent!=0)) {
01556       *colon = 0;
01557       node->fNs = (SXmlAttr_t*) FindNs(xmlparent, SXmlNode_t::Name(node));
01558       *colon =':';
01559    }
01560 
01561    if (!inp->ShiftCurrent(len)) return 0;
01562 
01563    do {
01564       if (!inp->SkipSpaces()) return 0;
01565 
01566       char nextsymb = *inp->fCurrent;
01567 
01568       if (nextsymb==endsymbol) {  // this is end of short node like <node ... />
01569          if (!inp->ShiftCurrent()) return 0;
01570          if (*inp->fCurrent=='>') {
01571             if (!inp->ShiftCurrent()) return 0;
01572 
01573             if (node->fNs!=0)
01574                TruncateNsExtension((XMLNodePointer_t) node);
01575 
01576             inp->SkipSpaces(kTRUE); // locate start of next string
01577             resvalue = 2;
01578             return node;
01579          } else return 0;
01580       } else
01581       if (nextsymb=='>') { // this is end of parent node, lets find all childs
01582          if (!canhaschilds) { resvalue = -11; return 0; }
01583 
01584          if (!inp->ShiftCurrent()) return 0;
01585 
01586          do {
01587             ReadNode(node, inp, resvalue);
01588          } while (resvalue==2);
01589 
01590          if (resvalue==1) {
01591             resvalue = 2;
01592             return node;
01593          } else return 0;
01594       } else {
01595          Int_t attrlen = inp->LocateIdentifier();
01596          if (attrlen<=0) { resvalue = -6; return 0; }
01597 
01598          char* valuestart = inp->fCurrent+attrlen;
01599 
01600          int valuelen = inp->LocateAttributeValue(valuestart);
01601          if (valuelen<3) { resvalue = -7; return 0; }
01602 
01603          SXmlAttr_t* attr = (SXmlAttr_t*) AllocateAttr(attrlen, valuelen-3, (XMLNodePointer_t) node);
01604 
01605          char* attrname = SXmlAttr_t::Name(attr);
01606          strncpy(attrname, inp->fCurrent, attrlen);
01607          attrname+=attrlen;
01608          *attrname = 0;
01609          attrname++;
01610          UnpackSpecialCharacters(attrname, valuestart+2, valuelen-3);
01611 
01612          if (!inp->ShiftCurrent(attrlen+valuelen)) return 0;
01613 
01614          attrname = SXmlAttr_t::Name(attr);
01615 
01616          if ((strlen(attrname)>6) && (strstr(attrname,"xmlns:")==attrname)) {
01617             if (strcmp(SXmlNode_t::Name(node), attrname + 6)!=0) {
01618                resvalue = -8;
01619                //return 0;
01620             }
01621             if (node->fNs!=0) {
01622                resvalue = -9;
01623                //return 0;
01624             }
01625             node->fNs = attr;
01626          }
01627       }
01628    } while (true);
01629 
01630    return 0;
01631 }
01632 
01633 //______________________________________________________________________________
01634 void TXMLEngine::DisplayError(Int_t error, Int_t linenumber)
01635 {
01636    // Dsiplays error, occured during parsing of xml file
01637    switch(error) {
01638       case -11: Error("ParseFile", "Node cannot be closed with > symbol at line %d, for instance <?xml ... ?> node", linenumber); break;
01639       case -10: Error("ParseFile", "Error in xml comments definition at line %d, must be <!-- comments -->", linenumber); break;
01640       case -9: Error("ParseFile", "Multiple name space definitions not allowed, line %d", linenumber); break;
01641       case -8: Error("ParseFile", "Invalid namespace specification, line %d", linenumber); break;
01642       case -7: Error("ParseFile", "Invalid attribute value, line %d", linenumber); break;
01643       case -6: Error("ParseFile", "Invalid identifier for node attribute, line %d", linenumber); break;
01644       case -5: Error("ParseFile", "Missmatch between open and close nodes, line %d", linenumber); break;
01645       case -4: Error("ParseFile", "Unexpected close node, line %d", linenumber); break;
01646       case -3: Error("ParseFile", "Valid identifier for close node is missing, line %d", linenumber); break;
01647       case -2: Error("ParseFile", "No multiple content entries allowed, line %d", linenumber); break;
01648       case -1: Error("ParseFile", "Unexpected end of xml file"); break;
01649       default: Error("ParseFile", "XML syntax error at line %d", linenumber); break;
01650    }
01651    
01652 }
01653 

Generated on Tue Jul 5 14:30:39 2011 for ROOT_528-00b_version by  doxygen 1.5.1