Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/externals/g4tools/include/toolx/xml/loader

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 // Copyright (C) 2010, Guy Barrand. All rights reserved.
  2 // See the file tools.license for terms.
  3 
  4 #ifndef toolx_xml_loader
  5 #define toolx_xml_loader
  6 
  7 #include <tools/xml/tree>
  8 #include <tools/file>
  9 #include <tools/mnmx>
 10 
 11 #include <cstdio>
 12 #include <cctype> //iscntrl
 13 
 14 #include <expat.h>
 15 
 16 #ifdef TOOLS_MEM
 17 #include <tools/mem>
 18 namespace toolx {
 19 extern "C" {
 20 inline void* xml_malloc(size_t a_size){
 21   tools::mem::increment(tools::s_malloc().c_str());
 22   return ::malloc(a_size);
 23 }
 24 inline void* xml_realloc(void* a_ptr,size_t a_size){
 25   if(a_ptr==NULL) tools::mem::increment(tools::s_malloc().c_str());
 26   return ::realloc(a_ptr,a_size);
 27 }
 28 inline void xml_free(void* a_ptr){
 29   if(a_ptr!=NULL) tools::mem::decrement(tools::s_malloc().c_str());
 30   ::free(a_ptr);
 31 }
 32 }}
 33 #endif
 34 
 35 namespace toolx {
 36 namespace xml {
 37 
 38 class loader {
 39 #ifdef TOOLS_MEM
 40   TOOLS_SCLASS(toolx::xml::loader)
 41 #endif
 42 public:
 43   loader(tools::xml::factory& a_factory,
 44          std::ostream& a_out,bool a_verbose = false)
 45   :m_factory(a_factory)
 46   ,m_out(a_out)
 47   ,m_verbose(a_verbose)
 48   ,m_take_cntrl(false)
 49 
 50   ,m_errors(0)
 51   ,m_top(0) // Used to cleanup in case XML parsing failed.
 52   ,m_current(0)
 53   ,m_compressed_reader(0)
 54   ,m_depth(0)
 55   ,m_abort(false)
 56   {
 57 #ifdef TOOLS_MEM
 58     tools::mem::increment(s_class().c_str());
 59 #endif
 60   }
 61 
 62   virtual ~loader(){
 63     delete m_compressed_reader;
 64     clear();
 65 #ifdef TOOLS_MEM
 66     tools::mem::decrement(s_class().c_str());
 67 #endif
 68   }
 69 
 70 protected:
 71   loader(const loader& a_from)
 72   :m_factory(a_from.m_factory)
 73   ,m_out(a_from.m_out)
 74   ,m_verbose(a_from.m_verbose)
 75   ,m_take_cntrl(a_from.m_take_cntrl)
 76 
 77   ,m_errors(0)
 78   ,m_top(0) // Used to cleanup in case XML parsing failed.
 79   ,m_current(0)
 80   ,m_compressed_reader(0)
 81   ,m_depth(0)
 82   ,m_abort(false)
 83   {
 84 #ifdef TOOLS_MEM
 85     tools::mem::increment(s_class().c_str());
 86 #endif
 87   }
 88   loader& operator=(const loader& a_from){
 89     if(&a_from==this) return *this;
 90 
 91     m_verbose = a_from.m_verbose;
 92     m_take_cntrl = a_from.m_take_cntrl;
 93 
 94     m_errors = 0;
 95     m_top = 0;
 96     m_current = 0;
 97     m_compressed_reader = 0;
 98     m_depth = 0;
 99     m_abort = false;
100 
101     return *this;
102   }
103 
104 public:
105   virtual bool visit_end_element(tools::xml::tree&,bool& a_keep) {
106     a_keep = true;
107     return true;
108   }
109 
110 public:
111   void set_take_cntrl_chars(bool a_value) {m_take_cntrl = a_value;}
112 
113   std::ostream& out() const {return m_out;}
114   void set_compressed_reader(tools::file::reader* aReader){
115     delete m_compressed_reader;
116     m_compressed_reader = aReader; //take ownership.
117   }
118 
119   unsigned int errors() const {return m_errors;}
120 
121   void set_tags(const std::vector<std::string>& a_tags){m_tags=a_tags;}
122   void add_tag(const std::string& a_tag){m_tags.push_back(a_tag);}
123 
124   bool load_file(const std::string& a_file,bool a_compressed) {
125     clear();
126     if(!parse_file(a_file,
127                     (XML_StartElementHandler)start_element,
128                     (XML_EndElementHandler)end_element,
129                     this,a_compressed)) {
130       clear();
131       return false;
132     }
133     if(m_current) m_current->set_file(a_file);
134     return true;
135   }
136 
137   bool load_string(const std::string& a_string){
138     clear();
139     if(!parse_buffer(a_string.size(),a_string.c_str(),
140                     (XML_StartElementHandler)start_element,
141                     (XML_EndElementHandler)end_element,
142                     this)) {
143       clear();
144       return false;
145     }
146     return true;
147   }
148 
149   bool load_buffer(size_t aSize,const char* aBuffer){
150     clear();
151     if(!parse_buffer(aSize,aBuffer,
152                     (XML_StartElementHandler)start_element,
153                     (XML_EndElementHandler)end_element,
154                     this)) {
155       clear();
156       return false;
157     }
158     return true;
159   }
160 
161   const tools::xml::tree* top_item() const {return m_current;}
162 
163   tools::xml::tree* top_item(){return m_current;}
164 
165   void empty(){m_top = 0;m_current = 0;}
166 
167   bool is_tag(const std::string& a_string) const {
168     size_t number = m_tags.size();
169     for(size_t index=0;index<number;index++) {
170       if(a_string==m_tags[index]) return true;
171     }
172     return false;
173   }
174 
175 protected:
176   void clear(){
177     // In case of problem, deleting m_current is not sufficient.
178     delete m_top;
179     m_top = 0;
180     m_current = 0;
181   }
182 
183   bool parse_buffer(size_t aSize,const char* aBuffer,
184                     XML_StartElementHandler a_start,XML_EndElementHandler a_end,
185                     void* a_tag){
186     m_errors = 0;
187     if(!aSize) return true; //nothing to do.
188     m_depth = 0;
189     m_abort = false;
190 
191 #ifdef TOOLS_MEM
192     XML_Memory_Handling_Suite mem;
193     mem.malloc_fcn = xml_malloc;
194     mem.realloc_fcn = xml_realloc;
195     mem.free_fcn = xml_free;
196     XML_Parser _parser = XML_ParserCreate_MM(NULL,&mem,NULL);
197 #else
198     XML_Parser _parser = XML_ParserCreate(NULL);
199 #endif
200 
201     XML_SetUserData(_parser,a_tag);
202     XML_SetElementHandler(_parser,a_start,a_end);
203     XML_SetCharacterDataHandler(_parser,(XML_CharacterDataHandler)character_data_handler);
204   //XML_SetProcessingInstructionHandler(_parser,processingInstructionHandler);
205     char* buf = (char*)aBuffer;
206     size_t l = aSize;
207     int done = 0;
208     do {
209       size_t len = tools::mn<size_t>(l,BUFSIZ); //BUFSIZ in cstdio
210       done = len < BUFSIZ ? 1 : 0;
211       if(XML_Parse(_parser, buf, (int)len, done)==XML_STATUS_ERROR) {
212         m_out << "parse_buffer :"
213             << " " << XML_ErrorString(XML_GetErrorCode(_parser))
214             << " at line " << (int)XML_GetCurrentLineNumber(_parser)
215             << " at byte index " << (int)XML_GetCurrentByteIndex(_parser)
216             << std::endl;
217        {XML_Index pos = XML_GetCurrentByteIndex(_parser);
218         XML_Index pmn = tools::mx<XML_Index>(pos-10,0);
219         XML_Index pmx = tools::mn<XML_Index>(pos+10,XML_Index(aSize)-1);
220         std::string c = " ";
221        {for(XML_Index p=pmn;p<=pmx;p++) {c[0] = *(aBuffer+p);m_out << c;}
222         m_out << std::endl;}
223        {for(XML_Index p=pmn;p<pos;p++) m_out << " ";
224         m_out << "^" << std::endl;}}
225         XML_ParserFree(_parser);
226         return false;
227       }
228       if(m_abort) {
229         XML_ParserFree(_parser);
230         return false;
231       }
232       buf += len;
233       l -= len;
234     } while (!done);
235     XML_ParserFree(_parser);
236     return true;
237   }
238 
239   bool parse_file(const std::string& a_file,
240                   XML_StartElementHandler a_start,XML_EndElementHandler a_end,
241                   void* a_tag,bool a_compressed){
242     if(m_verbose) {
243       m_out << "parse_file :"
244             << " parse file " << tools::sout(a_file) << "..." << std::endl;
245     }
246     m_errors = 0;
247 
248     bool use_zlib = false;
249     if(a_compressed) {
250       if(m_verbose) {
251         m_out << "parse_file :"
252               << " uncompress requested for file "
253               << tools::sout(a_file) << "."
254               << std::endl;
255       }
256       use_zlib = true;
257     } else {
258       // may be compressed anyway :
259       bool compressed;
260       if(!tools::file::is_gzip(a_file,compressed)) {
261         m_out << "parse_file :"
262               << " tools::file::is_gzip() failed for " << a_file << "."
263               << std::endl;
264         return false;
265       }
266       if(compressed) use_zlib = true;
267     }
268 
269     tools::file::reader* freader = 0;
270     bool delete_freader = false;
271     if(use_zlib) {
272       if(!m_compressed_reader) {
273         m_out << "parse_file :"
274               << " no compressed reader given."
275               << std::endl;
276         return false;
277       }
278       freader = m_compressed_reader;
279     } else {
280       freader = new tools::FILE_reader();
281       delete_freader = true;
282     }
283     if(!freader->open(a_file)) {
284       m_out << "parse_file :"
285             << " can't open file " << a_file << std::endl;
286       if(delete_freader) delete freader;
287       return false;
288     }
289 
290     m_depth = 0;
291     m_abort = false;
292 
293 #ifdef TOOLS_MEM
294     XML_Memory_Handling_Suite mem;
295     mem.malloc_fcn = xml_malloc;
296     mem.realloc_fcn = xml_realloc;
297     mem.free_fcn = xml_free;
298     XML_Parser _parser = XML_ParserCreate_MM(NULL,&mem,NULL);
299 #else
300     XML_Parser _parser = XML_ParserCreate(NULL);
301 #endif
302 
303     XML_SetUserData(_parser,a_tag);
304     XML_SetElementHandler(_parser,a_start,a_end);
305     XML_SetCharacterDataHandler(_parser,(XML_CharacterDataHandler)character_data_handler);
306     //XML_SetProcessingInstructionHandler(_parser,
307     //      processingInstructionHandler);
308 
309 
310     //char buf[1024 * BUFSIZ];
311     char buf[BUFSIZ];
312     int done = 0;
313     do {
314       size_t len;
315       if(!freader->read(buf,sizeof(buf),len)) {
316         XML_ParserFree(_parser);
317         freader->close();
318         if(delete_freader) delete freader;
319         return false;
320       }
321       done = len < sizeof(buf) ? 1 : 0;
322       if(XML_Parse(_parser, buf, (int)len, done)==XML_STATUS_ERROR) {
323         m_out << "parse_file :"
324             << " in file " << tools::sout(a_file)
325             << " " << XML_ErrorString(XML_GetErrorCode(_parser))
326             << " at line " << (int)XML_GetCurrentLineNumber(_parser)
327             << std::endl;
328         XML_ParserFree(_parser);
329         freader->close();
330         if(delete_freader) delete freader;
331         return false;
332       }
333       if(m_abort) {
334         XML_ParserFree(_parser);
335         freader->close();
336         if(delete_freader) delete freader;
337         return false;
338       }
339     } while (!done);
340     XML_ParserFree(_parser);
341     freader->close();
342     if(m_verbose) {
343       m_out << "parse_file :"
344           << " parse file " << tools::sout(a_file) << " done." << std::endl;
345     }
346     if(delete_freader) delete freader;
347     return true;
348   }
349 
350 protected:
351   static void character_data_handler(void* aUserData,const XML_Char* a_string,int aLength){
352     loader* This = (loader*)aUserData;
353     std::string _s;
354     _s.resize(aLength);
355     size_t count = 0;
356     char* p = (char*)a_string;
357     for (int i = 0; i < aLength; i++, p++) {
358       if(This->m_take_cntrl || (!iscntrl(*p))) {
359         _s[count] = *p;
360         count++;
361       }
362     }
363     if(count) {
364       _s.resize(count);
365       This->m_value += _s;
366     }
367   }
368 
369   static void start_element(void* aUserData,const XML_Char* a_name,const XML_Char** a_atbs){
370     loader* This = (loader*)aUserData;
371     if(This->m_abort) return; //Do nothing.
372 
373     This->m_depth++;
374     This->m_value = "";
375 
376     std::string name = a_name; //Can't be empty
377     if(This->is_tag(name)) {
378 
379       if(!This->m_current) {
380         if(This->m_depth==1) {
381           // Ok. Head.
382         } else {
383           This->m_out << "start_element :"
384               << " no tag with a depth of " << This->m_depth
385               << std::endl;
386           This->m_abort = true;
387           return;
388         }
389       } else {
390         int delta = This->m_current->depth() - This->m_depth;
391         if(delta>=1) {
392           This->m_out << "start_element :"
393               << " for element " << tools::sout(name)
394               << " tag with a delta depth of " << delta
395               << std::endl;
396           This->m_abort = true;
397           return;
398         }
399       }
400 
401       std::vector<tools::xml::tree::atb> atbs;
402      {const XML_Char** a_atts = a_atbs;
403       while((*a_atts)&&(*(a_atts+1))) {
404         atbs.push_back(tools::xml::tree::atb(*a_atts,*(a_atts+1)));
405         a_atts+=2;
406       }}
407 
408       tools::xml::tree* parent = This->m_current;
409       tools::xml::tree* _tree = This->m_factory.create(name,atbs,parent);
410       if(!_tree) {
411         This->m_out << "start_element :"
412             << " can't create a tree for tag " << tools::sout(name)
413             << std::endl;
414         This->m_abort = true;
415         return;
416       }
417 
418       //out << "start_element :" << std::endl;
419       //_tree->print_xml(*(This->m_printer),"debug : ");
420 
421       if(parent) parent->add_child(_tree);
422 
423 /*
424       if(This->m_current && !This->m_current->parent()) {
425         This->m_out << "start_element :"
426             << " warning : current tree without parent."
427             << " Potential mem leak."
428             << std::endl;
429       }
430 */
431 
432       This->m_current = _tree;
433       _tree->set_depth(This->m_depth); // Internal only.
434 
435       if(!This->m_top) This->m_top = _tree;
436 
437     } else {
438 
439       if(!This->m_current) {
440 
441         // Can't be in a non-tag without a tag !
442         This->m_out << "start_element :"
443             << " for element " << tools::sout(name)
444             << " non-tag without some parent tag."
445             << std::endl;
446         This->m_abort = true;
447         return;
448 
449       } else {
450 
451         int delta =  This->m_depth - This->m_current->depth();
452         if(delta>1) {
453 
454           This->m_out << "start_element :"
455               << " for element " << tools::sout(name)
456               << " grand child of a tag."
457               << std::endl;
458           This->m_abort = true;
459           return;
460 
461         } else if(delta==1) { //ok
462 
463           This->m_atbs.clear();
464          {const XML_Char** a_atts = a_atbs;
465           while((*a_atts)&&(*(a_atts+1))) {
466             This->m_atbs.push_back(tools::xml::tree::atb(*a_atts,*(a_atts+1)));
467             a_atts+=2;
468           }}
469 
470         } else {
471 
472           This->m_out << "start_element :"
473               << " for element " << tools::sout(name)
474               << " non-tag with a delta depth of " << delta
475               << std::endl;
476           This->m_abort = true;
477           return;
478 
479         }
480       }
481 
482     }
483   }
484 
485 
486   static void end_element(void* aUserData,const XML_Char* a_name){
487     loader* This = (loader*)aUserData;
488     if(This->m_abort) return; //Do nothing.
489 
490     if(This->m_current) {
491 
492       tools::xml::tree* tr = This->m_current;
493       int delta = This->m_depth - tr->depth();
494       if(delta==0) { //Back to a tag :
495 
496         tools::xml::tree* parent = tr->parent();
497 
498         bool keep = false;
499         bool cont = This->visit_end_element(*tr,keep);
500         if(keep) {
501           if(parent) {
502 /*
503             if(!This->m_current->parent()) {
504               This->m_out << "end_element :"
505                   << " warning : current tree without parent (1)."
506                   << " Potential mem leak."
507                   << std::endl;
508             }
509 */
510             This->m_current = parent;
511           }
512         } else {
513           //FIXME : the top could be recreated !
514           if(This->m_top==tr) This->m_top = 0;
515 
516           if(parent) {
517             parent->remove_child(tr); //delete the tr
518           } else {
519             delete tr;
520           }
521 
522 /*
523           if(!This->m_current->parent()) {
524             This->m_out << "end_element :"
525                    << " warning : current tree without parent (2)."
526                    << " Potential mem leak."
527                    << std::endl;
528           }
529 */
530 
531           This->m_current = parent; //parent could be 0 : ok.
532         }
533 
534         if(!cont) This->m_abort = true;
535 
536       } else if(delta==1) { //Back to a child of tag :
537 
538         //FIXME : correct m_value ? (Can we pick the one of a sub item ?)
539         tr->add_element(std::string(a_name),This->m_atbs,This->m_value);
540         //This->m_value = "";
541 
542       } else {
543 
544         This->m_out << "end_element :"
545             << " problem for element " << tools::sout(std::string(a_name))
546             << " : delta depth of " << delta
547             << std::endl;
548         This->m_abort = true;
549 
550       }
551 
552     }
553 
554 
555     This->m_depth--;
556   }
557 
558 protected:
559   tools::xml::factory& m_factory;
560   std::ostream& m_out;
561 protected:
562   bool m_verbose;
563   bool m_take_cntrl;
564   unsigned int m_errors;
565   std::vector<std::string> m_tags;
566   tools::xml::tree* m_top;
567   tools::xml::tree* m_current;
568   //std::vector<tools::xml::tree::atb> m_atbs;
569   std::vector< std::pair<std::string,std::string> > m_atbs;
570   std::string m_value;
571   tools::file::reader* m_compressed_reader;
572   unsigned int m_depth;
573   bool m_abort;
574 };
575 
576 }}
577 
578 #endif