51 const UInt_t kIsBigFile = BIT(16);
52 const Int_t kMaxLen = 2048;
54 ClassImp(TDirectoryFile);
60 TDirectoryFile::TDirectoryFile()
80 TDirectoryFile::TDirectoryFile(
const char *name,
const char *title, Option_t *classname, TDirectory* initMotherDir)
88 R__LOCKGUARD(gROOTMutex);
93 if (!initMotherDir) initMotherDir = gDirectory;
95 if (strchr(name,
'/')) {
96 ::Error(
"TDirectoryFile",
"directory name (%s) cannot contain a slash", name);
100 if (strlen(GetName()) == 0) {
101 ::Error(
"TDirectoryFile",
"directory name cannot be \"\"");
102 gDirectory =
nullptr;
106 BuildDirectoryFile(initMotherDir ? initMotherDir->GetFile() :
nullptr, initMotherDir);
108 TDirectory* motherdir = GetMotherDir();
109 TFile* f = TDirectoryFile::GetFile();
111 if (!motherdir || !f)
return;
112 if (!f->IsWritable())
return;
113 if (motherdir->GetKey(name)) {
114 Error(
"TDirectoryFile",
"An object with name %s exists already", name);
117 TClass *cl =
nullptr;
119 cl = TClass::GetClass(classname);
121 Error(
"TDirectoryFile",
"Invalid class name: %s",classname);
125 cl = TDirectoryFile::IsA();
131 InitDirectoryFile(cl);
137 gROOT->GetUUIDs()->AddUUID(fUUID,
this);
147 void TDirectoryFile::InitDirectoryFile(TClass *cl)
149 TFile* f = GetFile();
154 TDirectory* motherdir = GetMotherDir();
155 fSeekParent = f->GetSeekDir();
156 Int_t nbytes = TDirectoryFile::Sizeof();
157 TKey *key =
new TKey(fName,fTitle,cl,nbytes,motherdir);
158 fNbytesName = key->GetKeylen();
159 fSeekDir = key->GetSeekKey();
160 if (fSeekDir == 0)
return;
161 char *buffer = key->GetBuffer();
162 TDirectoryFile::FillBuffer(buffer);
163 Int_t cycle = motherdir ? motherdir->AppendKey(key) : 0;
164 key->WriteFile(cycle);
168 fSeekDir = f->DirCreateEntry(
this);
169 if (fSeekDir == 0)
return;
177 TDirectoryFile::~TDirectoryFile()
180 fKeys->Delete(
"slow");
184 TDirectoryFile::CleanTargets();
194 fList->Delete(
"slow");
199 Info(
"~TDirectoryFile",
"dtor called for %s", GetName());
209 void TDirectoryFile::Append(TObject *obj, Bool_t replace )
211 if (!obj || !fList)
return;
213 TDirectory::Append(obj,replace);
215 if (!fMother)
return;
216 if (fMother->IsA() == TMapFile::Class()) {
217 TMapFile *mfile = (TMapFile*)fMother;
225 Int_t TDirectoryFile::AppendKey(TKey *key)
228 Error(
"AppendKey",
"TDirectoryFile not initialized yet.");
234 key->SetMotherDir(
this);
237 TKey *oldkey = (TKey*)fKeys->FindObject(key->GetName());
245 TObjLink *lnk = fKeys->FirstLink();
247 oldkey = (TKey*)lnk->GetObject();
248 if (!strcmp(oldkey->GetName(), key->GetName()))
253 fKeys->AddBefore(lnk, key);
254 return oldkey->GetCycle() + 1;
260 void TDirectoryFile::Browse(TBrowser *b)
265 TObject *obj =
nullptr;
267 TKey *key =
nullptr, *keyo =
nullptr;
273 while ((obj = nextin())) {
274 if (fKeys->FindObject(obj->GetName()))
continue;
275 b->Add(obj, obj->GetName());
279 while ((key = (TKey *) next())) {
281 if (!keyo || (keyo && strcmp(keyo->GetName(), key->GetName()))) {
283 obj = fList->FindObject(key->GetName());
286 b->Add(obj, obj->GetName());
287 if (obj->IsFolder() && !obj->InheritsFrom(
"TTree"))
293 name.Form(
"%s;%d", key->GetName(), key->GetCycle());
305 void TDirectoryFile::BuildDirectoryFile(TFile* motherFile, TDirectory* motherDir)
311 if (motherDir && strlen(GetName()) != 0) motherDir->Append(
this);
321 fList =
new THashList(100,50);
322 fKeys =
new THashList(100,50);
325 fFile = motherFile ? motherFile : TFile::CurrentFile();
340 Bool_t TDirectoryFile::cd(
const char *path)
342 Bool_t ok = TDirectory::cd(path);
343 if (ok) TFile::CurrentFile() = fFile;
350 void TDirectoryFile::CleanTargets()
358 TDirectory::CleanTargets();
373 TObject *TDirectoryFile::CloneObject(
const TObject *obj, Bool_t autoadd )
376 char *pobj = (
char*)obj->IsA()->New();
377 if (!pobj)
return nullptr;
379 Int_t baseOffset = obj->IsA()->GetBaseClassOffset(TObject::Class());
380 if (baseOffset==-1) {
384 Fatal(
"CloneObject",
"Incorrect detection of the inheritance from TObject for class %s.\n",
385 obj->IsA()->GetName());
387 TObject *newobj = (TObject*)(pobj+baseOffset);
394 TFile *filsav = gFile;
396 const Int_t bufsize = 10000;
397 TBufferFile buffer(TBuffer::kWrite,bufsize);
398 buffer.MapObject(obj);
400 Bool_t isRef = obj->TestBit(kIsReferenced);
401 ((TObject*)obj)->ResetBit(kIsReferenced);
403 ((TObject*)obj)->Streamer(buffer);
405 if (isRef) ((TObject*)obj)->SetBit(kIsReferenced);
409 buffer.SetReadMode();
411 buffer.SetBufferOffset(0);
412 buffer.MapObject(newobj);
413 newobj->Streamer(buffer);
414 newobj->ResetBit(kIsReferenced);
415 newobj->ResetBit(kCanDelete);
420 ROOT::DirAutoAdd_t func = obj->IsA()->GetDirectoryAutoAdd();
431 TObject *TDirectoryFile::FindObjectAnyFile(
const char *name)
const
434 R__LOCKGUARD(gROOTMutex);
435 TIter next(gROOT->GetListOfFiles());
436 while ((f = (TFile*)next())) {
437 TObject *obj = f->GetList()->FindObject(name);
458 TDirectory *TDirectoryFile::GetDirectory(
const char *apath,
459 Bool_t printError,
const char *funcname)
462 if (apath) nch = strlen(apath);
467 if (funcname==0 || strlen(funcname)==0) funcname =
"GetDirectory";
469 TDirectory *result =
this;
471 char *path =
new char[nch+1]; path[0] = 0;
472 if (nch) strlcpy(path,apath,nch+1);
473 char *s = (
char*)strchr(path,
':');
476 R__LOCKGUARD(gROOTMutex);
477 TDirectory *f = (TDirectory *)gROOT->GetListOfFiles()->FindObject(path);
481 auto url = GetFile()->GetEndpointUrl();
482 if (f && 0 == url->Compare(f->GetFile()->GetEndpointUrl()))
483 return GetDirectory(s+1,printError,funcname);
485 if (!f && !strcmp(gROOT->GetName(), path)) f = gROOT;
489 if (s && *(s+1)) result = f->GetDirectory(s+1,printError,funcname);
490 delete [] path;
return result;
492 if (printError) Error(funcname,
"No such file %s", path);
493 delete [] path;
return nullptr;
498 if (path[0] ==
'/') {
499 TDirectory *td = fFile;
500 if (!fFile) td = gROOT;
501 result = td->GetDirectory(path+1,printError,funcname);
502 delete [] path;
return result;
506 char *slash = (
char*)strchr(path,
'/');
508 if (!strcmp(path,
"..")) {
509 result = GetMotherDir();
510 delete [] path;
return result;
514 if (printError) Error(funcname,
"Unknown directory %s", path);
515 delete [] path;
return nullptr;
518 delete [] path;
return obj;
521 TString subdir(path);
522 slash = (
char*)strchr(subdir.Data(),
'/');
525 if (!strcmp(subdir,
"..")) {
526 TDirectory* mom = GetMotherDir();
528 result = mom->GetDirectory(slash+1,printError,funcname);
529 delete [] path;
return result;
531 GetObject(subdir,obj);
533 if (printError) Error(funcname,
"Unknown directory %s", subdir.Data());
534 delete [] path;
return nullptr;
537 result = ((TDirectory*)obj)->GetDirectory(slash+1,printError,funcname);
538 delete [] path;
return result;
544 void TDirectoryFile::Close(Option_t *option)
546 if (!fList || !fSeekDir) {
553 Bool_t nodelete = option ? (!strcmp(option,
"nodelete") ? kTRUE : kFALSE) : kFALSE;
557 TObjLink *lnk = fList->FirstLink();
559 if (lnk->GetObject()->IsA() == TDirectoryFile::Class()) {fast = kFALSE;
break;}
568 if (fast) fList->Delete();
569 else fList->Delete(
"slow");
575 fKeys->Delete(
"slow");
578 TDirectoryFile::CleanTargets();
615 void TDirectoryFile::Delete(
const char *namecycle)
618 Info(
"Delete",
"Call for this = %s namecycle = %s",
619 GetName(), (namecycle ? namecycle :
"null"));
621 TDirectory::TContext ctxt(
this);
624 const char *nmcy = (namecycle) ? namecycle :
"";
625 DecodeNameCycle(nmcy, name, cycle, kMaxLen);
628 Int_t deletetree = 0;
629 if(strcmp(name,
"*") == 0) deleteall = 1;
630 if(strcmp(name,
"*T") == 0){ deleteall = 1; deletetree = 1;}
631 if(strcmp(name,
"T*") == 0){ deleteall = 1; deletetree = 1;}
632 if(namecycle==0 || !namecycle[0]){ deleteall = 1; deletetree = 1;}
633 TRegexp re(name,kTRUE);
639 if (cycle >= 9999 ) {
642 while ((idcur = (TNamed *) next())) {
644 s = idcur->GetName();
645 if (deleteall || s.Index(re) != kNPOS) {
647 if (idcur->IsA() == TDirectoryFile::Class()) {
649 if (!deletetree && deleteall) deleteOK = 0;
653 fList->Remove(idcur);
657 ((TDirectory*) idcur)->ReadAll(
"dirs");
658 idcur->Delete(deletetree ?
"T*;*" :
"*");
671 if (cycle != 9999 ) {
674 TIter nextkey(GetListOfKeys());
675 while ((key = (TKey *) nextkey())) {
678 if (deleteall || s.Index(re) != kNPOS) {
679 if (cycle == key->GetCycle()) deleteOK = 1;
680 if (cycle > 9999) deleteOK = 1;
682 if (strstr(key->GetClassName(),
"TDirectory")) {
684 if (!deletetree && deleteall) deleteOK = 0;
685 if (cycle == key->GetCycle()) deleteOK = 2;
691 TDirectory* dir = GetDirectory(key->GetName(), kTRUE,
"Delete");
705 TFile* f = GetFile();
706 if (fModified && (f!=0)) {
719 void TDirectoryFile::FillBuffer(
char *&buffer)
721 Version_t version = TDirectoryFile::Class_Version();
722 if (fSeekDir > TFile::kStartBigFile ||
723 fSeekParent > TFile::kStartBigFile ||
724 fSeekKeys > TFile::kStartBigFile )
732 tobuf(buffer, version);
733 const bool reproducible = TestBit(TFile::kReproducible) || (fFile && fFile->TestBit(TFile::kReproducible));
735 TDatime((UInt_t) 1).FillBuffer(buffer);
736 TDatime((UInt_t) 1).FillBuffer(buffer);
738 fDatimeC.FillBuffer(buffer);
739 fDatimeM.FillBuffer(buffer);
741 tobuf(buffer, fNbytesKeys);
742 tobuf(buffer, fNbytesName);
743 if (version > 1000) {
744 tobuf(buffer, fSeekDir);
745 tobuf(buffer, fSeekParent);
746 tobuf(buffer, fSeekKeys);
748 tobuf(buffer, (Int_t)fSeekDir);
749 tobuf(buffer, (Int_t)fSeekParent);
750 tobuf(buffer, (Int_t)fSeekKeys);
753 TUUID(
"00000000-0000-0000-0000-000000000000").FillBuffer(buffer);
755 fUUID.FillBuffer(buffer);
756 if (fFile && fFile->GetVersion() < 40000)
return;
757 if (version <=1000)
for (Int_t i=0;i<3;i++) tobuf(buffer,Int_t(0));
763 TKey *TDirectoryFile::FindKey(
const char *keyname)
const
768 DecodeNameCycle(keyname, name, cycle, kMaxLen);
769 return GetKey(name,cycle);
779 TKey *TDirectoryFile::FindKeyAny(
const char *keyname)
const
781 TDirectory *dirsav = gDirectory;
785 DecodeNameCycle(keyname, name, cycle, kMaxLen);
787 TIter next(GetListOfKeys());
789 while ((key = (TKey *) next())) {
790 if (!strcmp(name, key->GetName()))
791 if ((cycle == 9999) || (cycle >= key->GetCycle())) {
792 const_cast<TDirectoryFile*
>(
this)->cd();
798 while ((key = (TKey *) next())) {
800 if (strstr(key->GetClassName(),
"TDirectory")) {
802 const_cast<TDirectoryFile*
>(
this)->GetDirectory(key->GetName(), kTRUE,
"FindKeyAny");
803 TKey *k = subdir ? subdir->FindKeyAny(keyname) :
nullptr;
807 if (dirsav) dirsav->cd();
819 TObject *TDirectoryFile::FindObjectAny(
const char *aname)
const
822 TObject *obj = TDirectory::FindObjectAny(aname);
825 TDirectory *dirsav = gDirectory;
829 DecodeNameCycle(aname, name, cycle, kMaxLen);
831 TIter next(GetListOfKeys());
834 while ((key = (TKey *) next())) {
835 if (!strcmp(name, key->GetName())) {
836 if (cycle == 9999)
return key->ReadObj();
837 if (cycle >= key->GetCycle())
return key->ReadObj();
842 while ((key = (TKey *) next())) {
844 if (strstr(key->GetClassName(),
"TDirectory")) {
846 ((TDirectory*)
this)->GetDirectory(key->GetName(), kTRUE,
"FindKeyAny");
847 TKey *k = subdir ? subdir->FindKeyAny(aname) :
nullptr;
848 if (k) {
if (dirsav) dirsav->cd();
return k->ReadObj();}
851 if (dirsav) dirsav->cd();
906 TObject *TDirectoryFile::Get(
const char *namecycle)
911 DecodeNameCycle(namecycle, name, cycle, kMaxLen);
912 Int_t nch = strlen(name);
913 for (Int_t i = nch-1; i > 0; i--) {
914 if (name[i] ==
'/') {
916 TDirectory* dirToSearch=GetDirectory(name);
917 const char *subnamecycle = namecycle + i + 1;
919 return dirToSearch?dirToSearch->Get(subnamecycle):0;
922 const char *namobj = name;
926 TObject *idcur = fList ? fList->FindObject(namobj) :
nullptr;
928 if (idcur==
this && strlen(namobj)!=0) {
933 }
else if (cycle == 9999) {
936 if (idcur->InheritsFrom(TCollection::Class()))
946 TIter nextkey(GetListOfKeys());
947 while ((key = (TKey *) nextkey())) {
948 if (strcmp(namobj,key->GetName()) == 0) {
949 if ((cycle == 9999) || (cycle == key->GetCycle())) {
950 TDirectory::TContext ctxt(
this);
951 idcur = key->ReadObj();
975 void *TDirectoryFile::GetObjectUnchecked(
const char *namecycle)
977 return GetObjectChecked(namecycle,(TClass*)
nullptr);
983 void *TDirectoryFile::GetObjectChecked(
const char *namecycle,
const char* classname)
985 return GetObjectChecked(namecycle,TClass::GetClass(classname));
1010 void *TDirectoryFile::GetObjectChecked(
const char *namecycle,
const TClass* expectedClass)
1014 if (!namecycle ||
'\0' == namecycle[0]) {
1015 Error(
"GetObjectChecked",
"The provided key name is invalid.");
1022 DecodeNameCycle(namecycle, name, cycle, kMaxLen);
1023 Int_t nch = strlen(name);
1024 for (Int_t i = nch-1; i > 0; i--) {
1025 if (name[i] ==
'/') {
1027 TDirectory* dirToSearch=GetDirectory(name);
1028 const char *subnamecycle = namecycle + i + 1;
1031 return dirToSearch->GetObjectChecked(subnamecycle, expectedClass);
1037 const char *namobj = name;
1041 if (expectedClass==0 || expectedClass->IsTObject()) {
1042 TObject *objcur = fList ? fList->FindObject(namobj) :
nullptr;
1044 if (objcur==
this && strlen(namobj)!=0) {
1049 }
else if (cycle == 9999) {
1051 if (expectedClass && objcur->IsA()->GetBaseClassOffset(expectedClass) == -1)
return nullptr;
1054 if (objcur->InheritsFrom(TCollection::Class()))
1064 void *idcur =
nullptr;
1066 TIter nextkey(GetListOfKeys());
1067 while ((key = (TKey *) nextkey())) {
1068 if (strcmp(namobj,key->GetName()) == 0) {
1069 if ((cycle == 9999) || (cycle == key->GetCycle())) {
1070 TDirectory::TContext ctxt(
this);
1071 idcur = key->ReadObjectAny(expectedClass);
1086 Int_t TDirectoryFile::GetBufferSize()
const
1088 if (fBufferSize <= 0)
return fFile->GetBestBuffer();
1089 else return fBufferSize;
1098 TKey *TDirectoryFile::GetKey(
const char *name, Short_t cycle)
const
1100 if (!fKeys)
return nullptr;
1103 TIter next( ((THashList *)(GetListOfKeys()))->GetListForObject(name) );
1106 while (( key = (TKey *)next() )) {
1107 if (!strcmp(name, key->GetName())) {
1108 if ((cycle == 9999) || (cycle >= key->GetCycle()))
1129 void TDirectoryFile::ls(Option_t *option)
const
1131 TROOT::IndentLevel();
1132 std::cout <<ClassName()<<
"*\t\t"<<GetName()<<
"\t"<<GetTitle()<<std::endl;
1133 TROOT::IncreaseDirLevel();
1135 TString opta = option;
1136 TString opt = opta.Strip(TString::kBoth);
1137 Bool_t memobj = kTRUE;
1138 Bool_t diskobj = kTRUE;
1140 if (opt.BeginsWith(
"-m")) {
1142 if (opt.Length() > 2)
1143 reg = opt(2,opt.Length());
1144 }
else if (opt.BeginsWith(
"-d")) {
1146 if (opt.Length() > 2)
1147 reg = opt(2,opt.Length());
1148 }
else if (!opt.IsNull())
1151 TRegexp re(reg, kTRUE);
1155 TIter nextobj(fList);
1156 while ((obj = (TObject *) nextobj())) {
1157 TString s = obj->GetName();
1158 if (s.Index(re) == kNPOS)
continue;
1165 TIter next(GetListOfKeys());
1166 while ((key = (TKey *) next())) {
1167 TString s = key->GetName();
1168 if (s.Index(re) == kNPOS)
continue;
1172 TROOT::DecreaseDirLevel();
1178 TFile *TDirectoryFile::OpenFile(
const char *name, Option_t *option,
const char *ftitle, Int_t compress, Int_t netopt)
1180 return TFile::Open(name,option,ftitle,compress,netopt);
1194 TDirectory *TDirectoryFile::mkdir(
const char *name,
const char *title, Bool_t returnExistingDirectory)
1196 if (!name || !title || !name[0])
return nullptr;
1197 if (!title[0]) title = name;
1199 if (returnExistingDirectory)
1200 return (TDirectoryFile*) GetDirectory(name);
1202 Error(
"mkdir",
"An object with name %s exists already",name);
1206 TDirectoryFile *newdir =
nullptr;
1207 if (
const char *slash = strchr(name,
'/')) {
1208 TString workname(name, Long_t(slash-name));
1209 TDirectoryFile *tmpdir =
nullptr;
1210 GetObject(workname.Data(), tmpdir);
1212 tmpdir = (TDirectoryFile*)mkdir(workname.Data(),title);
1213 if (!tmpdir)
return nullptr;
1215 if (!newdir) newdir = tmpdir;
1216 tmpdir->mkdir(slash+1);
1220 TDirectory::TContext ctxt(
this);
1222 newdir =
new TDirectoryFile(name, title,
"",
this);
1233 void TDirectoryFile::Purge(Short_t)
1235 if (!IsWritable())
return;
1237 TDirectory::TContext ctxt(
this);
1240 TIter prev(GetListOfKeys(), kIterBackward);
1242 while ((key = (TKey*)prev())) {
1243 TKey *keyprev = (TKey*)GetListOfKeys()->Before(key);
1244 if (!keyprev)
break;
1245 if (key->GetKeep() == 0) {
1246 if (strcmp(key->GetName(), keyprev->GetName()) == 0) {
1252 TFile *f = GetFile();
1253 if (fModified && f) {
1269 void TDirectoryFile::ReadAll(Option_t* opt)
1271 TDirectory::TContext ctxt(
this);
1274 TIter next(GetListOfKeys());
1276 Bool_t readdirs = ((opt!=0) && ((strcmp(opt,
"dirs")==0) || (strcmp(opt,
"dirs*")==0)));
1279 while ((key = (TKey *) next())) {
1282 if (strstr(key->GetClassName(),
"TDirectory")==0)
continue;
1284 TDirectory *dir = GetDirectory(key->GetName(), kTRUE,
"ReadAll");
1286 if ((dir!=0) && (strcmp(opt,
"dirs*")==0)) dir->ReadAll(
"dirs*");
1289 while ((key = (TKey *) next())) {
1290 TObject *thing = GetList()->FindObject(key->GetName());
1291 if (thing) {
delete thing; }
1322 Int_t TDirectoryFile::ReadKeys(Bool_t forceRead)
1324 if (!fFile || !fKeys)
return 0;
1326 if (!fFile->IsBinary())
1327 return fFile->DirReadKeys(
this);
1329 TDirectory::TContext ctxt(
this);
1336 Int_t nbytes = fNbytesName + TDirectoryFile::Sizeof();
1337 char *header =
new char[nbytes];
1339 fFile->Seek(fSeekDir);
1340 if ( fFile->ReadBuffer(buffer,nbytes) ) {
1345 buffer += fNbytesName;
1346 Version_t versiondir;
1347 frombuf(buffer,&versiondir);
1348 fDatimeC.ReadBuffer(buffer);
1349 fDatimeM.ReadBuffer(buffer);
1350 frombuf(buffer, &fNbytesKeys);
1351 frombuf(buffer, &fNbytesName);
1352 if (versiondir > 1000) {
1353 frombuf(buffer, &fSeekDir);
1354 frombuf(buffer, &fSeekParent);
1355 frombuf(buffer, &fSeekKeys);
1357 Int_t sdir,sparent,skeys;
1358 frombuf(buffer, &sdir); fSeekDir = (Long64_t)sdir;
1359 frombuf(buffer, &sparent); fSeekParent = (Long64_t)sparent;
1360 frombuf(buffer, &skeys); fSeekKeys = (Long64_t)skeys;
1366 Long64_t fsize = fFile->GetSize();
1367 if ( fSeekKeys > 0) {
1368 TKey *headerkey =
new TKey(fSeekKeys, fNbytesKeys,
this);
1369 headerkey->ReadFile();
1370 buffer = headerkey->GetBuffer();
1371 headerkey->ReadKeyBuffer(buffer);
1374 frombuf(buffer, &nkeys);
1375 for (Int_t i = 0; i < nkeys; i++) {
1376 key =
new TKey(
this);
1377 key->ReadKeyBuffer(buffer);
1378 if (key->GetSeekKey() < 64 || key->GetSeekKey() > fsize) {
1379 Error(
"ReadKeys",
"reading illegal key, exiting after %d keys",i);
1384 if (key->GetSeekPdir() < 64 || key->GetSeekPdir() > fsize) {
1385 Error(
"ReadKeys",
"reading illegal key, exiting after %d keys",i);
1408 Int_t TDirectoryFile::ReadTObject(TObject *obj,
const char *keyname)
1410 if (!fFile) { Error(
"Read",
"No file open");
return 0; }
1411 TKey *key =
nullptr;
1412 TIter nextkey(GetListOfKeys());
1413 while ((key = (TKey *) nextkey())) {
1414 if (strcmp(keyname,key->GetName()) == 0) {
1415 return key->Read(obj);
1418 Error(
"Read",
"Key not found");
1430 void TDirectoryFile::ResetAfterMerge(TFileMergeInfo *info)
1445 TKey *key = fKeys ? (TKey*)fKeys->FindObject(fName) :
nullptr;
1448 cl = TClass::GetClass(key->GetClassName());
1453 fKeys->Delete(
"slow");
1456 InitDirectoryFile(cl);
1459 TIter next(GetList());
1461 while ((idcur = next())) {
1462 if (idcur->IsA() == TDirectoryFile::Class()) {
1463 ((TDirectoryFile*)idcur)->ResetAfterMerge(info);
1476 void TDirectoryFile::rmdir(
const char *name)
1478 if (!name || (*name==0))
return;
1488 void TDirectoryFile::Save()
1490 TDirectory::TContext ctxt(
this);
1495 if (fList && fList->FirstLink()) {
1496 auto lnk = fList->FirstLink()->shared_from_this();
1498 TObject *idcur = lnk->GetObject();
1499 if (idcur && idcur->InheritsFrom(TDirectoryFile::Class())) {
1500 TDirectoryFile *dir = (TDirectoryFile *)idcur;
1503 lnk = lnk->NextSP();
1521 Int_t TDirectoryFile::SaveObjectAs(
const TObject *obj,
const char *filename, Option_t *option)
const
1524 TDirectory *dirsav = gDirectory;
1525 TString fname = filename;
1526 if (!filename || !filename[0]) {
1527 fname.Form(
"%s.root",obj->GetName());
1530 if (fname.Index(
".json") > 0) {
1531 nbytes = TBufferJSON::ExportToFile(fname, obj, option);
1533 TFile *local = TFile::Open(fname.Data(),
"recreate");
1534 if (!local)
return 0;
1535 nbytes = obj->Write();
1537 if (dirsav) dirsav->cd();
1539 TString opt = option;
1541 if (!opt.Contains(
"q")) {
1542 if (!gSystem->AccessPathName(fname.Data())) obj->Info(
"SaveAs",
"ROOT file %s has been created", fname.Data());
1562 void TDirectoryFile::SaveSelf(Bool_t force)
1564 if (IsWritable() && (fModified || force) && fFile) {
1565 Bool_t dowrite = kTRUE;
1566 if (fFile->GetListOfFree())
1567 dowrite = fFile->GetListOfFree()->First() !=
nullptr;
1569 TDirectory *dirsav = gDirectory;
1570 if (dirsav !=
this) cd();
1573 if (dirsav && dirsav !=
this) dirsav->cd();
1583 void TDirectoryFile::SetBufferSize(Int_t bufsize)
1585 fBufferSize = bufsize;
1598 void TDirectoryFile::SetTRefAction(TObject *ref, TObject *parent)
1600 Int_t offset = (
char*)ref - (
char*)parent;
1601 TClass *cl = parent->IsA();
1602 cl->BuildRealData(parent);
1603 TStreamerInfo *info = (TStreamerInfo*)cl->GetStreamerInfo();
1604 TIter next(info->GetElements());
1605 TStreamerElement *element;
1606 while((element = (TStreamerElement*)next())) {
1607 if (element->GetOffset() != offset)
continue;
1608 Int_t execid = element->GetExecID();
1609 if (execid > 0) ref->SetBit(execid << 8);
1617 void TDirectoryFile::SetWritable(Bool_t writable)
1619 TDirectory::TContext ctxt(
this);
1621 fWritable = writable;
1627 while ((idcur = next())) {
1628 if (idcur->InheritsFrom(TDirectoryFile::Class())) {
1629 TDirectoryFile *dir = (TDirectoryFile*)idcur;
1630 dir->SetWritable(writable);
1640 Int_t TDirectoryFile::Sizeof()
const
1644 nbytes += fDatimeC.Sizeof();
1645 nbytes += fDatimeM.Sizeof();
1646 nbytes += fUUID.Sizeof();
1648 if (fFile && fFile->GetVersion() >= 40000) nbytes += 12;
1656 void TDirectoryFile::Streamer(TBuffer &b)
1658 Version_t v,version;
1659 if (b.IsReading()) {
1660 BuildDirectoryFile((TFile*)b.GetParent(),
nullptr);
1661 if (fFile && fFile->IsWritable()) fWritable = kTRUE;
1663 if (fFile && !fFile->IsBinary()) {
1664 Version_t R__v = b.ReadVersion(0, 0);
1666 TClass* dirclass = (R__v < 5) ? TDirectory::Class() : TDirectoryFile::Class();
1668 b.ClassBegin(dirclass, R__v);
1672 b.ClassMember(
"CreateTime",
"TString");
1674 TDatime timeC(sbuf.Data());
1677 b.ClassMember(
"ModifyTime",
"TString");
1679 TDatime timeM(sbuf.Data());
1682 b.ClassMember(
"UUID",
"TString");
1684 TUUID id(sbuf.Data());
1687 b.ClassEnd(dirclass);
1692 fDatimeC.Streamer(b);
1693 fDatimeM.Streamer(b);
1696 if (version > 1000) {
1702 Int_t sdir,sparent,skeys;
1703 b >> sdir; fSeekDir = (Long64_t)sdir;
1704 b >> sparent; fSeekParent = (Long64_t)sparent;
1705 b >> skeys; fSeekKeys = (Long64_t)skeys;
1709 fUUID.StreamerV1(b);
1715 R__LOCKGUARD(gROOTMutex);
1716 gROOT->GetUUIDs()->AddUUID(fUUID,
this);
1717 if (fSeekKeys) ReadKeys();
1719 if (fFile && !fFile->IsBinary()) {
1720 b.WriteVersion(TDirectoryFile::Class());
1724 b.ClassBegin(TDirectoryFile::Class());
1726 b.ClassMember(
"CreateTime",
"TString");
1727 sbuf = fDatimeC.AsSQLString();
1730 b.ClassMember(
"ModifyTime",
"TString");
1732 sbuf = fDatimeM.AsSQLString();
1735 b.ClassMember(
"UUID",
"TString");
1736 sbuf = fUUID.AsString();
1739 b.ClassEnd(TDirectoryFile::Class());
1741 version = TDirectoryFile::Class_Version();
1742 if (fFile && fFile->GetEND() > TFile::kStartBigFile) version += 1000;
1744 fDatimeC.Streamer(b);
1745 fDatimeM.Streamer(b);
1748 if (version > 1000) {
1753 b << (Int_t)fSeekDir;
1754 b << (Int_t)fSeekParent;
1755 b << (Int_t)fSeekKeys;
1758 if (version <=1000)
for (Int_t i=0;i<3;i++) b << Int_t(0);
1771 Int_t TDirectoryFile::Write(
const char *, Int_t opt, Int_t bufsize)
1773 if (!IsWritable())
return 0;
1774 TDirectory::TContext ctxt(
this);
1780 while ((obj=next())) {
1781 nbytes += obj->Write(0,opt,bufsize);
1791 Int_t TDirectoryFile::Write(
const char *n, Int_t opt, Int_t bufsize)
const
1793 Error(
"Write const",
"A const TDirectory object should not be saved. We try to proceed anyway.");
1794 return const_cast<TDirectoryFile*
>(
this)->Write(n, opt, bufsize);
1841 Int_t TDirectoryFile::WriteTObject(
const TObject *obj,
const char *name, Option_t *option, Int_t bufsize)
1843 TDirectory::TContext ctxt(
this);
1846 const char *objname =
"no name specified";
1847 if (name) objname = name;
1848 else if (obj) objname = obj->GetName();
1849 Error(
"WriteTObject",
"The current directory (%s) is not associated with a file. The object (%s) has not been written.",GetName(),objname);
1853 if (!fFile->IsWritable()) {
1854 if (!fFile->TestBit(TFile::kWriteError)) {
1856 Error(
"WriteTObject",
"Directory %s is not writable", fFile->GetName());
1863 TString opt = option;
1866 TKey *key=0, *oldkey=0;
1867 Int_t bsize = GetBufferSize();
1868 if (bufsize > 0) bsize = bufsize;
1874 oname = obj->GetName();
1877 Int_t nch = strlen(oname);
1878 char *newName =
nullptr;
1879 if (nch && oname[nch-1] ==
' ') {
1880 newName =
new char[nch+1];
1881 strlcpy(newName,oname,nch+1);
1882 for (Int_t i=0;i<nch;i++) {
1883 if (newName[nch-i-1] !=
' ')
break;
1884 newName[nch-i-1] = 0;
1889 if (opt.Contains(
"overwrite")) {
1892 key = GetKey(oname);
1898 if (opt.Contains(
"writedelete")) {
1899 oldkey = GetKey(oname);
1901 key = fFile->CreateKey(
this, obj, oname, bsize);
1902 if (newName)
delete [] newName;
1904 if (!key->GetSeekKey()) {
1907 if (bufsize) fFile->SetBufferSize(bufsize);
1910 fFile->SumBuffer(key->GetObjlen());
1911 Int_t nbytes = key->WriteFile(0);
1912 if (fFile->TestBit(TFile::kWriteError)) {
1913 if (bufsize) fFile->SetBufferSize(bufsize);
1920 if (bufsize) fFile->SetBufferSize(bufsize);
1954 Int_t TDirectoryFile::WriteObjectAny(
const void *obj,
const char *classname,
const char *name, Option_t *option, Int_t bufsize)
1956 TClass *cl = TClass::GetClass(classname);
1958 TObject *info_obj = *(TObject**)obj;
1959 TVirtualStreamerInfo *info =
dynamic_cast<TVirtualStreamerInfo*
>(info_obj);
1961 Error(
"WriteObjectAny",
"Unknown class: %s",classname);
1964 cl = info->GetClass();
1967 return WriteObjectAny(obj,cl,name,option,bufsize);
1981 Int_t TDirectoryFile::WriteObjectAny(
const void *obj,
const TClass *cl,
const char *name, Option_t *option, Int_t bufsize)
1983 TDirectory::TContext ctxt(
this);
1985 if (!fFile)
return 0;
1988 Error(
"WriteObject",
"Unknown type for %s, it can not be written.",name);
1992 if (!fFile->IsWritable()) {
1993 if (!fFile->TestBit(TFile::kWriteError)) {
1995 Error(
"WriteObject",
"File %s is not writable", fFile->GetName());
2002 const char *className = cl->GetName();
2009 if (cl && cl->GetCollectionProxy() &&
dynamic_cast<TEmulatedCollectionProxy*
>(cl->GetCollectionProxy())) {
2010 Error(
"WriteObjectAny",
2011 "The class requested (%s) for the key name \"%s\""
2012 " is an instance of an stl collection and does not have a compiled CollectionProxy."
2013 " Please generate the dictionary for this collection (%s). No data will be written.",
2014 className, oname, className);
2018 TKey *key, *oldkey =
nullptr;
2019 Int_t bsize = GetBufferSize();
2020 if (bufsize > 0) bsize = bufsize;
2022 TString opt = option;
2026 Int_t nch = strlen(oname);
2027 char *newName =
nullptr;
2028 if (nch && oname[nch-1] ==
' ') {
2029 newName =
new char[nch+1];
2030 strlcpy(newName,oname,nch+1);
2031 for (Int_t i=0;i<nch;i++) {
2032 if (newName[nch-i-1] !=
' ')
break;
2033 newName[nch-i-1] = 0;
2038 if (opt.Contains(
"overwrite")) {
2041 key = GetKey(oname);
2047 if (opt.Contains(
"writedelete")) {
2048 oldkey = GetKey(oname);
2050 key = fFile->CreateKey(
this, obj, cl, oname, bsize);
2051 if (newName)
delete [] newName;
2053 if (!key->GetSeekKey()) {
2058 fFile->SumBuffer(key->GetObjlen());
2059 Int_t nbytes = key->WriteFile(0);
2060 if (fFile->TestBit(TFile::kWriteError))
return 0;
2073 void TDirectoryFile::WriteDirHeader()
2075 TFile* f = GetFile();
2078 if (!f->IsBinary()) {
2080 f->DirWriteHeader(
this);
2084 Int_t nbytes = TDirectoryFile::Sizeof();
2085 char *header =
new char[nbytes];
2086 char *buffer = header;
2088 TDirectoryFile::FillBuffer(buffer);
2089 Long64_t pointer = fSeekDir + fNbytesName;
2092 f->WriteBuffer(header, nbytes);
2093 if (f->MustFlush()) f->Flush();
2102 void TDirectoryFile::WriteKeys()
2104 TFile* f = GetFile();
2107 if (!f->IsBinary()) {
2108 f->DirWriteKeys(
this);
2113 if (fSeekKeys != 0) {
2114 f->MakeFree(fSeekKeys, fSeekKeys + fNbytesKeys -1);
2119 Int_t nkeys = fKeys->GetSize();
2120 Int_t nbytes =
sizeof nkeys;
2121 if (f->GetEND() > TFile::kStartBigFile) nbytes += 8;
2122 while ((key = (TKey*)next())) {
2123 nbytes += key->Sizeof();
2125 TKey *headerkey =
new TKey(fName,fTitle,IsA(),nbytes,
this);
2126 if (headerkey->GetSeekKey() == 0) {
2130 char *buffer = headerkey->GetBuffer();
2132 tobuf(buffer, nkeys);
2133 while ((key = (TKey*)next())) {
2134 key->FillBuffer(buffer);
2137 fSeekKeys = headerkey->GetSeekKey();
2138 fNbytesKeys = headerkey->GetNbytes();
2139 headerkey->WriteFile();