17 string XML_FILENAME =
"/home/davidl/work/latest/sim-recon/src/libraries/HDDM/event.xml";
26 void startElement(
void *data,
const char *el,
const char **attr);
39 int main(
int narg,
char *argv[])
45 stack<string> ancestory;
47 XML_Parser parser = XML_ParserCreate(NULL);
48 XML_SetUserData(parser, &ancestory);
54 ifs.seekg (0, ios::end);
55 int length = ifs.tellg();
56 ifs.seekg (0, ios::beg);
58 if(length > 102400)length = 102400;
60 char *buff =
new char[length];
61 ifs.read (buff,length);
65 char *end = strstr(buff,
"</HDDM>");
67 end[strlen(
"</HDDM>")] = 0;
68 length = strlen(buff);
72 mkdir(
"hddm_root_generated", S_IRWXU | S_IRWXG | S_IRWXO);
75 ofstream hddmxmlofs(
"hddm_root_generated/hddm_def.xml");
76 if(hddmxmlofs.is_open()){
85 mkdir(
"hddm_root_generated/HDDM", S_IRWXU | S_IRWXG | S_IRWXO);
86 system(
"cd hddm_root_generated/HDDM ; hddm-c ../hddm_def.xml");
87 system(
"cd hddm_root_generated/HDDM ; hddm-cpp ../hddm_def.xml");
92 XML_Parse(parser, buff, length, done);
104 map<string, DClassDef>::iterator iter;
106 string name = iter->first;
107 string type = iter->second.name;
108 map<string,string> &members = iter->second.members;
111 if(name ==
"HDDM_t")
continue;
114 string fname =
string(
"hddm_root_generated/") + name +
".h";
115 cout<<
"writing "<<fname<<endl;
116 ofstream ofs(fname.c_str());
119 ofs <<
"#include<vector>" << endl;
120 ofs <<
"using namespace std;" << endl;
122 ofs <<
"#include<Rtypes.h>" << endl;
123 ofs <<
"#include<TObject.h>" << endl;
126 ofs <<
"#ifndef _" << name <<
"_"<<endl;
127 ofs <<
"#define _" << name <<
"_"<<endl;
129 ofs <<
"typedef int Particle_t;" << endl;
133 set<string> &include_types = iter->second.include_types;
134 set<string>::iterator iter_inc;
135 for(iter_inc=include_types.begin(); iter_inc!=include_types.end(); iter_inc++){
136 ofs <<
"#include \"" << *iter_inc <<
"_t.h\""<<endl;
141 ofs<<
"class " << name <<
":public TObject{" << endl;
142 ofs<<
" public:"<<endl;
145 map<string,string>::iterator iter2;
146 for(iter2=members.begin(); iter2!=members.end(); iter2++){
147 ofs <<
" " << iter2->second <<
" " << iter2->first <<
";" << endl;
150 ofs<<
" ClassDef("<<name<<
",1)"<<endl;
154 ofs <<
"#endif" << endl;
161 ofstream ofs(
"hddm_root_generated/makefile");
163 ofs <<
"all: dictionaries copy_routines tool" << endl;
165 ofs <<
"dictionaries: *.h"<<endl;
167 string name = iter->first;
168 if(name ==
"HDDM_t")
continue;
170 string cmd =
" rootcint -f " + name +
"_Dict.cc -c " + name +
".h";
175 string name = iter->first;
176 if(name ==
"HDDM_t")
continue;
178 string cmd =
" c++ `root-config --cflags` -c " + name +
"_Dict.cc" +
CXXFLAGS;
181 ofs <<
" ar -r libhddm_root.a *_t_Dict.o" << endl;
185 ofs <<
"copy_routines: hddm_root_CopyRoutines.cc hddm_root_CopyRoutines.h" << endl;
186 string cmd =
" c++ `root-config --cflags` -c -I${HALLD_RECON_HOME}/${BMS_OSNAME}/include -I. hddm_root_CopyRoutines.cc" +
CXXFLAGS;
188 ofs <<
" ar -r libhddm_root.a hddm_root_CopyRoutines.o" << endl;
191 ofs <<
"tool: hddm2root_*.cc" << endl;
192 cmd =
" c++ `root-config --cflags --libs` -I${HALLD_RECON_HOME}/${BMS_OSNAME}/include -I. hddm2root_" +
HDDM_CLASS +
".cc -o hddm2root_" +
HDDM_CLASS +
CXXFLAGS +
" ./libhddm_root.a -lbz2 -lz -L${HALLD_RECON_HOME}/${BMS_OSNAME}/lib -lHDDM -lxstream";
207 cout<<
"Code generation complete. Issue the following"<<endl;
208 cout<<
"to build the hddm2root_"<<
HDDM_CLASS<<
" tool:"<<endl;
210 cout<<
" make -C hddm_root_generated"<<endl;
212 cout<<
"The tool will be left as hddm_root_generated/hddm2root_"<<
HDDM_CLASS<<endl;
224 stack<string> &ancestory = *(stack<string>*)data;
230 map<string, string> members;
231 bool is_unbounded =
false;
232 for (
int i = 0; attr[i]; i += 2) {
233 string name(attr[i]);
234 string type(attr[i+1]);
238 if(name ==
"minOccurs")
continue;
239 if(name ==
"version")
continue;
240 if(name ==
"maxOccurs"){
241 if(type ==
"unbounded"){
245 if(atoi(type.c_str())>1){
252 if(type.find(
"GeV")== 0 )
continue;
253 if(type ==
"rad")
continue;
254 if(type ==
"ns")
continue;
255 if(type ==
"cm")
continue;
257 if(type==
"boolean") type =
"bool";
260 members[name] = type;
265 if(!ancestory.empty()){
267 CLASSES[ancestory.top()].members[name+
"s"] =
string(
"vector<") + name +
"_t>";
269 CLASSES[ancestory.top()].members[name] = name +
"_t";
271 CLASSES[ancestory.top()].include_types.insert(name);
276 class_def.
members.insert(members.begin(), members.end());
277 class_def.
depth = ancestory.size();
280 ancestory.push(name +
"_t");
288 stack<string> &ancestory = *(stack<string>*)data;
299 cout <<
"Writing hddm_root_generated/hddm_root_CopyRoutines.h" << endl;
300 ofstream ofs(
"hddm_root_generated/hddm_root_CopyRoutines.h");
303 time_t t = time(NULL);
305 ofs <<
"// Auto-generated HDDM to ROOT copy routines DO NOT EDIT" << endl;
307 ofs <<
"// "<<ctime(&t);
312 ofs <<
"#define Particle_t Particle_tt"<<endl;
313 map<string, DClassDef>::iterator iter;
314 for(
unsigned int depth=0; depth<
MAX_DEPTH; depth++){
316 if(iter->second.depth != depth)
continue;
317 if(iter->first ==
"HDDM_t")
continue;
318 ofs <<
"#include \"" << iter->first <<
".h\"" << endl;
321 ofs <<
"#undef Particle_t" << endl;
325 ofs <<
"#include <HDDM/hddm_"<<
HDDM_CLASS<<
".hpp>"<<endl;
326 ofs <<
"using namespace hddm_"<<
HDDM_CLASS<<
";"<<endl;
331 string name = iter->first;
332 string varname = name.substr(0, name.length()-2);
335 if(varname ==
"HDDM")
continue;
337 ofs <<
"void Copy"<<name_hddm<<
"("<<name<<
" &"<<varname<<
", class "<<name_hddm<<
" &"<<varname<<
"_hddm, bool hddm_invalid=false);"<<endl;
343 string name = iter->first;
344 string varname = name.substr(0, name.length()-2);
347 if(varname ==
"HDDM")
continue;
349 ofs <<
"void Clear"<<name_hddm<<
"("<<name<<
" &"<<varname<<
");"<<endl;
356 cout <<
"Writing hddm_root_generated/hddm_root_CopyRoutines.cc" << endl;
357 ofs.open(
"hddm_root_generated/hddm_root_CopyRoutines.cc");
361 ofs <<
"// Auto-generated HDDM to ROOT copy routines DO NOT EDIT" << endl;
363 ofs <<
"// "<<ctime(&t);
367 ofs <<
"#include \"hddm_root_CopyRoutines.h\"" << endl;
373 string name = iter->first;
374 string varname = name.substr(0, name.length()-2);
376 string name_hddm_plural =
HDDMPlural(name_hddm);
377 map<string, string> &members = iter->second.members;
379 if(varname ==
"HDDM")
continue;
381 ofs <<
"void Copy"<<name_hddm<<
"("<<name<<
" &"<<varname<<
", class "<<name_hddm<<
" &"<<varname<<
"_hddm, bool hddm_invalid)"<<endl;
383 ofs <<
" if(hddm_invalid)return; // FIXME!!!" << endl;
386 map<string, string>::iterator iter_members;
387 for(iter_members=members.begin(); iter_members!=members.end(); iter_members++){
388 string myname = iter_members->first;
389 string mytype = iter_members->second;
390 string myvarname = myname;
396 || mytype ==
"Particle_t"
397 || mytype ==
"string"){
400 ofs <<
" " << varname<<
"."<<myvarname<<
" = "<<varname<<
"_hddm.get"<<myname_hddm<<
"();" << endl;
401 }
else if(mytype.find(
"vector<") == 0){
403 mytype = myname.substr(0, myname.length()-1);
405 string myname_hddm_plural =
HDDMPlural(mytype);
406 string iter_name =
"iter_" + mytype;
409 ofs <<
" "<<myname_hddm<<
"List &"<<myname_hddm_plural<<
" = "<<varname<<
"_hddm.get"<<
HDDMPlural(myname_hddm)<<
"();" <<endl;
410 ofs <<
" "<<myname_hddm<<
"List::iterator "<<iter_name<<
";"<<endl;
411 ofs <<
" for("<<iter_name<<
"="<<myname_hddm_plural<<
".begin(); "<<iter_name<<
"!="<<myname_hddm_plural<<
".end(); "<<iter_name<<
"++){"<<endl;
412 ofs <<
" "<<mytype<<
"_t a;"<<endl;
413 ofs <<
" Copy"<<myname_hddm<<
"(a, *"<<iter_name<<
");"<<endl;
414 ofs <<
" "<<varname<<
"."<<myname<<
".push_back(a);"<<endl;
418 string myname_hddm_plural =
HDDMPlural(myname_hddm);
419 if(myname_hddm_plural ==
"Properties") myname_hddm_plural =
"PropertiesList";
420 ofs <<
" Copy"<<myname_hddm<<
"("<<varname<<
"."<<myvarname<<
", "<<varname<<
"_hddm.get"<<myname_hddm<<
"(), "<<varname<<
"_hddm.get"<< myname_hddm_plural<<
"().empty());" << endl;
432 string name = iter->first;
433 string varname = name.substr(0, name.length()-2);
435 string name_hddm_plural =
HDDMPlural(name_hddm);
436 map<string, string> &members = iter->second.members;
438 if(varname ==
"HDDM")
continue;
440 ofs <<
"void Clear"<<name_hddm<<
"("<<name<<
" &"<<varname<<
")"<<endl;
444 map<string, string>::iterator iter_members;
445 for(iter_members=members.begin(); iter_members!=members.end(); iter_members++){
446 string myname = iter_members->first;
447 string mytype = iter_members->second;
448 string myvarname = myname;
451 if(mytype ==
"int" || mytype ==
"Particle_t"){
452 ofs <<
" " << varname<<
"."<<myvarname<<
" = 0;" << endl;
453 }
else if(mytype ==
"float"){
454 ofs <<
" " << varname<<
"."<<myvarname<<
" = 0.0;" << endl;
455 }
else if(mytype ==
"string"){
456 ofs <<
" " << varname<<
"."<<myvarname<<
" = \"\";" << endl;
457 }
else if(mytype ==
"bool"){
458 ofs <<
" " << varname<<
"."<<myvarname<<
" = false;" << endl;
459 }
else if(mytype.find(
"vector<") == 0){
460 ofs <<
" " << varname<<
"."<<myname<<
".clear();"<< endl;
463 string myname_hddm_plural =
HDDMPlural(myname_hddm);
464 if(myname_hddm_plural ==
"Properties") myname_hddm_plural =
"PropertiesList";
465 ofs <<
" Clear"<<myname_hddm<<
"("<<varname<<
"."<<myvarname<<
");" << endl;
485 string fname =
string(
"hddm_root_generated/hddm2root_") +
HDDM_CLASS +
".cc";
486 ofstream ofs(fname.c_str());
487 cout <<
"Writing " << fname << endl;
490 time_t t = time(NULL);
492 ofs <<
"// Auto-generated HDDM to ROOT converion tool for class " <<
HDDM_CLASS << endl;
494 ofs <<
"// "<<ctime(&t);
501 ofs <<
"#include <stdlib.h>" << endl;
502 ofs <<
"#include <fstream>" << endl;
503 ofs <<
"#include <string>" << endl;
504 ofs <<
"#include <TTree.h>" << endl;
505 ofs <<
"#include <TFile.h>" << endl;
506 ofs <<
"using namespace std;" << endl;
508 ofs <<
"#include \"hddm_root_CopyRoutines.h\"" << endl;
513 ofs <<
"int main(int narg, char *argv[])" << endl;
516 ofs <<
" string usage = \"Usage:\\n\\n hddm2root_"<<
HDDM_CLASS<<
" [-n nevents] [-o outfile.root] file.{xml|hddm}\";" << endl;
518 ofs <<
" if(narg<2){cout << endl << usage << endl << endl; return -1;}"<<endl;
520 ofs <<
" // Parse command line arguments" << endl;
521 ofs <<
" int MAX_EVENTS = 0;"<<endl;
522 ofs <<
" string ofname=\"hddm2root_" <<
HDDM_CLASS <<
".root\";"<<endl;
523 ofs <<
" string fname=\"hdgeant_smeared.hddm\";"<<endl;
524 ofs <<
" for(int i=1; i<narg; i++){" << endl;
525 ofs <<
" string arg = argv[i];" << endl;
526 ofs <<
" if(arg==\"-n\"){" << endl;
527 ofs <<
" if(++i<narg){" << endl;
528 ofs <<
" MAX_EVENTS = atoi(argv[i]);" << endl;
529 ofs <<
" }else{" << endl;
530 ofs <<
" cerr<<\"-n option requires an argument!\"<<endl;" << endl;
531 ofs <<
" return -1;" << endl;
533 ofs <<
" }else if(arg==\"-o\"){" << endl;
534 ofs <<
" if(++i<narg){" << endl;
535 ofs <<
" ofname = argv[i];" << endl;
536 ofs <<
" }else{" << endl;
537 ofs <<
" cerr<<\"-o option requires an argument!\"<<endl;" << endl;
538 ofs <<
" return -2;" << endl;
540 ofs <<
" }else if(arg==\"-h\"){" << endl;
541 ofs <<
" cout << endl << usage << endl << endl;" << endl;
542 ofs <<
" return 0;" << endl;
543 ofs <<
" }else{" << endl;
544 ofs <<
" fname = argv[i];" << endl;
548 ofs <<
" TFile *f = new TFile(ofname.c_str(), \"RECREATE\");" << endl;
549 ofs <<
" TTree *t = new TTree(\"T\", \"A Tree\", 99);" << endl;
553 char branchname[2] =
"A";
554 map<string, DClassDef>::iterator iter;
557 string name = iter->first;
558 string varname = name.substr(0, name.length()-2);
560 ofs <<
" " << name <<
" *"<<varname <<
" = new " << name <<
"();" << endl;
561 ofs <<
" t->Branch(\""<<branchname<<
"\", &"<<varname<<
");"<<endl;
566 ofs <<
" // Open hddm file for reading" << endl;
567 ofs <<
" ifstream ifs(fname.c_str());" << endl;
569 ofs <<
" // Associate input file stream with HDDM record" << endl;
570 ofs <<
" hddm_"<<
HDDM_CLASS<<
"::istream istr(ifs);" << endl;
572 ofs <<
" // Loop over events" << endl;
573 ofs <<
" unsigned int N = 0;"<<endl;
574 ofs <<
" while(!ifs.eof()){" << endl;
575 ofs <<
" try{" << endl;
576 ofs <<
" HDDM xrec;" << endl;
577 ofs <<
" istr >> xrec;"<<endl;
582 string name = iter->first;
583 string varname = name.substr(0, name.length()-2);
586 ofs <<
" Clear" << name_hddm <<
"(*"<<varname<<
");"<<endl;
587 ofs <<
" Copy" << name_hddm <<
"(*"<<varname<<
", xrec.get"<<name_hddm<<
"());"<<endl;
590 ofs <<
" t->Fill();" << endl;
591 ofs <<
" if(++N%10 == 0){cout<<\" \"<<N<<\" events processed \\r\"; cout.flush();}"<<endl;
592 ofs <<
" if(MAX_EVENTS>0 && N>=MAX_EVENTS)break;"<<endl;
593 ofs <<
" }catch(...){" << endl;
594 ofs <<
" break;" << endl;
598 ofs <<
" f->Write();" << endl;
599 ofs <<
" f->Close();" << endl;
600 ofs <<
" delete f;" << endl;
602 ofs <<
" cout<<endl<<N<<\" events processed total\"<<endl;" << endl;
603 ofs <<
" return 0;" << endl;
617 string name_hddm = name;
618 name_hddm[0] = toupper(name[0]);
630 if(name_hddm.size()<3)
return name_hddm +
"s";
632 if(name_hddm.substr(name_hddm.length()-2, 2) ==
"ex"){
633 name_hddm.erase(name_hddm.length()-2);
635 }
else if(name_hddm.substr(name_hddm.length()-4, 4) ==
"ties"){
637 }
else if(name_hddm.substr(name_hddm.length()-2, 2) ==
"ty"){
638 name_hddm.erase(name_hddm.length()-2);
640 }
else if(name_hddm.substr(name_hddm.length()-3, 3) ==
"tum"){
641 name_hddm.erase(name_hddm.length()-3);
643 }
else if(name_hddm.substr(name_hddm.length()-1, 1) ==
"s"){
659 cout<<
"Usage:"<<endl;
660 cout<<
" hddm2root [-depth d] filename"<<endl;
662 cout<<
" Generate a tool for converting an HDDM formatted"<<endl;
663 cout<<
"file into a ROOT file. This does not convert the"<<endl;
664 cout<<
"file itself, but rather, generates a program than"<<endl;
665 cout<<
"can be used to convert a file."<<endl;
667 cout<<
" The file specified by \"filename\" can be either"<<endl;
668 cout<<
"the original XML file, or an existing HDDM file."<<endl;
669 cout<<
"If the latter is used, the XML is extracted from"<<endl;
670 cout<<
"beginning of the file."<<endl;
672 cout<<
" options:"<<endl;
673 cout<<
" -depth d Set the target depth for objects to"<<endl;
674 cout<<
" be written to the ROOT file"<<endl;
676 cout<<
" -h Print this Usage statement"<<endl;
679 cout<<
"There are several limitations to this system:"<<endl;
681 cout<<
"1. ROOT does not allow nested containers more"<<endl;
682 cout<<
" than a few levels deep. In other words, you can"<<endl;
683 cout<<
" have a container of containers, but not a"<<endl;
684 cout<<
" container of containers of containers .... For"<<endl;
685 cout<<
" practical purposes, this means any tag in "<<endl;
686 cout<<
" XML with more than 2 parents having maxOccurs"<<endl;
687 cout<<
" set to \"unbounded\" will not be accessible in"<<endl;
688 cout<<
" the file. Use the -depth d option to try and"<<endl;
689 cout<<
" get around this."<<endl;
691 cout<<
"2. All tags with a maxOccurs=1 will be treated"<<endl;
692 cout<<
" as though a single object of that type exists."<<endl;
693 cout<<
" This means that the if there are zero objects"<<endl;
694 cout<<
" of that type in the event, values will be written"<<endl;
695 cout<<
" anyway, not saving any disk space. The values"<<endl;
696 cout<<
" will be filled with zeros and empty strings"<<endl;
697 cout<<
" (false for bool types)."<<endl;
699 cout<<
"3. Top-level objects can only have single objects."<<endl;
700 cout<<
" In other words, if you specify a depth where an"<<endl;
701 cout<<
" object at that depth is \"unbounded\", the tool"<<endl;
702 cout<<
" will not try and loop over all instances of the"<<endl;
703 cout<<
" object type, just the first may be taken."<<endl;
706 cout<<
" > hddm2root $HALLD_RECON_HOME/src/libraries/HDDM/rest.xml"<<endl;
707 cout<<
" > hddm2root_r file.hddm"<<endl;
720 for(
int i=1; i<narg; i++){
721 string arg = argv[i];
723 if(arg.find(
"-depth") != arg.npos){
725 cerr<<endl<<
" -depth requires and argument!"<<endl;
732 if(arg.find(
"-h") != arg.npos){
void CreateCopyRoutines(void)
void startElement(void *data, const char *el, const char **attr)
unsigned int TARGET_DEPTH
void CreateHDDM2ROOT_tool(void)
string HDDMPlural(string name_hddm)
void ParseCommandLineArguments(int &narg, char *argv[])
string NameToHDDMname(string name)
map< string, string > members
map< string, DClassDef > CLASSES
void endElement(void *data, const char *el)
void Usage(JApplication &app)
int main(int argc, char *argv[])