60 if (
gROOT->GetListOfGeometries() !=
nullptr)
61 gROOT->GetListOfGeometries()->Clear(
"nodelete");
67 if ((obj1 ==
nullptr) || (obj2 ==
nullptr))
88 cout <<
"DIFF " << obj_path <<
": branch '" << branch1->
GetName() <<
"' has different number of entries ("
92 cout <<
"DIFF " << obj_path <<
": branch '" << branch1->
GetName() <<
"' has different data size ("
100 cout <<
"DIFF " << obj_path <<
": branch '" << branch1->
GetName() <<
"' has different number of sub-branches ("
107 if (sub_branch2 ==
nullptr) {
108 cout <<
"DIFF " << obj_path <<
": branch '" << sub_branch1->
GetName() <<
"' is missing in the second file"
123 cout <<
"DIFF " << obj_path <<
": different number of entries (" << entry_count <<
" vs " << tree2->
GetEntries()
132 cout <<
"DIFF " << obj_path <<
": different number of branches (" << branch_count <<
" vs "
136 for (
Int_t i = 0;
i < branch_count;
i++) {
139 cout <<
"DIFF " << obj_path <<
": branch '" << branch1->
GetName() <<
"' is missing in the second file"
147 bool is_equal =
true;
148 for (
Int_t i = 0;
i < branch_count;
i++) {
154 cout <<
"OK " << obj_path <<
" (TTree): " << entry_count <<
" entries, same branch sizes ("
155 << tree1->
GetTotBytes() <<
" bytes uncompressed)" << endl;
159 for (
Long64_t entry = 0; entry < entry_count; entry++) {
162 for (
Int_t i = 0;
i < branch_count;
i++) {
168 for (
Int_t i = 0;
i < branch_count;
i++) {
175 if ((branch_el1 !=
nullptr) && (branch_el2 !=
nullptr) && (branch_el1->
GetObject() !=
nullptr)
179 cout <<
"DIFF " << obj_path <<
": branch '" << branch1->
GetName() <<
"' has different classes ("
185 cout <<
"DIFF " << obj_path <<
": branch '" << branch1->
GetName() <<
"' differs at entry " << entry
195 while ((leaf1 = (
TLeaf*)next_leaf()) !=
nullptr) {
197 if ((leaf2 ==
nullptr) || (leaf1->
GetLen() != leaf2->
GetLen())
202 cout <<
"DIFF " << obj_path <<
": leaf '" << branch1->
GetName() <<
"/" << leaf1->
GetName()
203 <<
"' differs at entry " << entry << endl;
210 cout <<
"OK " << obj_path <<
" (TTree): " << entry_count <<
" entries are identical" << endl;
217 bool is_equal =
true;
219 set<string> key_names1, key_names2;
222 while ((key = (
TKey*)next_key1()) !=
nullptr)
223 key_names1.insert(key->GetName());
225 while ((key = (
TKey*)next_key2()) !=
nullptr)
226 key_names2.insert(key->GetName());
228 for (
const string& key_name : key_names1)
229 if (key_names2.count(key_name) == 0) {
230 cout <<
"DIFF " << dir_path << key_name <<
": present only in the first file" << endl;
233 for (
const string& key_name : key_names2)
234 if (key_names1.count(key_name) == 0) {
235 cout <<
"DIFF " << dir_path << key_name <<
": present only in the second file" << endl;
239 for (
const string& key_name : key_names1) {
240 if (key_names2.count(key_name) == 0)
245 TString obj_path = dir_path + key_name;
248 cout <<
"DIFF " << obj_path <<
": different classes (" << key1->
GetClassName() <<
" vs "
257 if ((obj_class !=
nullptr) && obj_class->
InheritsFrom(
"TProcessID"))
267 obj_path +
"/", size_only))
269 }
else if (size_only) {
275 cout <<
"DIFF " << obj_path <<
" (" << key1->
GetClassName() <<
"): different size ("
276 << key1->
GetObjlen() <<
" vs " << key2->
GetObjlen() <<
" bytes uncompressed)" << endl;
279 }
else if (obj_class ==
nullptr) {
280 cout <<
"WARN " << obj_path <<
": unknown class " << key1->
GetClassName() <<
", the key is skipped" << endl;
287 cout <<
"OK " << obj_path <<
" (" << key1->
GetClassName() <<
")" << endl;
289 cout <<
"DIFF " << obj_path <<
" (" << key1->
GetClassName() <<
"): content differs" << endl;
339 if ((obj ==
nullptr) || (obj_class ==
nullptr)) {
357 map<string, TBranch*> sub_branches;
361 sub_branches[sub_branch->
GetName()] = sub_branch;
364 for (
const auto& sub_branch : sub_branches)
375 map<string, TBranch*> branches;
379 branches[branch->
GetName()] = branch;
385 for (
const auto& branch : branches)
390 for (
Long64_t entry = 0; entry < entry_count; entry++) {
393 for (
const auto& branch : branches)
394 branch.second->GetEntry(entry);
396 for (
const auto& branch : branches) {
397 HashText(digest, branch.first.c_str());
401 if ((branch_el !=
nullptr) && (branch_el->
GetObject() !=
nullptr)) {
408 TIter next_leaf(branch.second->GetListOfLeaves());
410 while ((leaf = (
TLeaf*)next_leaf()) !=
nullptr) {
425 set<string> key_names;
428 while ((key = (
TKey*)next_key()) !=
nullptr)
429 key_names.insert(key->GetName());
431 for (
const string& key_name : key_names) {
432 TKey* dir_key = dir->
GetKey(key_name.c_str());
433 TString obj_path = dir_path + key_name;
437 if ((obj_class !=
nullptr) && obj_class->
InheritsFrom(
"TProcessID"))
442 if ((obj_class ==
nullptr) && !size_only) {
443 cout <<
"WARN " << obj_path <<
": unknown class " << dir_key->
GetClassName() <<
", the key is not hashed"
473 gSystem->ExpandPathName(root_file_path);
475 if (
gSystem->AccessPathName(root_file_path.
Data())) {
476 cerr <<
"Error: file does not exist or is not accessible: " << root_file_path << endl;
481 if ((root_file ==
nullptr) || root_file->
IsZombie()) {
482 cerr <<
"Error: could not open ROOT file: " << root_file_path << endl;
491 HashText(digest, size_only ?
"size-only" :
"content");
496 cout << hash <<
" " << root_file_path << (size_only ?
" (sizes only)" :
" (data content)") << endl;
507 gSystem->ExpandPathName(root_file_path1);
508 gSystem->ExpandPathName(root_file_path2);
511 if (
gSystem->AccessPathName(root_file_path1.
Data())) {
512 cerr <<
"Error: file does not exist or is not accessible: " << root_file_path1 << endl;
515 if (
gSystem->AccessPathName(root_file_path2.
Data())) {
516 cerr <<
"Error: file does not exist or is not accessible: " << root_file_path2 << endl;
521 if ((root_file1 ==
nullptr) || root_file1->
IsZombie()) {
522 cerr <<
"Error: could not open ROOT file: " << root_file_path1 << endl;
526 if ((root_file2 ==
nullptr) || root_file2->
IsZombie()) {
527 cerr <<
"Error: could not open ROOT file: " << root_file_path2 << endl;
539 cout <<
"The files are IDENTICAL ("
540 << (size_only ?
"by entry counts and data sizes only" :
"data content, ignoring metadata") <<
")" << endl;
542 cout <<
"The files are DIFFERENT" << endl;
R__EXTERN TGeoManager * gGeoManager
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
const char * GetClassName() const override
virtual TLeaf * GetLeaf(const char *name) const
TObjArray * GetListOfBranches()
virtual Int_t GetEntry(Long64_t entry=0, Int_t getall=0)
Long64_t GetEntries() const
Long64_t GetTotBytes(Option_t *option="") const
TObjArray * GetListOfLeaves()
void Destructor(ObjectPtr obj, Bool_t dtorOnly=kFALSE)
static TClass * GetClass(Bool_t load=kTRUE, Bool_t silent=kFALSE)
Bool_t InheritsFrom(const char *cl) const override
void Streamer(TBuffer &) override
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
virtual TKey * GetKey(const char *, Short_t=9999) const
virtual TList * GetListOfKeys() const
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
void Close(Option_t *option="") override
static void AddDirectory(Bool_t add=kTRUE)
virtual const char * GetClassName() const
virtual void * ReadObjectAny(const TClass *expectedClass)
virtual TObject * ReadObj()
virtual void * GetValuePointer() const
virtual Int_t GetLenType() const
virtual Int_t GetLen() const
const char * AsString() const
void Update(const UChar_t *buf, UInt_t len)
const char * GetName() const override
Int_t GetEntries() const override
TObject * At(Int_t idx) const override
TObject * FindObject(const char *name) const override
R__ALWAYS_INLINE Bool_t IsZombie() const
const char * Data() const
virtual TBranch * GetBranch(const char *name)
virtual Long64_t GetEntries() const
virtual Long64_t GetTotBytes() const
virtual TObjArray * GetListOfBranches()
void HashBlock(TMD5 &digest, const void *data, Int_t length)
bool CompareBranchSizes(TBranch *branch1, TBranch *branch2, const TString &obj_path)
void HashText(TMD5 &digest, const char *text)
void HashDirectory(TMD5 &digest, TDirectory *dir, const TString &dir_path, bool size_only)
static const char * hash_scheme_tag
void HashNumber(TMD5 &digest, Long64_t number)
void compare_files(TString root_file_path1, TString root_file_path2, Bool_t size_only=kFALSE)
void HashBranchSizes(TMD5 &digest, TBranch *branch)
TString hash_file(TString root_file_path, Bool_t size_only=kFALSE)
void HashTree(TMD5 &digest, TTree *tree, bool size_only)
bool CompareDirectories(TDirectory *dir1, TDirectory *dir2, const TString &dir_path, bool size_only)
bool CompareTrees(TTree *tree1, TTree *tree2, const TString &obj_path, bool size_only)
void HashObject(TMD5 &digest, void *obj, TClass *obj_class)
bool AreObjectsEqual(void *obj1, void *obj2, TClass *obj_class)