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