Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/Geant4/toolx/xml/loader is written in an unsupported language. File is not indexed.

0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003 
0004 #ifndef toolx_xml_loader
0005 #define toolx_xml_loader
0006 
0007 #include <tools/xml/tree>
0008 #include <tools/file>
0009 #include <tools/mnmx>
0010 
0011 #include <cstdio>
0012 #include <cctype> //iscntrl
0013 
0014 #include <expat.h>
0015 
0016 #ifdef TOOLS_MEM
0017 #include <tools/mem>
0018 namespace toolx {
0019 extern "C" {
0020 inline void* xml_malloc(size_t a_size){
0021   tools::mem::increment(tools::s_malloc().c_str());
0022   return ::malloc(a_size);
0023 }
0024 inline void* xml_realloc(void* a_ptr,size_t a_size){
0025   if(a_ptr==NULL) tools::mem::increment(tools::s_malloc().c_str());
0026   return ::realloc(a_ptr,a_size);
0027 }
0028 inline void xml_free(void* a_ptr){
0029   if(a_ptr!=NULL) tools::mem::decrement(tools::s_malloc().c_str());
0030   ::free(a_ptr);
0031 }
0032 }}
0033 #endif
0034 
0035 namespace toolx {
0036 namespace xml {
0037 
0038 class loader {
0039 #ifdef TOOLS_MEM
0040   TOOLS_SCLASS(toolx::xml::loader)
0041 #endif
0042 public:
0043   loader(tools::xml::factory& a_factory,
0044          std::ostream& a_out,bool a_verbose = false)
0045   :m_factory(a_factory)
0046   ,m_out(a_out)
0047   ,m_verbose(a_verbose)
0048   ,m_take_cntrl(false)
0049 
0050   ,m_errors(0)
0051   ,m_top(0) // Used to cleanup in case XML parsing failed.
0052   ,m_current(0)
0053   ,m_compressed_reader(0)
0054   ,m_depth(0)
0055   ,m_abort(false)
0056   {
0057 #ifdef TOOLS_MEM
0058     tools::mem::increment(s_class().c_str());
0059 #endif
0060   }
0061 
0062   virtual ~loader(){
0063     delete m_compressed_reader;
0064     clear();
0065 #ifdef TOOLS_MEM
0066     tools::mem::decrement(s_class().c_str());
0067 #endif
0068   }
0069 
0070 protected:
0071   loader(const loader& a_from)
0072   :m_factory(a_from.m_factory)
0073   ,m_out(a_from.m_out)
0074   ,m_verbose(a_from.m_verbose)
0075   ,m_take_cntrl(a_from.m_take_cntrl)
0076 
0077   ,m_errors(0)
0078   ,m_top(0) // Used to cleanup in case XML parsing failed.
0079   ,m_current(0)
0080   ,m_compressed_reader(0)
0081   ,m_depth(0)
0082   ,m_abort(false)
0083   {
0084 #ifdef TOOLS_MEM
0085     tools::mem::increment(s_class().c_str());
0086 #endif
0087   }
0088   loader& operator=(const loader& a_from){
0089     if(&a_from==this) return *this;
0090 
0091     m_verbose = a_from.m_verbose;
0092     m_take_cntrl = a_from.m_take_cntrl;
0093 
0094     m_errors = 0;
0095     m_top = 0;
0096     m_current = 0;
0097     m_compressed_reader = 0;
0098     m_depth = 0;
0099     m_abort = false;
0100 
0101     return *this;
0102   }
0103 
0104 public:
0105   virtual bool visit_end_element(tools::xml::tree&,bool& a_keep) {
0106     a_keep = true;
0107     return true;
0108   }
0109 
0110 public:
0111   void set_take_cntrl_chars(bool a_value) {m_take_cntrl = a_value;}
0112 
0113   std::ostream& out() const {return m_out;}
0114   void set_compressed_reader(tools::file::reader* aReader){
0115     delete m_compressed_reader;
0116     m_compressed_reader = aReader; //take ownership.
0117   }
0118 
0119   unsigned int errors() const {return m_errors;}
0120 
0121   void set_tags(const std::vector<std::string>& a_tags){m_tags=a_tags;}
0122   void add_tag(const std::string& a_tag){m_tags.push_back(a_tag);}
0123 
0124   bool load_file(const std::string& a_file,bool a_compressed) {
0125     clear();
0126     if(!parse_file(a_file,
0127                     (XML_StartElementHandler)start_element,
0128                     (XML_EndElementHandler)end_element,
0129                     this,a_compressed)) {
0130       clear();
0131       return false;
0132     }
0133     if(m_current) m_current->set_file(a_file);
0134     return true;
0135   }
0136 
0137   bool load_string(const std::string& a_string){
0138     clear();
0139     if(!parse_buffer(a_string.size(),a_string.c_str(),
0140                     (XML_StartElementHandler)start_element,
0141                     (XML_EndElementHandler)end_element,
0142                     this)) {
0143       clear();
0144       return false;
0145     }
0146     return true;
0147   }
0148 
0149   bool load_buffer(size_t aSize,const char* aBuffer){
0150     clear();
0151     if(!parse_buffer(aSize,aBuffer,
0152                     (XML_StartElementHandler)start_element,
0153                     (XML_EndElementHandler)end_element,
0154                     this)) {
0155       clear();
0156       return false;
0157     }
0158     return true;
0159   }
0160 
0161   const tools::xml::tree* top_item() const {return m_current;}
0162 
0163   tools::xml::tree* top_item(){return m_current;}
0164 
0165   void empty(){m_top = 0;m_current = 0;}
0166 
0167   bool is_tag(const std::string& a_string) const {
0168     size_t number = m_tags.size();
0169     for(size_t index=0;index<number;index++) {
0170       if(a_string==m_tags[index]) return true;
0171     }
0172     return false;
0173   }
0174 
0175 protected:
0176   void clear(){
0177     // In case of problem, deleting m_current is not sufficient.
0178     delete m_top;
0179     m_top = 0;
0180     m_current = 0;
0181   }
0182 
0183   bool parse_buffer(size_t aSize,const char* aBuffer,
0184                     XML_StartElementHandler a_start,XML_EndElementHandler a_end,
0185                     void* a_tag){
0186     m_errors = 0;
0187     if(!aSize) return true; //nothing to do.
0188     m_depth = 0;
0189     m_abort = false;
0190 
0191 #ifdef TOOLS_MEM
0192     XML_Memory_Handling_Suite mem;
0193     mem.malloc_fcn = xml_malloc;
0194     mem.realloc_fcn = xml_realloc;
0195     mem.free_fcn = xml_free;
0196     XML_Parser _parser = XML_ParserCreate_MM(NULL,&mem,NULL);
0197 #else
0198     XML_Parser _parser = XML_ParserCreate(NULL);
0199 #endif
0200 
0201     XML_SetUserData(_parser,a_tag);
0202     XML_SetElementHandler(_parser,a_start,a_end);
0203     XML_SetCharacterDataHandler(_parser,(XML_CharacterDataHandler)character_data_handler);
0204   //XML_SetProcessingInstructionHandler(_parser,processingInstructionHandler);
0205     char* buf = (char*)aBuffer;
0206     size_t l = aSize;
0207     int done = 0;
0208     do {
0209       size_t len = tools::mn<size_t>(l,BUFSIZ); //BUFSIZ in cstdio
0210       done = len < BUFSIZ ? 1 : 0;
0211       if(XML_Parse(_parser, buf, (int)len, done)==XML_STATUS_ERROR) {
0212         m_out << "parse_buffer :"
0213             << " " << XML_ErrorString(XML_GetErrorCode(_parser))
0214             << " at line " << (int)XML_GetCurrentLineNumber(_parser)
0215             << " at byte index " << (int)XML_GetCurrentByteIndex(_parser)
0216             << std::endl;
0217        {XML_Index pos = XML_GetCurrentByteIndex(_parser);
0218         XML_Index pmn = tools::mx<XML_Index>(pos-10,0);
0219         XML_Index pmx = tools::mn<XML_Index>(pos+10,XML_Index(aSize)-1);
0220         std::string c = " ";
0221        {for(XML_Index p=pmn;p<=pmx;p++) {c[0] = *(aBuffer+p);m_out << c;}
0222         m_out << std::endl;}
0223        {for(XML_Index p=pmn;p<pos;p++) m_out << " ";
0224         m_out << "^" << std::endl;}}
0225         XML_ParserFree(_parser);
0226         return false;
0227       }
0228       if(m_abort) {
0229         XML_ParserFree(_parser);
0230         return false;
0231       }
0232       buf += len;
0233       l -= len;
0234     } while (!done);
0235     XML_ParserFree(_parser);
0236     return true;
0237   }
0238 
0239   bool parse_file(const std::string& a_file,
0240                   XML_StartElementHandler a_start,XML_EndElementHandler a_end,
0241                   void* a_tag,bool a_compressed){
0242     if(m_verbose) {
0243       m_out << "parse_file :"
0244             << " parse file " << tools::sout(a_file) << "..." << std::endl;
0245     }
0246     m_errors = 0;
0247 
0248     bool use_zlib = false;
0249     if(a_compressed) {
0250       if(m_verbose) {
0251         m_out << "parse_file :"
0252               << " uncompress requested for file "
0253               << tools::sout(a_file) << "."
0254               << std::endl;
0255       }
0256       use_zlib = true;
0257     } else {
0258       // may be compressed anyway :
0259       bool compressed;
0260       if(!tools::file::is_gzip(a_file,compressed)) {
0261         m_out << "parse_file :"
0262               << " tools::file::is_gzip() failed for " << a_file << "."
0263               << std::endl;
0264         return false;
0265       }
0266       if(compressed) use_zlib = true;
0267     }
0268 
0269     tools::file::reader* freader = 0;
0270     bool delete_freader = false;
0271     if(use_zlib) {
0272       if(!m_compressed_reader) {
0273         m_out << "parse_file :"
0274               << " no compressed reader given."
0275               << std::endl;
0276         return false;
0277       }
0278       freader = m_compressed_reader;
0279     } else {
0280       freader = new tools::FILE_reader();
0281       delete_freader = true;
0282     }
0283     if(!freader->open(a_file)) {
0284       m_out << "parse_file :"
0285             << " can't open file " << a_file << std::endl;
0286       if(delete_freader) delete freader;
0287       return false;
0288     }
0289 
0290     m_depth = 0;
0291     m_abort = false;
0292 
0293 #ifdef TOOLS_MEM
0294     XML_Memory_Handling_Suite mem;
0295     mem.malloc_fcn = xml_malloc;
0296     mem.realloc_fcn = xml_realloc;
0297     mem.free_fcn = xml_free;
0298     XML_Parser _parser = XML_ParserCreate_MM(NULL,&mem,NULL);
0299 #else
0300     XML_Parser _parser = XML_ParserCreate(NULL);
0301 #endif
0302 
0303     XML_SetUserData(_parser,a_tag);
0304     XML_SetElementHandler(_parser,a_start,a_end);
0305     XML_SetCharacterDataHandler(_parser,(XML_CharacterDataHandler)character_data_handler);
0306     //XML_SetProcessingInstructionHandler(_parser,
0307     //      processingInstructionHandler);
0308 
0309 
0310     //char buf[1024 * BUFSIZ];
0311     char buf[BUFSIZ];
0312     int done = 0;
0313     do {
0314       size_t len;
0315       if(!freader->read(buf,sizeof(buf),len)) {
0316         XML_ParserFree(_parser);
0317         freader->close();
0318         if(delete_freader) delete freader;
0319         return false;
0320       }
0321       done = len < sizeof(buf) ? 1 : 0;
0322       if(XML_Parse(_parser, buf, (int)len, done)==XML_STATUS_ERROR) {
0323         m_out << "parse_file :"
0324             << " in file " << tools::sout(a_file)
0325             << " " << XML_ErrorString(XML_GetErrorCode(_parser))
0326             << " at line " << (int)XML_GetCurrentLineNumber(_parser)
0327             << std::endl;
0328         XML_ParserFree(_parser);
0329         freader->close();
0330         if(delete_freader) delete freader;
0331         return false;
0332       }
0333       if(m_abort) {
0334         XML_ParserFree(_parser);
0335         freader->close();
0336         if(delete_freader) delete freader;
0337         return false;
0338       }
0339     } while (!done);
0340     XML_ParserFree(_parser);
0341     freader->close();
0342     if(m_verbose) {
0343       m_out << "parse_file :"
0344           << " parse file " << tools::sout(a_file) << " done." << std::endl;
0345     }
0346     if(delete_freader) delete freader;
0347     return true;
0348   }
0349 
0350 protected:
0351   static void character_data_handler(void* aUserData,const XML_Char* a_string,int aLength){
0352     loader* This = (loader*)aUserData;
0353     std::string _s;
0354     _s.resize(aLength);
0355     size_t count = 0;
0356     char* p = (char*)a_string;
0357     for (int i = 0; i < aLength; i++, p++) {
0358       if(This->m_take_cntrl || (!iscntrl(*p))) {
0359         _s[count] = *p;
0360         count++;
0361       }
0362     }
0363     if(count) {
0364       _s.resize(count);
0365       This->m_value += _s;
0366     }
0367   }
0368 
0369   static void start_element(void* aUserData,const XML_Char* a_name,const XML_Char** a_atbs){
0370     loader* This = (loader*)aUserData;
0371     if(This->m_abort) return; //Do nothing.
0372 
0373     This->m_depth++;
0374     This->m_value = "";
0375 
0376     std::string name = a_name; //Can't be empty
0377     if(This->is_tag(name)) {
0378 
0379       if(!This->m_current) {
0380         if(This->m_depth==1) {
0381           // Ok. Head.
0382         } else {
0383           This->m_out << "start_element :"
0384               << " no tag with a depth of " << This->m_depth
0385               << std::endl;
0386           This->m_abort = true;
0387           return;
0388         }
0389       } else {
0390         int delta = This->m_current->depth() - This->m_depth;
0391         if(delta>=1) {
0392           This->m_out << "start_element :"
0393               << " for element " << tools::sout(name)
0394               << " tag with a delta depth of " << delta
0395               << std::endl;
0396           This->m_abort = true;
0397           return;
0398         }
0399       }
0400 
0401       std::vector<tools::xml::tree::atb> atbs;
0402      {const XML_Char** a_atts = a_atbs;
0403       while((*a_atts)&&(*(a_atts+1))) {
0404         atbs.push_back(tools::xml::tree::atb(*a_atts,*(a_atts+1)));
0405         a_atts+=2;
0406       }}
0407 
0408       tools::xml::tree* parent = This->m_current;
0409       tools::xml::tree* _tree = This->m_factory.create(name,atbs,parent);
0410       if(!_tree) {
0411         This->m_out << "start_element :"
0412             << " can't create a tree for tag " << tools::sout(name)
0413             << std::endl;
0414         This->m_abort = true;
0415         return;
0416       }
0417 
0418       //out << "start_element :" << std::endl;
0419       //_tree->print_xml(*(This->m_printer),"debug : ");
0420 
0421       if(parent) parent->add_child(_tree);
0422 
0423 /*
0424       if(This->m_current && !This->m_current->parent()) {
0425         This->m_out << "start_element :"
0426             << " warning : current tree without parent."
0427             << " Potential mem leak."
0428             << std::endl;
0429       }
0430 */
0431 
0432       This->m_current = _tree;
0433       _tree->set_depth(This->m_depth); // Internal only.
0434 
0435       if(!This->m_top) This->m_top = _tree;
0436 
0437     } else {
0438 
0439       if(!This->m_current) {
0440 
0441         // Can't be in a non-tag without a tag !
0442         This->m_out << "start_element :"
0443             << " for element " << tools::sout(name)
0444             << " non-tag without some parent tag."
0445             << std::endl;
0446         This->m_abort = true;
0447         return;
0448 
0449       } else {
0450 
0451         int delta =  This->m_depth - This->m_current->depth();
0452         if(delta>1) {
0453 
0454           This->m_out << "start_element :"
0455               << " for element " << tools::sout(name)
0456               << " grand child of a tag."
0457               << std::endl;
0458           This->m_abort = true;
0459           return;
0460 
0461         } else if(delta==1) { //ok
0462 
0463           This->m_atbs.clear();
0464          {const XML_Char** a_atts = a_atbs;
0465           while((*a_atts)&&(*(a_atts+1))) {
0466             This->m_atbs.push_back(tools::xml::tree::atb(*a_atts,*(a_atts+1)));
0467             a_atts+=2;
0468           }}
0469 
0470         } else {
0471 
0472           This->m_out << "start_element :"
0473               << " for element " << tools::sout(name)
0474               << " non-tag with a delta depth of " << delta
0475               << std::endl;
0476           This->m_abort = true;
0477           return;
0478 
0479         }
0480       }
0481 
0482     }
0483   }
0484 
0485 
0486   static void end_element(void* aUserData,const XML_Char* a_name){
0487     loader* This = (loader*)aUserData;
0488     if(This->m_abort) return; //Do nothing.
0489 
0490     if(This->m_current) {
0491 
0492       tools::xml::tree* tr = This->m_current;
0493       int delta = This->m_depth - tr->depth();
0494       if(delta==0) { //Back to a tag :
0495 
0496         tools::xml::tree* parent = tr->parent();
0497 
0498         bool keep = false;
0499         bool cont = This->visit_end_element(*tr,keep);
0500         if(keep) {
0501           if(parent) {
0502 /*
0503             if(!This->m_current->parent()) {
0504               This->m_out << "end_element :"
0505                   << " warning : current tree without parent (1)."
0506                   << " Potential mem leak."
0507                   << std::endl;
0508             }
0509 */
0510             This->m_current = parent;
0511           }
0512         } else {
0513           //FIXME : the top could be recreated !
0514           if(This->m_top==tr) This->m_top = 0;
0515 
0516           if(parent) {
0517             parent->remove_child(tr); //delete the tr
0518           } else {
0519             delete tr;
0520           }
0521 
0522 /*
0523           if(!This->m_current->parent()) {
0524             This->m_out << "end_element :"
0525                    << " warning : current tree without parent (2)."
0526                    << " Potential mem leak."
0527                    << std::endl;
0528           }
0529 */
0530 
0531           This->m_current = parent; //parent could be 0 : ok.
0532         }
0533 
0534         if(!cont) This->m_abort = true;
0535 
0536       } else if(delta==1) { //Back to a child of tag :
0537 
0538         //FIXME : correct m_value ? (Can we pick the one of a sub item ?)
0539         tr->add_element(std::string(a_name),This->m_atbs,This->m_value);
0540         //This->m_value = "";
0541 
0542       } else {
0543 
0544         This->m_out << "end_element :"
0545             << " problem for element " << tools::sout(std::string(a_name))
0546             << " : delta depth of " << delta
0547             << std::endl;
0548         This->m_abort = true;
0549 
0550       }
0551 
0552     }
0553 
0554 
0555     This->m_depth--;
0556   }
0557 
0558 protected:
0559   tools::xml::factory& m_factory;
0560   std::ostream& m_out;
0561 protected:
0562   bool m_verbose;
0563   bool m_take_cntrl;
0564   unsigned int m_errors;
0565   std::vector<std::string> m_tags;
0566   tools::xml::tree* m_top;
0567   tools::xml::tree* m_current;
0568   //std::vector<tools::xml::tree::atb> m_atbs;
0569   std::vector< std::pair<std::string,std::string> > m_atbs;
0570   std::string m_value;
0571   tools::file::reader* m_compressed_reader;
0572   unsigned int m_depth;
0573   bool m_abort;
0574 };
0575 
0576 }}
0577 
0578 #endif