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