Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-03-14 08:15:00

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 
0014 // Framework include files
0015 #include <XML/Printout.h>
0016 #include <XML/UriReader.h>
0017 #include <XML/DocumentHandler.h>
0018 
0019 // C/C++ include files
0020 #include <memory>
0021 #include <iostream>
0022 #include <stdexcept>
0023 #include <sys/types.h>
0024 #include <sys/stat.h>
0025 #ifndef _WIN32
0026 #include <libgen.h>
0027 #endif
0028 #include <TSystem.h>
0029 
0030 using namespace dd4hep::xml;
0031 
0032 namespace {
0033   std::string undressed_file_name(const std::string& fn)   {
0034     if ( !fn.empty() )   {
0035       TString tfn(fn);
0036       gSystem->ExpandPathName(tfn);
0037       return std::string(tfn.Data());
0038     }
0039     return fn;
0040   }
0041   int s_minPrintLevel = dd4hep::INFO;
0042 
0043   std::string _clean_fname(const std::string& filepath) {
0044     // This function seems to resolve environment variables inside the filepath string and return resolved string
0045     std::string const& temp = getEnviron(filepath);
0046     std::string temp2 = undressed_file_name( temp.empty() ? filepath : temp );
0047     if ( strncmp(temp2.c_str(),"file:",5)==0 ) return temp2.substr(5);
0048     return temp2;
0049   }
0050 
0051 }
0052 
0053 #ifndef __TIXML__
0054 #include <xercesc/framework/LocalFileFormatTarget.hpp>
0055 #include <xercesc/framework/StdOutFormatTarget.hpp>
0056 #include <xercesc/framework/MemBufFormatTarget.hpp>
0057 #include <xercesc/framework/MemBufInputSource.hpp>
0058 #include <xercesc/sax/SAXParseException.hpp>
0059 #include <xercesc/sax/EntityResolver.hpp>
0060 #include <xercesc/sax/InputSource.hpp>
0061 #include <xercesc/parsers/XercesDOMParser.hpp>
0062 #include <xercesc/util/XMLEntityResolver.hpp>
0063 #include <xercesc/util/PlatformUtils.hpp>
0064 #include <xercesc/util/XercesDefs.hpp>
0065 #include <xercesc/util/XMLUni.hpp>
0066 #include <xercesc/util/XMLURL.hpp>
0067 #include <xercesc/util/XMLString.hpp>
0068 #include <xercesc/dom/DOM.hpp>
0069 #include <xercesc/sax/ErrorHandler.hpp>
0070 
0071 using namespace xercesc;
0072 
0073 /// Namespace for the AIDA detector description toolkit
0074 namespace dd4hep {
0075 
0076   /// Namespace containing utilities to parse XML files using XercesC or TinyXML
0077   namespace xml {
0078 
0079     /// XML-DOM ERror handler class for the XercesC document parser.
0080     class DocumentErrorHandler: public ErrorHandler, public DOMErrorHandler {
0081     public:
0082       /// Constructor
0083       DocumentErrorHandler() {
0084       }
0085       /// Destructor
0086       virtual ~DocumentErrorHandler()  {
0087         printout(DEBUG,"DocumentErrorHandler","+++ Destructing the XercesC DOM-XML document error handler....");
0088       }
0089       /// Reset errors (Noop)
0090       void resetErrors() {
0091       }
0092       /// Warnings callback. Ignore them
0093       void warning(const SAXParseException& /* e */) {
0094       }
0095       /// Error handler
0096       void error(const SAXParseException& e);
0097       /// Fatal error handler
0098       void fatalError(const SAXParseException& e);
0099       /// Dom Error handler callback
0100       virtual bool handleError(const DOMError& domError);
0101     };
0102 
0103     /// Dom Error handler callback
0104     bool DocumentErrorHandler::handleError(const DOMError& domError) {
0105       std::string err = "DOM UNKNOWN: ";
0106       switch (domError.getSeverity()) {
0107       case DOMError::DOM_SEVERITY_WARNING:
0108         err = "DOM WARNING: ";
0109         break;
0110       case DOMError::DOM_SEVERITY_ERROR:
0111         err = "DOM ERROR:   ";
0112         break;
0113       case DOMError::DOM_SEVERITY_FATAL_ERROR:
0114         err = "DOM FATAL:   ";
0115         break;
0116       default:
0117         return false;
0118       }
0119       printout(FATAL,"DocumentErrorHandler", "+++ %s %s: %s", err.c_str(),
0120                _toString(domError.getType()).c_str(),_toString(domError.getMessage()).c_str());
0121       DOMLocator* loc = domError.getLocation();
0122       if (loc) {
0123         printout(FATAL,"DocumentErrorHandler","+++ Location: Line:%d Column: %d",
0124                  int(loc->getLineNumber()),int(loc->getColumnNumber()));
0125       }
0126       return false;
0127     }
0128     /// Error handler
0129     void DocumentErrorHandler::error(const SAXParseException& e) {
0130       std::string m(_toString(e.getMessage()));
0131       if (m.find("The values for attribute 'name' must be names or name tokens") != std::string::npos
0132           || m.find("The values for attribute 'ID' must be names or name tokens") != std::string::npos
0133           || m.find("for attribute 'name' must be Name or Nmtoken") != std::string::npos
0134           || m.find("for attribute 'ID' must be Name or Nmtoken") != std::string::npos
0135           || m.find("for attribute 'name' is invalid Name or NMTOKEN value") != std::string::npos
0136           || m.find("for attribute 'ID' is invalid Name or NMTOKEN value") != std::string::npos)
0137         return;
0138       std::string sys(_toString(e.getSystemId()));
0139       printout(ERROR,"XercesC","+++ Error at file \"%s\", Line %d Column: %d Message:%s",
0140                sys.c_str(), int(e.getLineNumber()), int(e.getColumnNumber()), m.c_str());
0141     }
0142     /// Fatal error handler
0143     void DocumentErrorHandler::fatalError(const SAXParseException& e) {
0144       std::string m(_toString(e.getMessage()));
0145       std::string sys(_toString(e.getSystemId()));
0146       printout(FATAL,"XercesC","+++ FATAL Error at file \"%s\", Line %d Column: %d Message:%s",
0147                sys.c_str(), int(e.getLineNumber()), int(e.getColumnNumber()), m.c_str());
0148     }
0149 
0150     namespace {
0151 
0152       /// Specialized DOM parser to handle special system IDs
0153       class dd4hepDOMParser : public XercesDOMParser      {
0154         /// Pointer to URI reader
0155         UriReader*           m_reader;
0156         /// Xerces Error handler
0157         DocumentErrorHandler m_errHandle_tr;
0158         class Resolver : public XMLEntityResolver {
0159           dd4hepDOMParser* parser;
0160         public:
0161           Resolver(dd4hepDOMParser* p) : parser(p) {}
0162           virtual ~Resolver() {}
0163           virtual InputSource *resolveEntity(XMLResourceIdentifier *id)
0164           {   return parser->read_uri(id);                            }
0165         };
0166         Resolver m_resolver;
0167       public:
0168         /// Initializing constructor
0169         dd4hepDOMParser(UriReader* rdr) : XercesDOMParser(), m_reader(rdr), m_resolver(this)  {
0170           //printout(FATAL,"XercesC","+++ Creating new parser");
0171           setErrorHandler(&m_errHandle_tr);
0172           setXMLEntityResolver(&m_resolver);
0173         }
0174         /// Default destructor
0175         virtual ~dd4hepDOMParser() {
0176           //printout(FATAL,"XercesC","+++ Deleting new parser");
0177         }
0178         /// Entity resolver overload to use uri reader
0179         InputSource *read_uri(XMLResourceIdentifier *id)   {
0180           if ( m_reader )   {
0181             std::string buf, systemID(_toString(id->getSystemId()));
0182             if ( m_reader->load(systemID, buf) )  {
0183               const XMLByte* input = (const XMLByte*)XMLString::replicate(buf.c_str());
0184 #if 0
0185               std::string baseURI(_toString(id->getBaseURI()));
0186               std::string schema(_toString(id->getSchemaLocation()));
0187               std::string ns(_toString(id->getNameSpace()));
0188               if ( s_minPrintLevel <= INFO ) {
0189                 printout(INFO,"XercesC","+++ Resolved URI: sysID:%s uri:%s ns:%s schema:%s",
0190                          systemID.c_str(), baseURI.c_str(), ns.c_str(), schema.c_str());
0191               }
0192 #endif
0193               return new MemBufInputSource(input,buf.length(),systemID.c_str(),true);
0194             }
0195           }
0196           return 0;
0197         }
0198       };
0199 
0200       /// Helper function to create a XercesC pareser
0201       XercesDOMParser* make_parser(UriReader* reader=0) {
0202         XercesDOMParser* parser = new dd4hepDOMParser(reader);
0203         parser->setValidationScheme(XercesDOMParser::Val_Auto);
0204         parser->setValidationSchemaFullChecking(true);
0205         parser->setCreateEntityReferenceNodes(false);
0206         parser->setDoNamespaces(false);
0207         parser->setDoSchema(true);
0208 
0209         ////parser->setDoNamespaces( true );
0210         //domParser->setDoSchema( true );
0211         ////parser->setHandleMultipleImports ( true );
0212         //domParser->setValidationSchemaFullChecking( true );
0213         return parser;
0214       }
0215     }
0216 
0217     /// Dump DOM tree using XercesC handles
0218     void dumpTree(DOMNode* doc, std::ostream& os) {
0219       if ( doc )  {
0220         DOMImplementation  *imp = DOMImplementationRegistry::getDOMImplementation(Strng_t("LS"));
0221         MemBufFormatTarget *tar = new MemBufFormatTarget();
0222         DOMLSOutput        *out = imp->createLSOutput();
0223         DOMLSSerializer    *wrt = imp->createLSSerializer();
0224         out->setByteStream(tar);
0225         wrt->getDomConfig()->setParameter(Strng_t("format-pretty-print"), true);
0226         wrt->write(doc, out);
0227         os << tar->getRawBuffer() << std::endl << std::flush;
0228         out->release();
0229         wrt->release();
0230         return;
0231       }
0232       printout(ERROR,"dumpTree","+++ Cannot dump invalid document.");
0233     }
0234 
0235     /// Dump DOM tree using XercesC handles
0236     void dump_doc(DOMDocument* doc, std::ostream& os) {
0237       dumpTree(doc,os);
0238     }
0239     /// Dump DOM tree using XercesC handles
0240     void dump_tree(Handle_t elt, std::ostream& os) {
0241       dumpTree((DOMNode*)elt.ptr(),os);
0242     }
0243     /// Dump DOM tree using XercesC handles
0244     void dump_tree(Document doc, std::ostream& os) {
0245       dump_doc((DOMDocument*)doc.ptr(),os);
0246     }
0247   }
0248 }
0249 
0250 #ifdef DD4HEP_NONE
0251 /// System ID of a given XML entity
0252 std::string DocumentHandler::system_path(Handle_t base, const std::string& fn)   {
0253   std::string path = system_path(base);
0254   std::string dir  = ::dirname((char*)path.c_str());
0255   return dir+fn;
0256 }
0257 #else
0258 
0259 #include <TUri.h>
0260 #include <TUrl.h>
0261 #endif
0262 
0263 /// System ID of a given XML entity
0264 std::string DocumentHandler::system_path(Handle_t base, const std::string& fn)   {
0265   std::string path, dir = system_path(base);
0266   TUri uri_base(dir.c_str()), uri_rel(fn.c_str());
0267   TUrl url_base(dir.c_str());
0268   path = TUri::MergePaths(uri_rel,uri_base);
0269   TUri final(path.c_str());
0270   final.Normalise();
0271   path = url_base.GetProtocol()+std::string("://")+final.GetUri().Data();
0272   if ( path[path.length()-1]=='/' ) path = path.substr(0,path.length()-1);
0273   return path;
0274 }
0275 
0276 /// System ID of a given XML entity
0277 std::string DocumentHandler::system_path(Handle_t base)   {
0278   DOMElement* elt = (DOMElement*)base.ptr();
0279   std::string path = _toString(elt->getBaseURI());
0280   if ( path[0] == '/' )  {
0281     std::string tmp = "file:"+path;
0282     return tmp;
0283   }
0284   return path;
0285 }
0286 
0287 /// Load secondary XML file with relative addressing with respect to handle
0288 Document DocumentHandler::load(Handle_t base, const XMLCh* fname, UriReader* reader) const {
0289   std::string path;
0290   DOMElement* elt = (DOMElement*)base.ptr();
0291   try  {
0292     Document doc;
0293     Strng_t p = _toString(fname);    
0294     path      = _toString(fname);
0295     /// This is a bit complicated, but if the primary source is in-memory
0296     try  {
0297       XMLURL  ref_url(elt->getBaseURI(), p);
0298       path = _toString(ref_url.getURLText());
0299     }
0300     catch(...)   {
0301     }
0302     return load(path, reader);
0303   }
0304   catch(const std::exception& exc)   {
0305     std::string b = _toString(elt->getBaseURI());
0306     std::string e = _toString(fname);
0307     printout(DEBUG,"DocumentHandler","+++ URI exception: %s -> %s [%s]",b.c_str(),e.c_str(),exc.what());
0308   }
0309   catch(...)   {
0310     std::string b = _toString(elt->getBaseURI());
0311     std::string e = _toString(fname);
0312     printout(DEBUG,"DocumentHandler","+++ URI exception: %s -> %s",b.c_str(),e.c_str());
0313   }
0314   if ( reader )   {
0315     std::string buf, sys = system_path(base,fname);
0316 #if 0
0317     std::string buf, sys, dir = _toString(elt->getBaseURI());
0318     std::string fn = _toString(fname);
0319     dir = ::dirname((char*)dir.c_str());
0320     while( fn.substr(0,3) == "../" )  {
0321       dir = ::dirname((char*)dir.c_str());
0322       fn = fn.substr(3);
0323     }
0324     sys = dir + "/" + fn;
0325 #endif
0326     if ( reader->load(sys, buf) )  {
0327 #if 0
0328       Document doc = parse(buf.c_str(), buf.length(), sys.c_str(), reader);
0329       dumpTree(doc);
0330       return doc;
0331 #endif
0332       return parse(buf.c_str(), buf.length(), sys.c_str(), reader);
0333     }
0334   }
0335   return Document(0);
0336 }
0337 
0338 /// Load XML file and parse it using URI resolver to read data.
0339 Document DocumentHandler::load(const std::string& fname, UriReader* reader) const   {
0340   auto fname_clean = _clean_fname(fname);
0341   std::string path;
0342   printout(DEBUG,"DocumentHandler","+++ Loading document URI: %s",fname_clean.c_str());
0343   try  {
0344     size_t idx = fname_clean.find(':');
0345     size_t idq = fname_clean.find('/');
0346     if ( idq == std::string::npos ) idq = 0;
0347     XMLURL xerurl = (const XMLCh*) Strng_t(idx==std::string::npos || idx>idq ? "file:"+fname_clean : fname_clean);
0348     std::string proto  = _toString(xerurl.getProtocolName());
0349     path = _toString(xerurl.getPath());
0350     printout(DEBUG,"DocumentHandler","+++             protocol:%s path:%s",proto.c_str(), path.c_str());
0351   }
0352   catch(...)   {
0353   }
0354   std::unique_ptr < XercesDOMParser > parser(make_parser(reader));
0355   try {
0356     if ( !path.empty() )  {
0357       parser->parse(path.c_str());
0358       if ( reader ) reader->parserLoaded(path);
0359     }
0360     else   {
0361       if ( reader && reader->load(fname_clean, path) )  {
0362         MemBufInputSource src((const XMLByte*)path.c_str(), path.length(), fname.c_str(), false);
0363         parser->parse(src);
0364         return (XmlDocument*)parser->adoptDocument();
0365       }
0366       return (XmlDocument*)0;
0367     }
0368   }
0369   catch (const std::exception& e) {
0370     printout(ERROR,"DocumentHandler","+++ Exception(XercesC): parse(path):%s",e.what());
0371     try {
0372       parser->parse(fname.c_str());
0373       if ( reader ) reader->parserLoaded(path);
0374     }
0375     catch (const std::exception& ex) {
0376       printout(FATAL,"DocumentHandler","+++ Exception(XercesC): parse(URI):%s",ex.what());
0377       throw;
0378     }
0379   }
0380   printout(DEBUG,"DocumentHandler","+++ Document %s succesfully parsed with XercesC .....",path.c_str());
0381   return (XmlDocument*)parser->adoptDocument();
0382 }
0383 
0384 /// Parse a standalong XML string into a document.
0385 Document DocumentHandler::parse(const char* bytes, size_t length, const char* sys_id, UriReader* rdr) const {
0386   std::unique_ptr < XercesDOMParser > parser(make_parser(rdr));
0387   MemBufInputSource src((const XMLByte*)bytes, length, sys_id, false);
0388   parser->parse(src);
0389   DOMDocument* doc = parser->adoptDocument();
0390   doc->setXmlStandalone(true);
0391   doc->setStrictErrorChecking(true);
0392   return (XmlDocument*) doc;
0393 }
0394 
0395 /// Write xml document to output file (stdout if file name empty)
0396 int DocumentHandler::output(Document doc, const std::string& fname) const {
0397   XMLFormatTarget *tar = 0;
0398   DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(Strng_t("LS"));
0399   DOMLSOutput *out = imp->createLSOutput();
0400   DOMLSSerializer *wrt = imp->createLSSerializer();
0401 
0402   if (fname.empty())
0403     tar = new StdOutFormatTarget();
0404   else   {
0405     std::string fn = undressed_file_name(fname);
0406     tar = new LocalFileFormatTarget(Strng_t(fn));
0407   }
0408   out->setByteStream(tar);
0409   wrt->getDomConfig()->setParameter(Strng_t("format-pretty-print"), true);
0410   wrt->write((xercesc::DOMDocument*) doc.ptr(), out);
0411   out->release();
0412   wrt->release();
0413   delete tar;
0414   return 1;
0415 }
0416 
0417 #else
0418 
0419 #include <XML/tinyxml.h>
0420 
0421 /// Namespace for the AIDA detector description toolkit
0422 namespace dd4hep {
0423   /// Namespace containing utilities to parse XML files using XercesC or TinyXML
0424   namespace xml {
0425 
0426     /// XML-DOM ERror handler class for the TinyXML document parser (Compatibility class)
0427     class DocumentErrorHandler {};
0428 
0429     union Xml {
0430       Xml(void* ptr) : p(ptr) {}
0431       Xml(const void* ptr) : cp(ptr) {}
0432       void* p;
0433       const void* cp;
0434       TiXmlElement* e;
0435       XmlElement* xe;
0436       TiXmlAttribute* a;
0437       Attribute attr;
0438       TiXmlNode* n;
0439       TiXmlDocument* d;
0440       XmlDocument* xd;
0441     };
0442   }}
0443 
0444 /// System ID of a given XML entity
0445 std::string DocumentHandler::system_path(Handle_t base, const std::string& fname)   {
0446   std::string fn, clean = _clean_fname(fname);
0447   struct stat st;
0448   Element elt(base);
0449   // Poor man's URI handling. Xerces is much much better here
0450   if ( elt ) {
0451     std::string bn = Xml(elt.document()).d->Value();
0452 #ifdef _WIN32
0453     char drive[_MAX_DRIVE], dir[_MAX_DIR], file[_MAX_FNAME], ext[_MAX_EXT];
0454     ::_splitpath(bn.c_str(),drive,dir,file,ext);
0455     fn = drive;
0456     fn += ":";
0457     fn += dir;
0458     fn += "/";
0459     fn += clean;
0460 #else
0461     fn = ::dirname((char*)bn.c_str());
0462 #endif
0463     fn += "/";
0464     fn += _clean_fname(fname);
0465   }
0466   if ( ::stat(fn.c_str(),&st)==0 )
0467     return fn;
0468   else if ( ::stat(clean.c_str(),&st)==0 )
0469     return clean;
0470   return fname;
0471 }
0472 
0473 /// System ID of a given XML entity
0474 std::string DocumentHandler::system_path(Handle_t base)   {
0475   std::string fn;
0476   Element elt(base);
0477   // Poor man's URI handling. Xerces is much much better here
0478   if ( elt ) {
0479     fn = Xml(elt.document()).d->Value();
0480   }
0481   return undressed_file_name(fn);
0482 }
0483 
0484 /// Load XML file and parse it using URI resolver to read data.
0485 Document DocumentHandler::load(const std::string& fname, UriReader* reader) const  {
0486   std::string clean = _clean_fname(fname);
0487   if ( reader )   {
0488     printout(WARNING,"DocumentHandler","+++ Loading document URI: %s %s",
0489              fname.c_str(),"[URI Resolution is not supported by TiXML]");
0490   }
0491   else if ( s_minPrintLevel <= INFO ) {
0492     printout(INFO,"DocumentHandler","+++ Loading document URI: %s [Resolved:'%s']",
0493              fname.c_str(),clean.c_str());
0494   }
0495   TiXmlDocument* doc = new TiXmlDocument(clean.c_str());
0496   bool result = false;
0497   try {
0498     result = doc->LoadFile();
0499     if ( !result ) {
0500       if ( doc->Error() ) {
0501         printout(FATAL,"DocumentHandler","+++ Error (TinyXML) parsing XML document:%s [%s]",
0502                  fname.c_str(), clean.c_str());
0503         printout(FATAL,"DocumentHandler","+++ Error (TinyXML) XML parsing error:%s",
0504                  doc->ErrorDesc());
0505         printout(FATAL,"DocumentHandler","+++ Document:%s Location Line:%d Column:%d",
0506                  doc->Value(), doc->ErrorRow(), doc->ErrorCol());
0507         except("dd4hep:XML","++ file:%s error:%s",clean.c_str(),doc->ErrorDesc());
0508       }
0509       except("dd4hep:XML","++ Unknown error (TinyXML) while parsing:%s",fname.c_str());
0510     }
0511   }
0512   catch(std::exception& e) {
0513     printout(ERROR,"DocumentHandler","+++ Exception (TinyXML): parse(path):%s",e.what());
0514   }
0515   if ( result ) {
0516     if ( s_minPrintLevel <= INFO ) {
0517       printout(INFO,"DocumentHandler","+++ Document %s succesfully parsed with TinyXML .....",
0518                fname.c_str());
0519     }
0520     return (XmlDocument*)doc;
0521   }
0522   delete doc;
0523   return 0;
0524 }
0525 
0526 /// Load XML file and parse it using URI resolver to read data.
0527 Document DocumentHandler::load(Handle_t base, const XmlChar* fname, UriReader* reader) const  {
0528   std::string path = system_path(base, fname);
0529   return load(path,reader);
0530 }
0531 
0532 /// Parse a standalong XML string into a document.
0533 Document DocumentHandler::parse(const char* bytes, size_t length, const char* /* sys_id */, UriReader* reader) const {
0534   if ( reader )   {
0535     printout(WARNING,"DocumentHandler","+++ Parsing memory document %s",
0536              "[URI Resolution is not supported by TiXML]");
0537   }
0538   TiXmlDocument* doc = new TiXmlDocument();
0539   try  {
0540     if ( bytes )   {
0541       size_t str_len = ::strlen(bytes);
0542       size_t len = length;
0543       // TiXml does not support white spaces at the end. Check and remove.
0544       if ( str_len+1 != len || bytes[str_len] != 0 || ::isspace(bytes[str_len-1]) )   {
0545         std::unique_ptr<char[]> data(new char[len+1]);
0546         char* buff = data.get();
0547         try  {
0548           ::memcpy(buff, bytes, len+1);
0549           buff[len] = 0;
0550           for(size_t i=len-1; i>0 && (buff[i]==0 || ::isspace(buff[i])); --i)
0551             buff[i] = 0;
0552           if ( 0 == doc->Parse(buff) ) {
0553             return (XmlDocument*)doc;
0554           }
0555         }
0556         catch(...)   {
0557         }
0558       }
0559       if ( 0 == doc->Parse(bytes) ) {
0560         return (XmlDocument*)doc;
0561       }
0562       if ( doc->Error() ) {
0563         printout(FATAL,"DocumentHandler",
0564                  "+++ Error (TinyXML) while parsing XML string [%s]",
0565                  doc->ErrorDesc());
0566         printout(FATAL,"DocumentHandler",
0567                  "+++ XML Document error: %s Location Line:%d Column:%d",
0568                  doc->Value(), doc->ErrorRow(), doc->ErrorCol());
0569         throw std::runtime_error(std::string("dd4hep: ")+doc->ErrorDesc());
0570       }
0571       throw std::runtime_error("dd4hep: Unknown error while parsing XML document string with TiXml.");
0572     }
0573     throw std::runtime_error("dd4hep: FAILED to parse invalid document string [NULL] with TiXml.");
0574   }
0575   catch(std::exception& e) {
0576     printout(ERROR,"DocumentHandler","+++ Exception (TinyXML): parse(string):%s",e.what());
0577   }
0578   delete doc;
0579   return 0;
0580 }
0581 
0582 /// Write xml document to output file (stdout if file name empty)
0583 int DocumentHandler::output(Document doc, const std::string& fname) const {
0584   std::string fn = undressed_file_name(fname);
0585   FILE* file = fn.empty() ? stdout : ::fopen(fn.c_str(),"w");
0586   if ( !file ) {
0587     printout(ERROR,"DocumentHandler","+++ Failed to open output file: %s",fname.c_str());
0588     return 0;
0589   }
0590   TiXmlDocument* d = (TiXmlDocument*)doc.ptr();
0591   d->Print(file);
0592   if ( !fn.empty() ) ::fclose(file);
0593   return 1;
0594 }
0595 
0596 /// Dump partial or full XML trees
0597 void dd4hep::xml::dump_tree(Handle_t elt, std::ostream& os) {
0598   TiXmlNode* node = (TiXmlNode*)elt.ptr();
0599   TiXmlPrinter printer;
0600   printer.SetStreamPrinting();
0601   node->Accept( &printer );
0602   os << printer.Str();
0603 }
0604 
0605 /// Dump partial or full XML documents
0606 void dd4hep::xml::dump_tree(Document doc, std::ostream& os) {
0607   TiXmlDocument* node = (TiXmlDocument*)doc.ptr();
0608   TiXmlPrinter printer;
0609   printer.SetStreamPrinting();
0610   node->Accept( &printer );
0611   os << printer.Str();
0612 }
0613 #endif
0614 
0615 
0616 /// Default constructor of a document handler using TiXml
0617 DocumentHandler::DocumentHandler() {}
0618 
0619 /// Default destructor of a document handler using TiXml
0620 DocumentHandler::~DocumentHandler() {}
0621 
0622 /// Set minimum print level
0623 int DocumentHandler::setMinimumPrintLevel(int level)    {
0624   int tmp = s_minPrintLevel;
0625   s_minPrintLevel = level;
0626   return tmp;
0627 }
0628 
0629 /// Default comment string
0630 std::string DocumentHandler::defaultComment()  {
0631   const char comment[] = "\n"
0632     "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
0633     "      ++++   dd4hep generated alignment file using the         ++++\n"
0634     "      ++++   dd4hep Detector description XML generator.        ++++\n"
0635     "      ++++                                                     ++++\n"
0636     "      ++++   Parser:"
0637     XML_IMPLEMENTATION_TYPE
0638     "                ++++\n"
0639     "      ++++                                                     ++++\n"
0640     "      ++++                              M.Frank CERN/LHCb      ++++\n"
0641     "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n  ";
0642   return comment;
0643 }
0644 
0645 /// Load XML file and parse it.
0646 Document DocumentHandler::load(const std::string& fname) const {
0647   return load(fname, 0);
0648 }
0649 
0650 /// Load secondary XML file with relative addressing with respect to handle
0651 Document DocumentHandler::load(Handle_t base, const XmlChar* fname) const {
0652   return load(base, fname, 0);
0653 }
0654 
0655 /// Parse a standalong XML string into a document.
0656 Document DocumentHandler::parse(const char* bytes, size_t length) const {
0657   return parse(bytes, length, "xml-memory-buffer", 0);
0658 }
0659 
0660 /// System ID of a given XML entity
0661 std::string DocumentHandler::system_path(Handle_t base, const XmlChar* fname)   {
0662   std::string fn = _toString(fname);
0663   return system_path(base, fn);
0664 }
0665 
0666 /// System directory of a given XML entity
0667 std::string DocumentHandler::system_directory(Handle_t base, const XmlChar* fname)   {
0668   std::string path = system_path(base,fname);
0669   std::string dir = ::dirname((char*)path.c_str());
0670   return dir;
0671 }
0672 
0673 /// System directory of a given XML entity
0674 std::string DocumentHandler::system_directory(Handle_t base)   {
0675   std::string path = system_path(base);
0676   std::string dir = ::dirname((char*)path.c_str());
0677   return dir;
0678 }
0679 
0680 /// Create new XML document by parsing empty xml buffer
0681 Document DocumentHandler::create(const char* tag, const char* comment) const {
0682   std::string top(tag);
0683   std::string empty = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
0684   empty += "<" + top + "/>\0\0";
0685   Document doc = parse(empty.c_str(), empty.length() + 1);
0686   if (comment) {
0687     Element top_elt = doc.root();
0688     top_elt.addComment(comment);
0689   }
0690   return doc;
0691 }
0692 
0693 // Create new XML document by parsing empty xml buffer
0694 Document DocumentHandler::create(const std::string& tag, const std::string& comment) const   {
0695   return create(tag.c_str(), comment.c_str());
0696 }
0697 
0698 /// Dump partial or full XML trees to stdout
0699 void dd4hep::xml::dump_tree(Handle_t elt) {
0700   dump_tree(elt,std::cout);
0701 }
0702 
0703 /// Dump partial or full XML documents to stdout
0704 void dd4hep::xml::dump_tree(Document doc) {
0705   dump_tree(doc,std::cout);
0706 }