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