Logo ROOT  
Reference Guide
TDirectoryFile.cxx
Go to the documentation of this file.
1// @(#)root/io:$Id$
2// Author: Rene Brun 22/01/2007
3
4/*************************************************************************
5 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/**
13 \class TDirectoryFile
14 \ingroup IO
15
16 A ROOT file is structured in Directories (like a file system).
17 Each Directory has a list of Keys (see TKeys) and a list of objects
18 in memory. A Key is a small object that describes the type and location
19 of a persistent object in a file. The persistent object may be a directory.
20Begin_Macro
21../../../tutorials/io/fildir.C
22End_Macro
23 The structure of a file is shown in TFile::TFile
24*/
25
26#include <iostream>
27#include "Strlen.h"
28#include "strlcpy.h"
29#include "TDirectoryFile.h"
30#include "TFile.h"
31#include "TBufferFile.h"
32#include "TBufferJSON.h"
33#include "TMapFile.h"
34#include "TClassTable.h"
35#include "TInterpreter.h"
36#include "THashList.h"
37#include "TBrowser.h"
38#include "TFree.h"
39#include "TKey.h"
40#include "TStreamerInfo.h"
41#include "TROOT.h"
42#include "TError.h"
43#include "Bytes.h"
44#include "TClass.h"
45#include "TRegexp.h"
46#include "TSystem.h"
47#include "TStreamerElement.h"
48#include "TProcessUUID.h"
49#include "TVirtualMutex.h"
52const UInt_t kIsBigFile = BIT(16);
53const Int_t kMaxLen = 2048;
54
56
57
58////////////////////////////////////////////////////////////////////////////////
59/// Default TDirectoryFile constructor
62{
63 /// Intentionally placed here
64 /// when TDirectoryFile() = default; used, mac1014/cxx17 fails on some tests
65 /// Problem with TObject::IsOnHeap() failing
66}
67
68
69////////////////////////////////////////////////////////////////////////////////
70/// Create a new TDirectoryFile
71///
72/// A new directory with a name and a title is created in the current directory.
73/// The directory header information is immediately saved on the file
74/// A new key is added in the parent directory.
75/// When this constructor is called from a class directly derived
76/// from TDirectoryFile, the third argument, classname, MUST be specified.
77/// In this case, classname must be the name of the derived class.
78///
79/// Note that the directory name cannot contain slashes.
81TDirectoryFile::TDirectoryFile(const char *name, const char *title, Option_t *classname, TDirectory* initMotherDir)
82{
83 // We must not publish this objects to the list of RecursiveRemove (indirectly done
84 // by 'Appending' this object to it's mother) before the object is completely
85 // initialized.
86 // However a better option would be to delay the publishing until the very end,
87 // but it is currently done in the middle of the initialization (by Build which
88 // is a public interface) ....
90
91 fName = name;
92 fTitle = title;
93
94 if (!initMotherDir) initMotherDir = gDirectory;
95
96 if (strchr(name,'/')) {
97 ::Error("TDirectoryFile","directory name (%s) cannot contain a slash", name);
98 gDirectory = nullptr;
99 return;
100 }
101 if (strlen(GetName()) == 0) {
102 ::Error("TDirectoryFile","directory name cannot be \"\"");
103 gDirectory = nullptr;
104 return;
105 }
106
107 BuildDirectoryFile(initMotherDir ? initMotherDir->GetFile() : nullptr, initMotherDir);
108
109 TDirectory* motherdir = GetMotherDir();
111
112 if (!motherdir || !f) return;
113 if (!f->IsWritable()) return; //*-* in case of a directory in memory
114 if (motherdir->GetKey(name)) {
115 Error("TDirectoryFile","An object with name %s exists already", name);
116 return;
117 }
118 TClass *cl = nullptr;
119 if (classname[0]) {
120 cl = TClass::GetClass(classname);
121 if (!cl) {
122 Error("TDirectoryFile","Invalid class name: %s",classname);
123 return;
124 }
125 } else {
126 cl = TDirectoryFile::IsA();
127 }
128
129 fBufferSize = 0;
131
133
135
136 // Temporarily redundant, see comment on lock early in the function.
137 // R__LOCKGUARD(gROOTMutex);
138 gROOT->GetUUIDs()->AddUUID(fUUID,this);
139 // We should really be doing this now rather than in Build, see
140 // comment at the start of the function.
141 // if (initMotherDir && strlen(GetName()) != 0) initMotherDir->Append(this);
142}
143
144////////////////////////////////////////////////////////////////////////////////
145/// Initialize the key associated with this directory (and the related
146/// data members.
149{
150 TFile* f = GetFile(); // NOLINT: silence clang-tidy warnings
151 if (f->IsBinary()) {
152 if (!cl) {
153 cl = IsA(); // NOLINT: silence clang-tidy warnings
154 }
155 TDirectory* motherdir = GetMotherDir();
156 fSeekParent = f->GetSeekDir();
157 Int_t nbytes = TDirectoryFile::Sizeof();
158 TKey *key = new TKey(fName,fTitle,cl,nbytes,motherdir);
159 fNbytesName = key->GetKeylen();
160 fSeekDir = key->GetSeekKey();
161 if (fSeekDir == 0) return;
162 char *buffer = key->GetBuffer();
164 Int_t cycle = motherdir ? motherdir->AppendKey(key) : 0;
165 key->WriteFile(cycle);
166 } else {
167 fSeekParent = 0;
168 fNbytesName = 0;
169 fSeekDir = f->DirCreateEntry(this);
170 if (fSeekDir == 0) return;
171 }
172
173}
174
175////////////////////////////////////////////////////////////////////////////////
176/// Destructor.
179{
180 if (fKeys) {
181 fKeys->Delete("slow");
183 }
184
186
187 // Delete our content before we become somewhat invalid
188 // since some those objects (TTree for example) needs information
189 // from this object. Note that on some platform after the end
190 // of the body (i.e. thus during ~TDirectory which is also
191 // contains this code) the execution of 'this->GetFile()' fails
192 // to return the 'proper' value (because it uses the wrong
193 // virtual function).
194 if (fList) {
195 fList->Delete("slow");
197 }
198
199 if (gDebug) {
200 Info("~TDirectoryFile", "dtor called for %s", GetName());
201 }
202}
203
204////////////////////////////////////////////////////////////////////////////////
205/// Append object to this directory.
206///
207/// If replace is true:
208/// remove any existing objects with the same same (if the name is not ""
210void TDirectoryFile::Append(TObject *obj, Bool_t replace /* = kFALSE */)
211{
212 if (!obj || !fList) return;
213
214 TDirectory::Append(obj,replace);
215
216 if (!fMother) return;
217 if (fMother->IsA() == TMapFile::Class()) {
218 TMapFile *mfile = (TMapFile*)fMother;
219 mfile->Add(obj);
220 }
221}
222
223////////////////////////////////////////////////////////////////////////////////
224/// Insert key in the linked list of keys of this directory.
227{
228 if (!fKeys) {
229 Error("AppendKey","TDirectoryFile not initialized yet.");
230 return 0;
231 }
232
234
235 key->SetMotherDir(this);
236
237 // This is a fast hash lookup in case the key does not already exist
238 TKey *oldkey = (TKey*)fKeys->FindObject(key->GetName());
239 if (!oldkey) {
240 fKeys->Add(key);
241 return 1;
242 }
243
244 // If the key name already exists we have to make a scan for it
245 // and insert the new key ahead of the current one
246 TObjLink *lnk = fKeys->FirstLink();
247 while (lnk) {
248 oldkey = (TKey*)lnk->GetObject();
249 if (!strcmp(oldkey->GetName(), key->GetName()))
250 break;
251 lnk = lnk->Next();
252 }
253
254 fKeys->AddBefore(lnk, key);
255 return oldkey->GetCycle() + 1;
256}
257
258////////////////////////////////////////////////////////////////////////////////
259/// Browse the content of the directory.
262{
264
265 if (b) {
266 TObject *obj = nullptr;
267 TIter nextin(fList);
268 TKey *key = nullptr, *keyo = nullptr;
269 TIter next(fKeys);
270
271 cd();
272
273 //Add objects that are only in memory
274 while ((obj = nextin())) {
275 if (fKeys->FindObject(obj->GetName())) continue;
276 b->Add(obj, obj->GetName());
277 }
278
279 //Add keys
280 while ((key = (TKey *) next())) {
281 int skip = 0;
282 if (!keyo || (keyo && strcmp(keyo->GetName(), key->GetName()))) {
283 skip = 0;
284 obj = fList->FindObject(key->GetName());
285
286 if (obj) {
287 b->Add(obj, obj->GetName());
288 if (obj->IsFolder() && !obj->InheritsFrom("TTree"))
289 skip = 1;
290 }
291 }
292
293 if (!skip) {
294 name.Form("%s;%d", key->GetName(), key->GetCycle());
295 b->Add(key, name);
296 }
297
298 keyo = key;
299 }
300 }
301}
302
303////////////////////////////////////////////////////////////////////////////////
304/// Initialise directory to defaults.
306void TDirectoryFile::BuildDirectoryFile(TFile* motherFile, TDirectory* motherDir)
307{
308 // If directory is created via default ctor (when dir is read from file)
309 // don't add it here to the directory since its name is not yet known.
310 // It will be added to the directory in TKey::ReadObj().
311
312 if (motherDir && strlen(GetName()) != 0) motherDir->Append(this);
313
316 fDatimeC.Set();
317 fDatimeM.Set();
318 fNbytesKeys = 0;
319 fSeekDir = 0;
320 fSeekParent = 0;
321 fSeekKeys = 0;
322 fList = new THashList(100,50);
323 fKeys = new THashList(100,50);
324 fList->UseRWLock();
325 fMother = motherDir;
326 fFile = motherFile ? motherFile : TFile::CurrentFile();
328}
329
330////////////////////////////////////////////////////////////////////////////////
331/// Change current directory to "this" directory.
332/// Using path one can
333/// change the current directory to "path". The absolute path syntax is:
334///
335/// file.root:/dir1/dir2
336///
337/// where file.root is the file and /dir1/dir2 the desired subdirectory
338/// in the file. Relative syntax is relative to "this" directory. E.g:
339/// ../aa. Returns kTRUE in case of success.
341Bool_t TDirectoryFile::cd(const char *path)
342{
343 Bool_t ok = TDirectory::cd(path);
344 if (ok) TFile::CurrentFile() = fFile;
345 return ok;
346}
347
348////////////////////////////////////////////////////////////////////////////////
349/// Clean the pointers to this object (gDirectory, TContext, etc.)
352{
353 // After CleanTargets either gFile was changed appropriately
354 // by a cd() or needs to be set to zero.
355 if (gFile == this) {
356 gFile = nullptr;
357 }
358
360}
361
362////////////////////////////////////////////////////////////////////////////////
363/// Make a clone of an object using the Streamer facility.
364///
365/// If the object derives from TNamed, this function is called
366/// by TNamed::Clone. TNamed::Clone uses the optional argument newname to set
367/// a new name to the newly created object.
368///
369/// If autoadd is true and if the object class has a
370/// DirectoryAutoAdd function, it will be called at the end of the
371/// function with the parameter gDirectory. This usually means that
372/// the object will be appended to the current ROOT directory.
374TObject *TDirectoryFile::CloneObject(const TObject *obj, Bool_t autoadd /* = kTRUE */)
375{
376 // if no default ctor return immediately (error issued by New())
377 char *pobj = (char*)obj->IsA()->New();
378 if (!pobj) return nullptr;
379
380 Int_t baseOffset = obj->IsA()->GetBaseClassOffset(TObject::Class());
381 if (baseOffset==-1) {
382 // cl does not inherit from TObject.
383 // Since this is not supported in this function, the only reason we could reach this code
384 // is because something is screwed up in the ROOT code.
385 Fatal("CloneObject","Incorrect detection of the inheritance from TObject for class %s.\n",
386 obj->IsA()->GetName());
387 }
388 TObject *newobj = (TObject*)(pobj+baseOffset);
389
390 //create a buffer where the object will be streamed
391 {
392 // NOTE: do we still need to make this change to gFile?
393 // NOTE: This can not be 'gDirectory=0' as at least roofit expect gDirectory to not be null
394 // during the streaming ....
395 TFile *filsav = gFile;
396 gFile = nullptr;
397 const Int_t bufsize = 10000;
398 TBufferFile buffer(TBuffer::kWrite,bufsize);
399 buffer.MapObject(obj); //register obj in map to handle self reference
400 {
401 Bool_t isRef = obj->TestBit(kIsReferenced);
402 ((TObject*)obj)->ResetBit(kIsReferenced);
403
404 ((TObject*)obj)->Streamer(buffer);
405
406 if (isRef) ((TObject*)obj)->SetBit(kIsReferenced);
407 }
408
409 // read new object from buffer
410 buffer.SetReadMode();
411 buffer.ResetMap();
412 buffer.SetBufferOffset(0);
413 buffer.MapObject(newobj); //register obj in map to handle self reference
414 newobj->Streamer(buffer);
415 newobj->ResetBit(kIsReferenced);
416 newobj->ResetBit(kCanDelete);
417 gFile = filsav;
418 }
419
420 if (autoadd) {
421 ROOT::DirAutoAdd_t func = obj->IsA()->GetDirectoryAutoAdd();
422 if (func) {
423 func(newobj,this);
424 }
425 }
426 return newobj;
427}
428
429////////////////////////////////////////////////////////////////////////////////
430/// Scan the memory lists of all files for an object with name
433{
434 TFile *f;
436 TIter next(gROOT->GetListOfFiles());
437 while ((f = (TFile*)next())) {
438 TObject *obj = f->GetList()->FindObject(name);
439 if (obj) return obj;
440 }
441 return nullptr;
442}
443
444////////////////////////////////////////////////////////////////////////////////
445/// Find a directory named "apath".
446///
447/// It apath is null or empty, returns "this" directory.
448/// Otherwise use the name "apath" to find a directory.
449/// The absolute path syntax is:
450///
451/// file.root:/dir1/dir2
452///
453/// where file.root is the file and /dir1/dir2 the desired subdirectory
454/// in the file. Relative syntax is relative to "this" directory. E.g:
455/// ../aa.
456/// Returns 0 in case path does not exist.
457/// If printError is true, use Error with 'funcname' to issue an error message.
460 Bool_t printError, const char *funcname)
461{
462 Int_t nch = 0;
463 if (apath) nch = strlen(apath);
464 if (!nch) {
465 return this;
466 }
467
468 if (funcname==0 || strlen(funcname)==0) funcname = "GetDirectory";
469
470 TDirectory *result = this;
471
472 char *path = new char[nch+1]; path[0] = 0;
473 if (nch) strlcpy(path,apath,nch+1);
474 char *s = (char*)strchr(path, ':');
475 if (s) {
476 *s = '\0';
478 TDirectory *f = (TDirectory *)gROOT->GetListOfFiles()->FindObject(path);
479 // Check if this is a duplicate (2nd opening) on this file and prefer
480 // this file.
481 if (GetFile()) {
482 auto url = GetFile()->GetEndpointUrl();
483 if (f && 0 == url->Compare(f->GetFile()->GetEndpointUrl())) {
484 result = GetDirectory(s+1,printError,funcname);
485 delete [] path;
486 return result;
487 }
488 }
489 if (!f && !strcmp(gROOT->GetName(), path)) f = gROOT;
490 if (s) *s = ':';
491 if (f) {
492 result = f;
493 if (s && *(s+1)) result = f->GetDirectory(s+1,printError,funcname);
494 delete [] path; return result;
495 } else {
496 if (printError) Error(funcname, "No such file %s", path);
497 delete [] path; return nullptr;
498 }
499 }
500
501 // path starts with a slash (assumes current file)
502 if (path[0] == '/') {
503 TDirectory *td = fFile;
504 if (!fFile) td = gROOT;
505 result = td->GetDirectory(path+1,printError,funcname);
506 delete [] path; return result;
507 }
508
509 TDirectoryFile *obj;
510 char *slash = (char*)strchr(path,'/');
511 if (!slash) { // we are at the lowest level
512 if (!strcmp(path, "..")) {
513 result = GetMotherDir();
514 delete [] path; return result;
515 }
516 GetObject(path,obj);
517 if (!obj) {
518 if (printError) Error(funcname,"Unknown directory %s", path);
519 delete [] path; return nullptr;
520 }
521
522 delete [] path; return obj;
523 }
524
525 TString subdir(path);
526 slash = (char*)strchr(subdir.Data(),'/');
527 *slash = 0;
528 //Get object with path from current directory/file
529 if (!strcmp(subdir, "..")) {
530 TDirectory* mom = GetMotherDir();
531 if (mom)
532 result = mom->GetDirectory(slash+1,printError,funcname);
533 delete [] path; return result;
534 }
535 GetObject(subdir,obj);
536 if (!obj) {
537 if (printError) Error(funcname,"Unknown directory %s", subdir.Data());
538 delete [] path; return nullptr;
539 }
540
541 result = ((TDirectory*)obj)->GetDirectory(slash+1,printError,funcname);
542 delete [] path; return result;
543}
544
545////////////////////////////////////////////////////////////////////////////////
546/// Delete all objects from memory and directory structure itself.
549{
550 if (!fList || !fSeekDir) {
551 return;
552 }
553
554 // Save the directory key list and header
555 Save();
556
557 Bool_t nodelete = option ? (!strcmp(option, "nodelete") ? kTRUE : kFALSE) : kFALSE;
558
559 if (!nodelete) {
560 Bool_t fast = kTRUE;
561 TObjLink *lnk = fList->FirstLink();
562 while (lnk) {
563 if (lnk->GetObject()->IsA() == TDirectoryFile::Class()) {fast = kFALSE;break;}
564 lnk = lnk->Next();
565 }
566 // Delete objects from directory list, this in turn, recursively closes all
567 // sub-directories (that were allocated on the heap)
568 // if this dir contains subdirs, we must use the slow option for Delete!
569 // we must avoid "slow" as much as possible, in particular Delete("slow")
570 // with a large number of objects (eg >10^5) would take for ever.
571 {
572 if (fast) fList->Delete();
573 else fList->Delete("slow");
574 }
575 }
576
577 // Delete keys from key list (but don't delete the list header)
578 if (fKeys) {
579 fKeys->Delete("slow");
580 }
581
583}
584
585////////////////////////////////////////////////////////////////////////////////
586/// Delete Objects or/and keys in a directory
587///
588/// Properties of the namecycle string:
589/// - namecycle has the format name;cycle
590/// - namecycle = "" is same as namecycle ="T*"
591/// - name = * means all
592/// - cycle = * means all cycles (memory and keys)
593/// - cycle = "" or cycle = 9999 ==> apply to a memory object
594/// When name=* use T* to delete subdirectories also
595///
596/// To delete one directory, you must specify the directory cycle,
597/// eg. file.Delete("dir1;1");
598///
599/// Examples:
600/// | Pattern | Description |
601/// |---------|-------------|
602/// | foo | delete object named foo in memory |
603/// | foo* | delete all objects with a name starting with foo |
604/// | foo;1 | delete cycle 1 of foo on file |
605/// | foo;* | delete all cycles of foo on file and also from memory |
606/// | *;2 | delete all objects on file having the cycle 2 |
607/// | *;* | delete all objects from memory and file |
608/// | T*;* | delete all objects from memory and file and all subdirectories |
609///
610/// ## WARNING
611/// If the key to be deleted contains special characters ("+","^","?", etc
612/// that have a special meaning for the regular expression parser (see TRegexp)
613/// then you must specify 2 backslash characters to escape the regular expression.
614/// For example, if the key to be deleted is namecycle = "C++", you must call
615///
616/// mydir.Delete("C\\+\\+"));
617///
619void TDirectoryFile::Delete(const char *namecycle)
620{
621 if (gDebug)
622 Info("Delete","Call for this = %s namecycle = %s",
623 GetName(), (namecycle ? namecycle : "null"));
624
625 TDirectory::TContext ctxt(this);
626 Short_t cycle;
627 char name[kMaxLen];
628 const char *nmcy = (namecycle) ? namecycle : "";
629 DecodeNameCycle(nmcy, name, cycle, kMaxLen);
630
631 Int_t deleteall = 0;
632 Int_t deletetree = 0;
633 if(strcmp(name,"*") == 0) deleteall = 1;
634 if(strcmp(name,"*T") == 0){ deleteall = 1; deletetree = 1;}
635 if(strcmp(name,"T*") == 0){ deleteall = 1; deletetree = 1;}
636 if(namecycle==0 || !namecycle[0]){ deleteall = 1; deletetree = 1;}
637 TRegexp re(name,kTRUE);
638 TString s;
639 Int_t deleteOK = 0;
640
641//*-*---------------------Case of Object in memory---------------------
642// ========================
643 if (cycle >= 9999 ) {
644 TNamed *idcur;
645 TIter next(fList);
646 while ((idcur = (TNamed *) next())) {
647 deleteOK = 0;
648 s = idcur->GetName();
649 if (deleteall || s.Index(re) != kNPOS) {
650 deleteOK = 1;
651 if (idcur->IsA() == TDirectoryFile::Class()) {
652 deleteOK = 2;
653 if (!deletetree && deleteall) deleteOK = 0;
654 }
655 }
656 if (deleteOK != 0) {
657 fList->Remove(idcur);
658 if (deleteOK==2) {
659 // read subdirectories to correctly delete them
660 if (deletetree)
661 ((TDirectory*) idcur)->ReadAll("dirs");
662 idcur->Delete(deletetree ? "T*;*" : "*");
663 delete idcur;
664 } else
665 idcur->Delete(name);
666 }
667 }
668// if (deleteOK == 2) {
669// Info("Delete","Dir:%lx %s", fList->FindObject(name), name);
670// delete fList->FindObject(name); //deleting a TDirectory
671// }
672 }
673//*-*---------------------Case of Key---------------------
674// ===========
675 if (cycle != 9999 ) {
676 if (IsWritable()) {
677 TKey *key;
678 TIter nextkey(GetListOfKeys());
679 while ((key = (TKey *) nextkey())) {
680 deleteOK = 0;
681 s = key->GetName();
682 if (deleteall || s.Index(re) != kNPOS) {
683 if (cycle == key->GetCycle()) deleteOK = 1;
684 if (cycle > 9999) deleteOK = 1;
685 //if (!strcmp(key->GetClassName(),"TDirectory")) {
686 if (strstr(key->GetClassName(),"TDirectory")) {
687 deleteOK = 2;
688 if (!deletetree && deleteall) deleteOK = 0;
689 if (cycle == key->GetCycle()) deleteOK = 2;
690 }
691 }
692 if (deleteOK) {
693 if (deleteOK==2) {
694 // read directory with subdirectories to correctly delete and free key structure
695 TDirectory* dir = GetDirectory(key->GetName(), kTRUE, "Delete");
696 if (dir!=0) {
697 dir->Delete("T*;*");
698 fList->Remove(dir);
699 delete dir;
700 }
701 }
702
703 key->Delete();
704 fKeys->Remove(key);
706 delete key;
707 }
708 }
709 TFile* f = GetFile();
710 if (fModified && (f!=0)) {
711 WriteKeys(); //*-* Write new keys structure
712 WriteDirHeader(); //*-* Write new directory header
713 f->WriteFree(); //*-* Write new free segments list
714 f->WriteHeader(); //*-* Write new file header
715 }
716 }
717 }
718}
719
720////////////////////////////////////////////////////////////////////////////////
721/// Encode directory header into output buffer
723void TDirectoryFile::FillBuffer(char *&buffer)
724{
725 Version_t version = TDirectoryFile::Class_Version();
729 {
730 // One of the address is larger than 2GB we need to use longer onfile
731 // integer, thus we increase the version number.
732 // Note that fSeekDir and fSeekKey are not necessarily correlated, if
733 // some object are 'removed' from the file and the holes are reused.
734 version += 1000;
735 }
736 tobuf(buffer, version);
737 const bool reproducible = TestBit(TFile::kReproducible) || (fFile && fFile->TestBit(TFile::kReproducible));
738 if (reproducible) {
739 TDatime((UInt_t) 1).FillBuffer(buffer);
740 TDatime((UInt_t) 1).FillBuffer(buffer);
741 } else {
742 fDatimeC.FillBuffer(buffer);
743 fDatimeM.FillBuffer(buffer);
744 }
745 tobuf(buffer, fNbytesKeys);
746 tobuf(buffer, fNbytesName);
747 if (version > 1000) {
748 tobuf(buffer, fSeekDir);
749 tobuf(buffer, fSeekParent);
750 tobuf(buffer, fSeekKeys);
751 } else {
752 tobuf(buffer, (Int_t)fSeekDir);
753 tobuf(buffer, (Int_t)fSeekParent);
754 tobuf(buffer, (Int_t)fSeekKeys);
755 }
756 if (reproducible)
757 TUUID("00000000-0000-0000-0000-000000000000").FillBuffer(buffer);
758 else
759 fUUID.FillBuffer(buffer);
760 if (fFile && fFile->GetVersion() < 40000) return;
761 if (version <=1000) for (Int_t i=0;i<3;i++) tobuf(buffer,Int_t(0));
762}
763
764////////////////////////////////////////////////////////////////////////////////
765/// Find key with name keyname in the current directory
767TKey *TDirectoryFile::FindKey(const char *keyname) const
768{
769 Short_t cycle;
770 char name[kMaxLen];
771
772 DecodeNameCycle(keyname, name, cycle, kMaxLen);
773 return GetKey(name,cycle);
774}
775
776////////////////////////////////////////////////////////////////////////////////
777/// Find key with name keyname in the current directory or
778/// its subdirectories.
779///
780/// NOTE: that If a key is found, the directory containing the key becomes
781/// the current directory
783TKey *TDirectoryFile::FindKeyAny(const char *keyname) const
784{
785 TDirectory *dirsav = gDirectory;
786 Short_t cycle;
787 char name[kMaxLen];
788
789 DecodeNameCycle(keyname, name, cycle, kMaxLen);
790
791 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
792 if (!listOfKeys) {
793 Error("FindKeyAny", "Unexpected type of TDirectoryFile::fKeys!");
794 return nullptr;
795 }
796
797 if (const TList *keyList = listOfKeys->GetListForObject(name)) {
798 for (auto key: TRangeDynCast<TKey>(*keyList)) {
799 if (key && !strcmp(key->GetName(), name)
800 && (cycle == 9999 || cycle >= key->GetCycle())) {
801 const_cast<TDirectoryFile*>(this)->cd(); // may be we should not make cd ???
802 return key;
803 }
804 }
805 }
806
807 //try with subdirectories
808 TIter next(GetListOfKeys());
809 TKey *key;
810 while ((key = (TKey *) next())) {
811 //if (!strcmp(key->GetClassName(),"TDirectory")) {
812 if (strstr(key->GetClassName(),"TDirectory")) {
813 TDirectory* subdir =
814 const_cast<TDirectoryFile*>(this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
815 TKey *k = subdir ? subdir->FindKeyAny(keyname) : nullptr;
816 if (k) return k;
817 }
818 }
819 if (dirsav) dirsav->cd();
820 return nullptr;
821}
822
823////////////////////////////////////////////////////////////////////////////////
824/// Find object by name in the list of memory objects of the current
825/// directory or its sub-directories.
826///
827/// After this call the current directory is not changed.
828/// To automatically set the current directory where the object is found,
829/// use FindKeyAny(aname)->ReadObj().
831TObject *TDirectoryFile::FindObjectAny(const char *aname) const
832{
833 //object may be already in the list of objects in memory
835 if (obj) return obj;
836
837 TDirectory *dirsav = gDirectory;
838 Short_t cycle;
839 char name[kMaxLen];
840
841 DecodeNameCycle(aname, name, cycle, kMaxLen);
842
843 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
844 if (!listOfKeys) {
845 Error("FindObjectAny", "Unexpected type of TDirectoryFile::fKeys!");
846 return nullptr;
847 }
848
849 if (const TList *keyList = listOfKeys->GetListForObject(name)) {
850 for (auto key: TRangeDynCast<TKey>(*keyList)) {
851 if (key && !strcmp(key->GetName(), name)
852 && (cycle == 9999 || cycle >= key->GetCycle())) {
853 return key->ReadObj();
854 }
855 }
856 }
857
858 //try with subdirectories
859 TIter next(GetListOfKeys());
860 TKey *key;
861 while ((key = (TKey *) next())) {
862 //if (!strcmp(key->GetClassName(),"TDirectory")) {
863 if (strstr(key->GetClassName(),"TDirectory")) {
864 TDirectory* subdir =
865 ((TDirectory*)this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
866 TKey *k = subdir ? subdir->FindKeyAny(aname) : nullptr;
867 if (k) { if (dirsav) dirsav->cd(); return k->ReadObj();}
868 }
869 }
870 if (dirsav) dirsav->cd();
871 return nullptr;
872}
873
874////////////////////////////////////////////////////////////////////////////////
875/// Return pointer to object identified by namecycle.
876///
877/// Properties:
878/// - namecycle has the format name;cycle
879/// - name = * is illegal, cycle = * is illegal
880/// - cycle = "" or cycle = 9999 ==> apply to a memory object
881///
882/// Examples:
883/// | %Pattern | Explanation |
884/// |----------|-------------|
885/// | foo | get object named foo in memory if object is not in memory, try with highest cycle from file |
886/// | foo;1 | get cycle 1 of foo on file |
887///
888/// The retrieved object should in principle derive from TObject.
889/// If not, the function TDirectoryFile::Get<T> should be called.
890/// However, this function will still work for a non-TObject, provided that
891/// the calling application cast the return type to the correct type (which
892/// is the actual type of the object).
893///
894/// ### The Get<T> Method
895/// The method Get<T> offers better protection and avoids the need for any
896/// cast:
897/// ~~~{.cpp}
898/// auto objPtr = directory->Get<MyClass>("some object");
899/// if (objPtr) { ... the object exist and inherits from MyClass ... }
900/// ~~~
901///
902/// ### Very important note about inheritance
903/// In case the class of this object derives from TObject but not
904/// as a first inheritance, one must use dynamic_cast<>().
905///
906/// #### Example 1 - Normal case:
907///
908/// class MyClass : public TObject, public AnotherClass
909///
910/// then on return, one can adopt a C style cast:
911///
912/// auto objPtr = (MyClass*)directory->Get("some object of MyClass");
913///
914/// #### Example 2 - Special case:
915///
916/// class MyClass : public AnotherClass, public TObject
917///
918/// then on return, one must do:
919///
920/// auto objPtr = dynamic_cast<MyClass*>(directory->Get("some object of MyClass"));
921///
922/// Of course, dynamic_cast<> can also be used in the example 1.
923///
925TObject *TDirectoryFile::Get(const char *namecycle)
926{
927 Short_t cycle;
928 char name[kMaxLen];
929
930 DecodeNameCycle(namecycle, name, cycle, kMaxLen);
931 Int_t nch = strlen(name);
932 for (Int_t i = nch-1; i > 0; i--) {
933 if (name[i] == '/') {
934 name[i] = 0;
935 TDirectory* dirToSearch=GetDirectory(name);
936 const char *subnamecycle = namecycle + i + 1;
937 name[i] = '/';
938 return dirToSearch?dirToSearch->Get(subnamecycle):0;
939 }
940 }
941 const char *namobj = name;
942
943//*-*---------------------Case of Object in memory---------------------
944// ========================
945 TObject *idcur = fList ? fList->FindObject(namobj) : nullptr;
946 if (idcur) {
947 if (idcur==this && strlen(namobj)!=0) {
948 // The object has the same name has the directory and
949 // that's what we picked-up! We just need to ignore
950 // it ...
951 idcur = nullptr;
952 } else if (cycle == 9999) {
953 return idcur;
954 } else {
955 if (idcur->InheritsFrom(TCollection::Class()))
956 idcur->Delete(); // delete also list elements
957 delete idcur;
958 idcur = nullptr;
959 }
960 }
961
962//*-*---------------------Case of Key---------------------
963// ===========
964 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
965 if (!listOfKeys) {
966 Error("Get", "Unexpected type of TDirectoryFile::fKeys!");
967 return nullptr;
968 }
969
970 if (const TList *keyList = listOfKeys->GetListForObject(namobj)) {
971 for (auto key: TRangeDynCast<TKey>(*keyList)) {
972 if (key && !strcmp(key->GetName(), namobj)
973 && (cycle == 9999 || cycle == key->GetCycle())) {
974 TDirectory::TContext ctxt(this);
975 return key->ReadObj();
976 }
977 }
978 }
979
980 return nullptr;
981}
982
983////////////////////////////////////////////////////////////////////////////////
984/// Return pointer to object identified by namecycle.
985///
986/// The returned object may or may not derive from TObject.
987///
988/// - namecycle has the format name;cycle
989/// - name = * is illegal, cycle = * is illegal
990/// - cycle = "" or cycle = 9999 ==> apply to a memory object
991///
992/// ## Very important note
993/// The calling application must cast the returned object to
994/// the final type, e.g.
995///
996/// auto objPtr = (MyClass*)directory->GetObject("some object of MyClass");
998void *TDirectoryFile::GetObjectUnchecked(const char *namecycle)
999{
1000 return GetObjectChecked(namecycle,(TClass*)nullptr);
1001}
1002
1003////////////////////////////////////////////////////////////////////////////////
1004/// See documentation of TDirectoryFile::GetObjectCheck(const char *namecycle, const TClass *cl)
1006void *TDirectoryFile::GetObjectChecked(const char *namecycle, const char* classname)
1007{
1008 return GetObjectChecked(namecycle,TClass::GetClass(classname));
1009}
1010
1011
1012////////////////////////////////////////////////////////////////////////////////
1013/// Return pointer to object identified by namecycle if and only if the actual
1014/// object is a type suitable to be stored as a pointer to a "expectedClass"
1015/// If expectedClass is null, no check is performed.
1016///
1017/// - namecycle has the format name;cycle
1018/// - name = * is illegal, cycle = * is illegal
1019/// - cycle = "" or cycle = 9999 ==> apply to a memory object
1020///
1021/// ### Very important note
1022/// The calling application must cast the returned pointer to
1023/// the type described by the 2 arguments (i.e. cl):
1024///
1025/// auto objPtr = (MyClass*)directory->GetObjectChecked("some object of MyClass","MyClass"));
1026///
1027/// Note: We recommend using the method TDirectoryFile::Get<T>:
1028/// ~~~{.cpp}
1029/// auto objPtr = directory->Get<MyClass>("some object inheriting from MyClass");
1030/// if (objPtr) { ... we found what we are looking for ... }
1031/// ~~~
1033void *TDirectoryFile::GetObjectChecked(const char *namecycle, const TClass* expectedClass)
1034{
1035
1036 // If the name is invalid, issue an error message and return a nullptr
1037 if (!namecycle || '\0' == namecycle[0]) {
1038 Error("GetObjectChecked", "The provided key name is invalid.");
1039 return nullptr;
1040 }
1041
1042 Short_t cycle;
1043 char name[kMaxLen];
1044
1045 DecodeNameCycle(namecycle, name, cycle, kMaxLen);
1046 Int_t nch = strlen(name);
1047 for (Int_t i = nch-1; i > 0; i--) {
1048 if (name[i] == '/') {
1049 name[i] = 0;
1050 TDirectory* dirToSearch=GetDirectory(name);
1051 const char *subnamecycle = namecycle + i + 1;
1052 name[i] = '/';
1053 if (dirToSearch) {
1054 return dirToSearch->GetObjectChecked(subnamecycle, expectedClass);
1055 } else {
1056 return nullptr;
1057 }
1058 }
1059 }
1060 const char *namobj = name;
1061
1062//*-*---------------------Case of Object in memory---------------------
1063// ========================
1064 if (expectedClass==0 || expectedClass->IsTObject()) {
1065 TObject *objcur = fList ? fList->FindObject(namobj) : nullptr;
1066 if (objcur) {
1067 if (objcur==this && strlen(namobj)!=0) {
1068 // The object has the same name has the directory and
1069 // that's what we picked-up! We just need to ignore
1070 // it ...
1071 objcur = nullptr;
1072 } else if (cycle == 9999) {
1073 // Check type
1074 if (expectedClass && objcur->IsA()->GetBaseClassOffset(expectedClass) == -1) return nullptr;
1075 else return objcur;
1076 } else {
1077 if (objcur->InheritsFrom(TCollection::Class()))
1078 objcur->Delete(); // delete also list elements
1079 delete objcur;
1080 objcur = nullptr;
1081 }
1082 }
1083 }
1084
1085//*-*---------------------Case of Key---------------------
1086// ===========
1087 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
1088 if (!listOfKeys) {
1089 Error("GetObjectChecked", "Unexpected type of TDirectoryFile::fKeys!");
1090 return nullptr;
1091 }
1092
1093 if (const TList *keyList = listOfKeys->GetListForObject(namobj)) {
1094 for (auto key: TRangeDynCast<TKey>(*keyList)) {
1095 if (key && !strcmp(key->GetName(), namobj)
1096 && (cycle == 9999 || cycle == key->GetCycle())) {
1097 TDirectory::TContext ctxt(this);
1098 return key->ReadObjectAny(expectedClass);
1099 }
1100 }
1101 }
1102
1103 return nullptr;
1104}
1105
1106////////////////////////////////////////////////////////////////////////////////
1107/// Return the buffer size to create new TKeys.
1108///
1109/// If the stored fBufferSize is null, the value returned is the average
1110/// buffer size of objects in the file so far.
1113{
1114 if (fBufferSize <= 0) return fFile->GetBestBuffer();
1115 else return fBufferSize;
1116}
1117
1118
1119////////////////////////////////////////////////////////////////////////////////
1120/// Return pointer to key with name,cycle
1121///
1122/// if cycle = 9999 returns highest cycle
1124TKey *TDirectoryFile::GetKey(const char *name, Short_t cycle) const
1125{
1126 if (!fKeys) return nullptr;
1127
1128 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
1129 if (!listOfKeys) {
1130 Error("GetKey", "Unexpected type of TDirectoryFile::fKeys!");
1131 return nullptr;
1132 }
1133
1134 if (const TList *keyList = listOfKeys->GetListForObject(name)) {
1135 for (auto key: TRangeDynCast<TKey>(*keyList)) {
1136 if (key && !strcmp(key->GetName(), name)
1137 && (cycle == 9999 || cycle >= key->GetCycle())) {
1138 return key;
1139 }
1140 }
1141 }
1142
1143 return nullptr;
1144}
1145
1146////////////////////////////////////////////////////////////////////////////////
1147/// List Directory contents
1148///
1149/// Indentation is used to identify the directory tree
1150/// Subdirectories are listed first, then objects in memory, then objects on the file
1151///
1152/// The option can has the following format: <b>[-d |-m][<regexp>]</b>
1153/// Options:
1154/// - -d: only list objects in the file
1155/// - -m: only list objects in memory
1156/// The <regexp> will be used to match the name of the objects.
1157/// By default memory and disk objects are listed.
1159void TDirectoryFile::ls(Option_t *option) const
1160{
1162 std::cout <<ClassName()<<"*\t\t"<<GetName()<<"\t"<<GetTitle()<<std::endl;
1164
1165 TString opta = option;
1166 TString opt = opta.Strip(TString::kBoth);
1167 Bool_t memobj = kTRUE;
1168 Bool_t diskobj = kTRUE;
1169 TString reg = "*";
1170 if (opt.BeginsWith("-m")) {
1171 diskobj = kFALSE;
1172 if (opt.Length() > 2)
1173 reg = opt(2,opt.Length());
1174 } else if (opt.BeginsWith("-d")) {
1175 memobj = kFALSE;
1176 if (opt.Length() > 2)
1177 reg = opt(2,opt.Length());
1178 } else if (!opt.IsNull())
1179 reg = opt;
1180
1181 TRegexp re(reg, kTRUE);
1182
1183 if (memobj) {
1184 TObject *obj;
1185 TIter nextobj(fList);
1186 while ((obj = (TObject *) nextobj())) {
1187 TString s = obj->GetName();
1188 if (s.Index(re) == kNPOS) continue;
1189 obj->ls(option); //*-* Loop on all the objects in memory
1190 }
1191 }
1192
1193 if (diskobj && fKeys) {
1194 //*-* Loop on all the keys
1195 TObjLink *lnk = fKeys->FirstLink();
1196 while (lnk) {
1197 TKey *key = (TKey*)lnk->GetObject();
1198 TString s = key->GetName();
1199 if (s.Index(re) == kNPOS) continue;
1200 bool first = (lnk->Prev() == nullptr) || (s != lnk->Prev()->GetObject()->GetName());
1201 bool hasbackup = (lnk->Next() != nullptr) && (s == lnk->Next()->GetObject()->GetName());
1202 if (first)
1203 if (hasbackup)
1204 key->ls(true);
1205 else
1206 key->ls();
1207 else
1208 key->ls(false);
1209 lnk = lnk->Next();
1210 }
1211 }
1213}
1214
1215////////////////////////////////////////////////////////////////////////////////
1216/// Interface to TFile::Open
1218TFile *TDirectoryFile::OpenFile(const char *name, Option_t *option,const char *ftitle, Int_t compress, Int_t netopt)
1219{
1220 return TFile::Open(name,option,ftitle,compress,netopt);
1221
1222}
1223
1224////////////////////////////////////////////////////////////////////////////////
1225/// Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...".
1226///
1227/// Returns 0 in case of error or if a sub-directory (hierarchy) with the requested
1228/// name already exists.
1229/// returnExistingDirectory returns a pointer to an already existing sub-directory instead of 0.
1230/// Returns a pointer to the created sub-directory or to the top sub-directory of
1231/// the hierarchy (in the above example, the returned TDirectory * always points
1232/// to "a").
1234TDirectory *TDirectoryFile::mkdir(const char *name, const char *title, Bool_t returnExistingDirectory)
1235{
1236 if (!name || !title || !name[0]) return nullptr;
1237 if (!title[0]) title = name;
1238 if (GetKey(name)) {
1239 if (returnExistingDirectory)
1240 return (TDirectoryFile*) GetDirectory(name);
1241 else {
1242 Error("mkdir","An object with name %s exists already",name);
1243 return nullptr;
1244 }
1245 }
1246 TDirectoryFile *newdir = nullptr;
1247 if (const char *slash = strchr(name,'/')) {
1248 TString workname(name, Long_t(slash-name));
1249 TDirectoryFile *tmpdir = nullptr;
1250 GetObject(workname.Data(), tmpdir);
1251 if (!tmpdir) {
1252 tmpdir = (TDirectoryFile*)mkdir(workname.Data(),title);
1253 if (!tmpdir) return nullptr;
1254 }
1255 if (!newdir) newdir = tmpdir;
1256 tmpdir->mkdir(slash+1);
1257 return newdir;
1258 }
1259
1260 TDirectory::TContext ctxt(this);
1261
1262 newdir = new TDirectoryFile(name, title, "", this);
1263
1264 return newdir;
1265}
1266
1267////////////////////////////////////////////////////////////////////////////////
1268/// Purge lowest key cycles in a directory.
1269///
1270/// By default, only the highest cycle of a key is kept. Keys for which
1271/// the "KEEP" flag has been set are not removed. See TKey::Keep().
1272/// NOTE: This does not reduce the size of a TFile--
1273/// the space is simply freed up to be overwritten.
1276{
1277 if (!IsWritable()) return;
1278
1279 TDirectory::TContext ctxt(this);
1280
1281 TKey *key;
1283
1284 while ((key = (TKey*)prev())) { // reverse loop on keys
1285 TKey *keyprev = (TKey*)GetListOfKeys()->Before(key);
1286 if (!keyprev) break;
1287 if (key->GetKeep() == 0) {
1288 if (strcmp(key->GetName(), keyprev->GetName()) == 0) {
1289 key->Delete(); // Remove from the file.
1290 delete key; // Remove from memory.
1291 }
1292 }
1293 }
1294 TFile *f = GetFile();
1295 if (fModified && f) {
1296 WriteKeys(); // Write new keys structure
1297 WriteDirHeader(); // Write new directory header
1298 f->WriteFree(); // Write new free segments list
1299 f->WriteHeader(); // Write new file header
1300 }
1301}
1302
1303////////////////////////////////////////////////////////////////////////////////
1304/// Read objects from a ROOT file directory into memory.
1305///
1306/// If an object is already in memory, the memory copy is deleted
1307/// and the object is again read from the file.
1308/// If opt=="dirs", only subdirectories will be read
1309/// If opt=="dirs*" complete directory tree will be read
1312{
1313 TDirectory::TContext ctxt(this);
1314
1315 TKey *key;
1316 TIter next(GetListOfKeys());
1317
1318 Bool_t readdirs = ((opt!=0) && ((strcmp(opt,"dirs")==0) || (strcmp(opt,"dirs*")==0)));
1319
1320 if (readdirs)
1321 while ((key = (TKey *) next())) {
1322
1323 //if (strcmp(key->GetClassName(),"TDirectory")!=0) continue;
1324 if (strstr(key->GetClassName(),"TDirectory")==0) continue;
1325
1326 TDirectory *dir = GetDirectory(key->GetName(), kTRUE, "ReadAll");
1327
1328 if ((dir!=0) && (strcmp(opt,"dirs*")==0)) dir->ReadAll("dirs*");
1329 }
1330 else
1331 while ((key = (TKey *) next())) {
1332 TObject *thing = GetList()->FindObject(key->GetName());
1333 if (thing) { delete thing; }
1334 key->ReadObj();
1335 }
1336}
1337
1338////////////////////////////////////////////////////////////////////////////////
1339/// Read the linked list of keys.
1340///
1341/// Every directory has a linked list (fKeys). This linked list has been
1342/// written on the file via WriteKeys as a single data record.
1343///
1344/// It is interesting to call this function in the following situation.
1345/// Assume another process1 is connecting this directory in Update mode
1346/// - Process1 is adding/updating objects in this directory
1347/// - You want to see the latest status from process1.
1348/// Example Process1:
1349/// ~~~{.cpp}
1350/// obj1.Write();
1351/// obj2.Write();
1352/// gDirectory->SaveSelf();
1353/// ~~~
1354///
1355/// Example Process2:
1356/// ~~~{.cpp}
1357/// gDirectory->ReadKeys();
1358/// obj1->Draw();
1359/// ~~~
1360/// This is an efficient way (without opening/closing files) to view
1361/// the latest updates of a file being modified by another process
1362/// as it is typically the case in a data acquisition system.
1365{
1366 if (!fFile || !fKeys) return 0;
1367
1368 if (!fFile->IsBinary())
1369 return fFile->DirReadKeys(this);
1370
1371 TDirectory::TContext ctxt(this);
1372
1373 char *buffer;
1374 if (forceRead) {
1375 fKeys->Delete();
1376 //In case directory was updated by another process, read new
1377 //position for the keys
1379 char *header = new char[nbytes];
1380 buffer = header;
1382 if ( fFile->ReadBuffer(buffer,nbytes) ) {
1383 // ReadBuffer return kTRUE in case of failure.
1384 delete [] header;
1385 return 0;
1386 }
1387 buffer += fNbytesName;
1388 Version_t versiondir;
1389 frombuf(buffer,&versiondir);
1390 fDatimeC.ReadBuffer(buffer);
1391 fDatimeM.ReadBuffer(buffer);
1392 frombuf(buffer, &fNbytesKeys);
1393 frombuf(buffer, &fNbytesName);
1394 if (versiondir > 1000) {
1395 frombuf(buffer, &fSeekDir);
1396 frombuf(buffer, &fSeekParent);
1397 frombuf(buffer, &fSeekKeys);
1398 } else {
1399 Int_t sdir,sparent,skeys;
1400 frombuf(buffer, &sdir); fSeekDir = (Long64_t)sdir;
1401 frombuf(buffer, &sparent); fSeekParent = (Long64_t)sparent;
1402 frombuf(buffer, &skeys); fSeekKeys = (Long64_t)skeys;
1403 }
1404 delete [] header;
1405 }
1406
1407 Int_t nkeys = 0;
1408 Long64_t fsize = fFile->GetSize();
1409 if ( fSeekKeys > 0) {
1410 TKey *headerkey = new TKey(fSeekKeys, fNbytesKeys, this);
1411 headerkey->ReadFile();
1412 buffer = headerkey->GetBuffer();
1413 headerkey->ReadKeyBuffer(buffer);
1414
1415 TKey *key;
1416 frombuf(buffer, &nkeys);
1417 for (Int_t i = 0; i < nkeys; i++) {
1418 key = new TKey(this);
1419 key->ReadKeyBuffer(buffer);
1420 if (key->GetSeekKey() < 64 || key->GetSeekKey() > fsize) {
1421 Error("ReadKeys","reading illegal key, exiting after %d keys",i);
1422 fKeys->Remove(key);
1423 nkeys = i;
1424 break;
1425 }
1426 if (key->GetSeekPdir() < 64 || key->GetSeekPdir() > fsize) {
1427 Error("ReadKeys","reading illegal key, exiting after %d keys",i);
1428 fKeys->Remove(key);
1429 nkeys = i;
1430 break;
1431 }
1432 fKeys->Add(key);
1433 }
1434 delete headerkey;
1435 }
1436
1437 return nkeys;
1438}
1439
1440
1441////////////////////////////////////////////////////////////////////////////////
1442/// Read object with keyname from the current directory
1443///
1444/// Read contents of object with specified name from the current directory.
1445/// First the key with keyname is searched in the current directory,
1446/// next the key buffer is deserialized into the object.
1447/// The object must have been created before via the default constructor.
1448/// See TObject::Write().
1450Int_t TDirectoryFile::ReadTObject(TObject *obj, const char *keyname)
1451{
1452 if (!fFile) { Error("ReadTObject","No file open"); return 0; }
1453 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
1454 if (!listOfKeys) {
1455 Error("ReadTObject", "Unexpected type of TDirectoryFile::fKeys!");
1456 return 0;
1457 }
1458
1459 if (const TList *keyList = listOfKeys->GetListForObject(keyname)) {
1460 for (auto key: TRangeDynCast<TKey>(*keyList)) {
1461 if (key && !strcmp(key->GetName(), keyname) ) {
1462 return key->Read(obj);
1463 }
1464 }
1465 }
1466
1467 Error("ReadTObject","Key not found");
1468 return 0;
1469}
1470
1471////////////////////////////////////////////////////////////////////////////////
1472/// Reset the TDirectory after its content has been merged into another
1473/// Directory.
1474///
1475/// This returns the TDirectoryFile object back to its state
1476/// before any data has been written to the file.
1477/// The object in the in-memory list are assumed to also have been reset.
1480{
1481 // There is nothing to reset in the base class (TDirectory) since
1482 // we do want to key the list of in-memory object as is.
1483 fModified = kFALSE;
1484 // Does not change: fWritable
1485 fDatimeC.Set();
1486 fDatimeM.Set();
1487 fNbytesKeys = 0; // updated when the keys are written
1488 fNbytesName = 0; // updated by Init
1489 // Does not change (user customization): fBufferSize;
1490 fSeekDir = 0; // updated by Init
1491 fSeekParent = 0; // updated by Init
1492 fSeekKeys = 0; // updated by Init
1493 // Does not change: fFile
1494 TKey *key = fKeys ? (TKey*)fKeys->FindObject(fName) : nullptr;
1495 TClass *cl = IsA();
1496 if (key) {
1497 cl = TClass::GetClass(key->GetClassName());
1498 }
1499 // NOTE: We should check that the content is really mergeable and in
1500 // the in-mmeory list, before deleting the keys.
1501 if (fKeys) {
1502 fKeys->Delete("slow");
1503 }
1504
1506
1507 // Do the same with the sub-directories.
1508 TIter next(GetList());
1509 TObject *idcur;
1510 while ((idcur = next())) {
1511 if (idcur->IsA() == TDirectoryFile::Class()) {
1512 ((TDirectoryFile*)idcur)->ResetAfterMerge(info);
1513 }
1514 }
1515
1516}
1517
1518////////////////////////////////////////////////////////////////////////////////
1519/// Removes subdirectory from the directory
1520///
1521/// When directory is deleted, all keys in all subdirectories will be
1522/// read first and deleted from file (if exists)
1523/// Equivalent call is Delete("name;*");
1525void TDirectoryFile::rmdir(const char *name)
1526{
1527 if (!name || (*name==0)) return;
1528
1529 TString mask(name);
1530 mask += ";*";
1531 Delete(mask);
1532}
1533
1534////////////////////////////////////////////////////////////////////////////////
1535/// Save recursively all directory keys and headers
1538{
1539 TDirectory::TContext ctxt(this);
1540
1541 SaveSelf();
1542
1543 // recursively save all sub-directories
1544 if (fList && fList->FirstLink()) {
1545 auto lnk = fList->FirstLink()->shared_from_this();
1546 while (lnk) {
1547 TObject *idcur = lnk->GetObject();
1548 if (idcur && idcur->InheritsFrom(TDirectoryFile::Class())) {
1549 TDirectoryFile *dir = (TDirectoryFile *)idcur;
1550 dir->Save();
1551 }
1552 lnk = lnk->NextSP();
1553 }
1554 }
1555}
1556
1557////////////////////////////////////////////////////////////////////////////////
1558/// Save object in filename.
1559///
1560/// If filename is 0 or "", a file with "objectname.root" is created.
1561/// The name of the key is the object name.
1562/// If the operation is successful, it returns the number of bytes written to the file
1563/// otherwise it returns 0.
1564/// By default a message is printed. Use option "q" to not print the message.
1565/// If filename contains ".json" extension, JSON representation of the object
1566/// will be created and saved in the text file. Such file can be used in
1567/// JavaScript ROOT (https://root.cern.ch/js/) to display object in web browser
1568/// When creating JSON file, option string may contain compression level from 0 to 3 (default 0)
1570Int_t TDirectoryFile::SaveObjectAs(const TObject *obj, const char *filename, Option_t *option) const
1571{
1572 if (!obj) return 0;
1573 TDirectory *dirsav = gDirectory;
1574 TString fname = filename;
1575 if (!filename || !filename[0]) {
1576 fname.Form("%s.root",obj->GetName());
1577 }
1578 Int_t nbytes = 0;
1579 if (fname.Index(".json") > 0) {
1580 nbytes = TBufferJSON::ExportToFile(fname, obj, option);
1581 } else {
1582 TFile *local = TFile::Open(fname.Data(),"recreate");
1583 if (!local) return 0;
1584 nbytes = obj->Write();
1585 delete local;
1586 if (dirsav) dirsav->cd();
1587 }
1588 TString opt = option;
1589 opt.ToLower();
1590 if (!opt.Contains("q")) {
1591 if (!gSystem->AccessPathName(fname.Data())) obj->Info("SaveAs", "ROOT file %s has been created", fname.Data());
1592 }
1593 return nbytes;
1594}
1595
1596////////////////////////////////////////////////////////////////////////////////
1597/// Save Directory keys and header
1598///
1599/// If the directory has been modified (fModified set), write the keys
1600/// and the directory header. This function assumes the cd is correctly set.
1601///
1602/// It is recommended to use this function in the following situation:
1603/// Assume a process1 using a directory in Update mode
1604/// - New objects or modified objects have been written to the directory.
1605/// - You do not want to close the file.
1606/// - You want your changes be visible from another process2 already connected
1607/// to this directory in read mode.
1608/// - Call this function.
1609/// - In process2, use TDirectoryFile::ReadKeys to refresh the directory.
1612{
1613 if (IsWritable() && (fModified || force) && fFile) {
1614 Bool_t dowrite = kTRUE;
1615 if (fFile->GetListOfFree())
1616 dowrite = fFile->GetListOfFree()->First() != nullptr;
1617 if (dowrite) {
1618 TDirectory *dirsav = gDirectory;
1619 if (dirsav != this) cd();
1620 WriteKeys(); //*-*- Write keys record
1621 WriteDirHeader(); //*-*- Update directory record
1622 if (dirsav && dirsav != this) dirsav->cd();
1623 }
1624 }
1625}
1626
1627////////////////////////////////////////////////////////////////////////////////
1628/// Set the default buffer size when creating new TKeys.
1629///
1630/// See also TDirectoryFile::GetBufferSize
1633{
1634 fBufferSize = bufsize;
1635}
1636
1637////////////////////////////////////////////////////////////////////////////////
1638/// Find the action to be executed in the dictionary of the parent class
1639/// and store the corresponding exec number into fBits.
1640///
1641/// This function searches a data member in the class of parent with an
1642/// offset corresponding to this.
1643/// If a comment "TEXEC:" is found in the comment field of the data member,
1644/// the function stores the exec identifier of the exec statement
1645/// following this keyword.
1648{
1649 Int_t offset = (char*)ref - (char*)parent;
1650 TClass *cl = parent->IsA();
1651 cl->BuildRealData(parent);
1653 TIter next(info->GetElements());
1654 TStreamerElement *element;
1655 while((element = (TStreamerElement*)next())) {
1656 if (element->GetOffset() != offset) continue;
1657 Int_t execid = element->GetExecID();
1658 if (execid > 0) ref->SetBit(execid << 8);
1659 return;
1660 }
1661}
1662
1663////////////////////////////////////////////////////////////////////////////////
1664/// Set the new value of fWritable recursively
1667{
1668 TDirectory::TContext ctxt(this);
1669
1670 fWritable = writable;
1671
1672 // recursively set all sub-directories
1673 if (fList) {
1674 TObject *idcur;
1675 TIter next(fList);
1676 while ((idcur = next())) {
1677 if (idcur->InheritsFrom(TDirectoryFile::Class())) {
1678 TDirectoryFile *dir = (TDirectoryFile*)idcur;
1679 dir->SetWritable(writable);
1680 }
1681 }
1682 }
1683}
1684
1685
1686////////////////////////////////////////////////////////////////////////////////
1687/// Return the size in bytes of the directory header
1690{
1691 Int_t nbytes = 22;
1692
1693 nbytes += fDatimeC.Sizeof();
1694 nbytes += fDatimeM.Sizeof();
1695 nbytes += fUUID.Sizeof();
1696 //assume that the file may be above 2 Gbytes if file version is > 4
1697 if (fFile && fFile->GetVersion() >= 40000) nbytes += 12;
1698 return nbytes;
1699}
1700
1701
1702////////////////////////////////////////////////////////////////////////////////
1703/// Stream a class object
1704
1705void TDirectoryFile::Streamer(TBuffer &b)
1706{
1707 Version_t v,version;
1708 if (b.IsReading()) {
1709 BuildDirectoryFile((TFile*)b.GetParent(), nullptr);
1710 if (fFile && fFile->IsWritable()) fWritable = kTRUE;
1711
1712 if (fFile && !fFile->IsBinary()) {
1713 Version_t R__v = b.ReadVersion(0, 0);
1714
1715 TClass* dirclass = (R__v < 5) ? TDirectory::Class() : TDirectoryFile::Class();
1716
1717 b.ClassBegin(dirclass, R__v);
1718
1719 TString sbuf;
1720
1721 b.ClassMember("CreateTime","TString");
1722 sbuf.Streamer(b);
1723 TDatime timeC(sbuf.Data());
1724 fDatimeC = timeC;
1725
1726 b.ClassMember("ModifyTime","TString");
1727 sbuf.Streamer(b);
1728 TDatime timeM(sbuf.Data());
1729 fDatimeM = timeM;
1730
1731 b.ClassMember("UUID","TString");
1732 sbuf.Streamer(b);
1733 TUUID id(sbuf.Data());
1734 fUUID = id;
1735
1736 b.ClassEnd(dirclass);
1737
1738 fSeekKeys = 0; // read keys later in the TKeySQL class
1739 } else {
1740 b >> version;
1741 fDatimeC.Streamer(b);
1742 fDatimeM.Streamer(b);
1743 b >> fNbytesKeys;
1744 b >> fNbytesName;
1745 if (version > 1000) {
1747 b >> fSeekDir;
1748 b >> fSeekParent;
1749 b >> fSeekKeys;
1750 } else {
1751 Int_t sdir,sparent,skeys;
1752 b >> sdir; fSeekDir = (Long64_t)sdir;
1753 b >> sparent; fSeekParent = (Long64_t)sparent;
1754 b >> skeys; fSeekKeys = (Long64_t)skeys;
1755 }
1756 v = version%1000;
1757 if (v == 2) {
1759 } else if (v > 2) {
1760 fUUID.Streamer(b);
1761 }
1762 }
1763 fList->UseRWLock();
1765 gROOT->GetUUIDs()->AddUUID(fUUID,this);
1766 if (fSeekKeys) ReadKeys();
1767 } else {
1768 if (fFile && !fFile->IsBinary()) {
1769 b.WriteVersion(TDirectoryFile::Class());
1770
1771 TString sbuf;
1772
1773 b.ClassBegin(TDirectoryFile::Class());
1774
1775 b.ClassMember("CreateTime","TString");
1776 sbuf = fDatimeC.AsSQLString();
1777 sbuf.Streamer(b);
1778
1779 b.ClassMember("ModifyTime","TString");
1780 fDatimeM.Set();
1781 sbuf = fDatimeM.AsSQLString();
1782 sbuf.Streamer(b);
1783
1784 b.ClassMember("UUID","TString");
1785 sbuf = fUUID.AsString();
1786 sbuf.Streamer(b);
1787
1788 b.ClassEnd(TDirectoryFile::Class());
1789 } else {
1790 version = TDirectoryFile::Class_Version();
1791 if (fFile && fFile->GetEND() > TFile::kStartBigFile) version += 1000;
1792 b << version;
1793 fDatimeC.Streamer(b);
1794 fDatimeM.Streamer(b);
1795 b << fNbytesKeys;
1796 b << fNbytesName;
1797 if (version > 1000) {
1798 b << fSeekDir;
1799 b << fSeekParent;
1800 b << fSeekKeys;
1801 } else {
1802 b << (Int_t)fSeekDir;
1803 b << (Int_t)fSeekParent;
1804 b << (Int_t)fSeekKeys;
1805 }
1806 fUUID.Streamer(b);
1807 if (version <=1000) for (Int_t i=0;i<3;i++) b << Int_t(0);
1808 }
1809 }
1810}
1811
1812////////////////////////////////////////////////////////////////////////////////
1813/// Write all objects in memory to disk.
1814///
1815/// Loop on all objects in memory (including subdirectories).
1816/// A new key is created in the keys linked list for each object.
1817/// For allowed options see TObject::Write().
1818/// The directory header info is rewritten on the directory header record.
1820Int_t TDirectoryFile::Write(const char *, Int_t opt, Int_t bufsize)
1821{
1822 if (!IsWritable()) return 0;
1823 TDirectory::TContext ctxt(this);
1824
1825 // Loop on all objects (including subdirs)
1826 TIter next(fList);
1827 TObject *obj;
1828 Int_t nbytes = 0;
1829 while ((obj=next())) {
1830 nbytes += obj->Write(0,opt,bufsize);
1831 }
1832 if (R__likely(!(opt & kOnlyPrepStep)))
1833 SaveSelf(kTRUE); // force save itself
1834
1835 return nbytes;
1836}
1837
1838////////////////////////////////////////////////////////////////////////////////
1839/// One can not save a const TDirectory object.
1841Int_t TDirectoryFile::Write(const char *n, Int_t opt, Int_t bufsize) const
1842{
1843 Error("Write const","A const TDirectory object should not be saved. We try to proceed anyway.");
1844 return const_cast<TDirectoryFile*>(this)->Write(n, opt, bufsize);
1845}
1846
1847////////////////////////////////////////////////////////////////////////////////
1848/// Write object obj to this directory.
1849///
1850/// The data structure corresponding to this object is serialized.
1851/// The corresponding buffer is written to this directory
1852/// with an associated key with name "name".
1853///
1854/// Writing an object to a file involves the following steps:
1855/// - Creation of a support TKey object in the directory. The TKey object
1856/// creates a TBuffer object.
1857/// - The TBuffer object is filled via the class::Streamer function.
1858/// - If the file is compressed (default) a second buffer is created to hold
1859/// the compressed buffer.
1860/// - Reservation of the corresponding space in the file by looking in the
1861/// TFree list of free blocks of the file.
1862/// - The buffer is written to the file.
1863///
1864/// By default, the buffersize will be taken from the average buffer size
1865/// of all objects written to the current file so far.
1866/// Use TDirectoryFile::SetBufferSize to force a given buffer size.
1867///
1868/// If a name is specified, it will be the name of the key.
1869/// If name is not given, the name of the key will be the name as returned
1870/// by obj->GetName().
1871///
1872/// The option can be a combination of:
1873/// - "SingleKey"
1874/// - "Overwrite"
1875/// - "WriteDelete"
1876/// Using the "Overwrite" option a previous key with the same name is
1877/// overwritten. The previous key is deleted before writing the new object.
1878/// Using the "WriteDelete" option a previous key with the same name is
1879/// deleted only after the new object has been written. This option
1880/// is safer than kOverwrite but it is slower.
1881/// The "SingleKey" option is only used by TCollection::Write() to write
1882/// a container with a single key instead of each object in the container
1883/// with its own key.
1884/// An object is read from this directory via TDirectoryFile::Get.
1885/// The function returns the total number of bytes written to the directory.
1886/// It returns 0 if the object cannot be written.
1887///
1888/// WARNING: avoid special characters like '^','$','.' in the name as they
1889/// are used by the regular expression parser (see TRegexp).
1891Int_t TDirectoryFile::WriteTObject(const TObject *obj, const char *name, Option_t *option, Int_t bufsize)
1892{
1893 TDirectory::TContext ctxt(this);
1894
1895 if (fFile==0) {
1896 const char *objname = "no name specified";
1897 if (name) objname = name;
1898 else if (obj) objname = obj->GetName();
1899 Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.",GetName(),objname);
1900 return 0;
1901 }
1902
1903 if (!fFile->IsWritable()) {
1905 // Do not print the error if the file already had a SysError.
1906 Error("WriteTObject","Directory %s is not writable", fFile->GetName());
1907 }
1908 return 0;
1909 }
1910
1911 if (!obj) return 0;
1912
1913 TString opt = option;
1914 opt.ToLower();
1915
1916 TKey *key=0, *oldkey=0;
1917 Int_t bsize = GetBufferSize();
1918 if (bufsize > 0) bsize = bufsize;
1919
1920 const char *oname;
1921 if (name && *name)
1922 oname = name;
1923 else
1924 oname = obj->GetName();
1925
1926 // Remove trailing blanks in object name
1927 Int_t nch = strlen(oname);
1928 char *newName = nullptr;
1929 if (nch && oname[nch-1] == ' ') {
1930 newName = new char[nch+1];
1931 strlcpy(newName,oname,nch+1);
1932 for (Int_t i=0;i<nch;i++) {
1933 if (newName[nch-i-1] != ' ') break;
1934 newName[nch-i-1] = 0;
1935 }
1936 oname = newName;
1937 }
1938
1939 if (opt.Contains("overwrite")) {
1940 //One must use GetKey. FindObject would return the lowest cycle of the key!
1941 //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
1942 key = GetKey(oname);
1943 if (key) {
1944 key->Delete();
1945 delete key;
1946 }
1947 }
1948 if (opt.Contains("writedelete")) {
1949 oldkey = GetKey(oname);
1950 }
1951 key = fFile->CreateKey(this, obj, oname, bsize);
1952 if (newName) delete [] newName;
1953
1954 if (!key->GetSeekKey()) {
1955 fKeys->Remove(key);
1956 delete key;
1957 if (bufsize) fFile->SetBufferSize(bufsize);
1958 return 0;
1959 }
1960 fFile->SumBuffer(key->GetObjlen());
1961 Int_t nbytes = key->WriteFile(0);
1963 if (bufsize) fFile->SetBufferSize(bufsize);
1964 return 0;
1965 }
1966 if (oldkey) {
1967 oldkey->Delete();
1968 delete oldkey;
1969 }
1970 if (bufsize) fFile->SetBufferSize(bufsize);
1971
1972 return nbytes;
1973}
1974
1975////////////////////////////////////////////////////////////////////////////////
1976/// Write object from pointer of class classname in this directory.
1977///
1978/// obj may not derive from TObject. See TDirectoryFile::WriteTObject for comments
1979///
1980/// ## Very important note
1981/// The value passed as 'obj' needs to be from a pointer to the type described by classname.
1982/// For example:
1983/// ~~~{.cpp}
1984/// TopClass *top;
1985/// BottomClass *bottom;
1986/// top = bottom;
1987/// ~~~
1988/// you can do:
1989/// ~~~{.cpp}
1990/// directory->WriteObjectAny(top,"top","name of object");
1991/// directory->WriteObjectAny(bottom,"bottom","name of object");
1992/// ~~~
1993/// <b>BUT YOU CAN NOT DO</b> the following since it will fail with multiple inheritance:
1994/// ~~~{.cpp}
1995/// directory->WriteObjectAny(top,"bottom","name of object");
1996/// ~~~
1997/// We <b>STRONGLY</b> recommend to use
1998/// ~~~{.cpp}
1999/// TopClass *top = ....;
2000/// directory->WriteObject(top,"name of object")
2001/// ~~~
2002/// See also remarks in TDirectoryFile::WriteTObject
2004Int_t TDirectoryFile::WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option, Int_t bufsize)
2005{
2006 TClass *cl = TClass::GetClass(classname);
2007 if (!cl) {
2008 TObject *info_obj = *(TObject**)obj;
2009 TVirtualStreamerInfo *info = dynamic_cast<TVirtualStreamerInfo*>(info_obj);
2010 if (!info) {
2011 Error("WriteObjectAny","Unknown class: %s",classname);
2012 return 0;
2013 } else {
2014 cl = info->GetClass();
2015 }
2016 }
2017 return WriteObjectAny(obj,cl,name,option,bufsize);
2018}
2019
2020////////////////////////////////////////////////////////////////////////////////
2021/// Write object of class with dictionary cl in this directory.
2022///
2023/// obj may not derive from TObject
2024/// To get the TClass* cl pointer, one can use
2025///
2026/// TClass *cl = TClass::GetClass("classname");
2027///
2028/// An alternative is to call the function WriteObjectAny above.
2029/// see TDirectoryFile::WriteTObject for comments
2031Int_t TDirectoryFile::WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option, Int_t bufsize)
2032{
2033 TDirectory::TContext ctxt(this);
2034
2035 if (!fFile) return 0;
2036
2037 if (!cl) {
2038 Error("WriteObject","Unknown type for %s, it can not be written.",name);
2039 return 0;
2040 }
2041
2042 if (!fFile->IsWritable()) {
2044 // Do not print the error if the file already had a SysError.
2045 Error("WriteObject","File %s is not writable", fFile->GetName());
2046 }
2047 return 0;
2048 }
2049
2050 if (!obj) return 0;
2051
2052 const char *className = cl->GetName();
2053 const char *oname;
2054 if (name && *name)
2055 oname = name;
2056 else
2057 oname = className;
2058
2059 if (cl && cl->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(cl->GetCollectionProxy())) {
2060 Error("WriteObjectAny",
2061 "The class requested (%s) for the key name \"%s\""
2062 " is an instance of an stl collection and does not have a compiled CollectionProxy."
2063 " Please generate the dictionary for this collection (%s). No data will be written.",
2064 className, oname, className);
2065 return 0;
2066 }
2067
2068 TKey *key, *oldkey = nullptr;
2069 Int_t bsize = GetBufferSize();
2070 if (bufsize > 0) bsize = bufsize;
2071
2072 TString opt = option;
2073 opt.ToLower();
2074
2075 // Remove trailing blanks in object name
2076 Int_t nch = strlen(oname);
2077 char *newName = nullptr;
2078 if (nch && oname[nch-1] == ' ') {
2079 newName = new char[nch+1];
2080 strlcpy(newName,oname,nch+1);
2081 for (Int_t i=0;i<nch;i++) {
2082 if (newName[nch-i-1] != ' ') break;
2083 newName[nch-i-1] = 0;
2084 }
2085 oname = newName;
2086 }
2087
2088 if (opt.Contains("overwrite")) {
2089 //One must use GetKey. FindObject would return the lowest cycle of the key!
2090 //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
2091 key = GetKey(oname);
2092 if (key) {
2093 key->Delete();
2094 delete key;
2095 }
2096 }
2097 if (opt.Contains("writedelete")) {
2098 oldkey = GetKey(oname);
2099 }
2100 key = fFile->CreateKey(this, obj, cl, oname, bsize);
2101 if (newName) delete [] newName;
2102
2103 if (!key->GetSeekKey()) {
2104 fKeys->Remove(key);
2105 delete key;
2106 return 0;
2107 }
2108 fFile->SumBuffer(key->GetObjlen());
2109 Int_t nbytes = key->WriteFile(0);
2110 if (fFile->TestBit(TFile::kWriteError)) return 0;
2111
2112 if (oldkey) {
2113 oldkey->Delete();
2114 delete oldkey;
2115 }
2116
2117 return nbytes;
2118}
2119
2120////////////////////////////////////////////////////////////////////////////////
2121/// Overwrite the Directory header record.
2124{
2125 TFile* f = GetFile();
2126 if (!f) return;
2127
2128 if (!f->IsBinary()) {
2129 fDatimeM.Set();
2130 f->DirWriteHeader(this);
2131 return;
2132 }
2133
2134 Int_t nbytes = TDirectoryFile::Sizeof(); //Warning ! TFile has a Sizeof()
2135 char *header = new char[nbytes];
2136 char *buffer = header;
2137 fDatimeM.Set();
2139 Long64_t pointer = fSeekDir + fNbytesName; // do not overwrite the name/title part
2140 fModified = kFALSE;
2141 f->Seek(pointer);
2142 f->WriteBuffer(header, nbytes);
2143 if (f->MustFlush()) f->Flush();
2144 delete [] header;
2145}
2146
2147////////////////////////////////////////////////////////////////////////////////
2148/// Write Keys linked list on the file.
2149///
2150/// The linked list of keys (fKeys) is written as a single data record
2153{
2154 TFile* f = GetFile();
2155 if (!f) return;
2156
2157 if (!f->IsBinary()) {
2158 f->DirWriteKeys(this);
2159 return;
2160 }
2161
2162//*-* Delete the old keys structure if it exists
2163 if (fSeekKeys != 0) {
2164 f->MakeFree(fSeekKeys, fSeekKeys + fNbytesKeys -1);
2165 }
2166//*-* Write new keys record
2167 TIter next(fKeys);
2168 TKey *key;
2169 Int_t nkeys = fKeys->GetSize();
2170 Int_t nbytes = sizeof nkeys; //*-* Compute size of all keys
2171 if (f->GetEND() > TFile::kStartBigFile) nbytes += 8;
2172 while ((key = (TKey*)next())) {
2173 nbytes += key->Sizeof();
2174 }
2175 TKey *headerkey = new TKey(fName,fTitle,IsA(),nbytes,this);
2176 if (headerkey->GetSeekKey() == 0) {
2177 delete headerkey;
2178 return;
2179 }
2180 char *buffer = headerkey->GetBuffer();
2181 next.Reset();
2182 tobuf(buffer, nkeys);
2183 while ((key = (TKey*)next())) {
2184 key->FillBuffer(buffer);
2185 }
2186
2187 fSeekKeys = headerkey->GetSeekKey();
2188 fNbytesKeys = headerkey->GetNbytes();
2189 headerkey->WriteFile();
2190 delete headerkey;
2191}
void frombuf(char *&buf, Bool_t *x)
Definition: Bytes.h:278
void tobuf(char *&buf, Bool_t x)
Definition: Bytes.h:55
void Class()
Definition: Class.C:29
#define R__likely(expr)
Definition: RConfig.hxx:598
#define SafeDelete(p)
Definition: RConfig.hxx:536
#define b(i)
Definition: RSha256.hxx:100
#define f(i)
Definition: RSha256.hxx:104
const Ssiz_t kNPOS
Definition: RtypesCore.h:124
int Int_t
Definition: RtypesCore.h:45
short Version_t
Definition: RtypesCore.h:65
unsigned int UInt_t
Definition: RtypesCore.h:46
const Bool_t kFALSE
Definition: RtypesCore.h:101
long Long_t
Definition: RtypesCore.h:54
bool Bool_t
Definition: RtypesCore.h:63
short Short_t
Definition: RtypesCore.h:39
long long Long64_t
Definition: RtypesCore.h:80
const Bool_t kTRUE
Definition: RtypesCore.h:100
const char Option_t
Definition: RtypesCore.h:66
#define BIT(n)
Definition: Rtypes.h:85
#define ClassImp(name)
Definition: Rtypes.h:364
const Bool_t kIterBackward
Definition: TCollection.h:43
const Int_t kMaxLen
const UInt_t kIsBigFile
#define gDirectory
Definition: TDirectory.h:348
#define gFile
Definition: TFile.h:343
XFontStruct * id
Definition: TGX11.cxx:109
char name[80]
Definition: TGX11.cxx:110
Int_t gDebug
Definition: TROOT.cxx:592
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:61
#define gROOT
Definition: TROOT.h:404
R__EXTERN TSystem * gSystem
Definition: TSystem.h:559
#define R__LOCKGUARD(mutex)
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:37
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition: TBufferFile.h:47
void MapObject(const TObject *obj, UInt_t offset=1) override
Add object to the fMap container.
Definition: TBufferIO.cxx:163
void ResetMap() override
Delete existing fMap and reset map counter.
Definition: TBufferIO.cxx:288
static Int_t ExportToFile(const char *filename, const TObject *obj, const char *option=nullptr)
Convert object into JSON and store in text file Returns size of the produce file Used in TObject::Sav...
Buffer base class used for serializing objects.
Definition: TBuffer.h:43
@ kWrite
Definition: TBuffer.h:73
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:93
void SetReadMode()
Set buffer in read mode.
Definition: TBuffer.cxx:302
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition: TClass.cxx:2018
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5931
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition: TClass.cxx:4592
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2884
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2955
virtual bool UseRWLock()
Set this collection to use a RW lock upon access, making it thread safe.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:184
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:37
void FillBuffer(char *&buffer)
Encode Date/Time into buffer, used by I/O system.
Definition: TDatime.cxx:229
const char * AsSQLString() const
Return the date & time in SQL compatible string format, like: 1997-01-15 20:16:28.
Definition: TDatime.cxx:152
Int_t Sizeof() const
Definition: TDatime.h:81
void Set()
Set Date/Time to current time as reported by the system.
Definition: TDatime.cxx:289
void ReadBuffer(char *&buffer)
Decode Date/Time from output buffer, used by I/O system.
Definition: TDatime.cxx:278
A ROOT file is structured in Directories (like a file system).
virtual ~TDirectoryFile()
Destructor.
void SetBufferSize(Int_t bufsize) override
Set the default buffer size when creating new TKeys.
void SetTRefAction(TObject *ref, TObject *parent) override
Find the action to be executed in the dictionary of the parent class and store the corresponding exec...
void Close(Option_t *option="") override
Delete all objects from memory and directory structure itself.
TFile * fFile
Pointer to current file in memory.
void Browse(TBrowser *b) override
Browse the content of the directory.
void Append(TObject *obj, Bool_t replace=kFALSE) override
Append object to this directory.
void SaveSelf(Bool_t force=kFALSE) override
Save Directory keys and header.
Bool_t IsWritable() const override
void Delete(const char *namecycle="") override
Delete Objects or/and keys in a directory.
virtual void ResetAfterMerge(TFileMergeInfo *)
Reset the TDirectory after its content has been merged into another Directory.
Int_t AppendKey(TKey *key) override
Insert key in the linked list of keys of this directory.
Int_t ReadKeys(Bool_t forceRead=kTRUE) override
Read the linked list of keys.
TDatime fDatimeM
Date and time of last modification.
void * GetObjectUnchecked(const char *namecycle) override
Return pointer to object identified by namecycle.
TKey * FindKey(const char *keyname) const override
Find key with name keyname in the current directory.
TKey * GetKey(const char *name, Short_t cycle=9999) const override
Return pointer to key with name,cycle.
void * GetObjectChecked(const char *namecycle, const char *classname) override
See documentation of TDirectoryFile::GetObjectCheck(const char *namecycle, const TClass *cl)
void InitDirectoryFile(TClass *cl=nullptr)
Initialize the key associated with this directory (and the related data members.
void Purge(Short_t nkeep=1) override
Purge lowest key cycles in a directory.
void Save() override
Save recursively all directory keys and headers.
TObject * FindObjectAnyFile(const char *name) const override
Scan the memory lists of all files for an object with name.
Int_t fNbytesKeys
Number of bytes for the keys.
Bool_t fModified
True if directory has been modified.
TDirectory * mkdir(const char *name, const char *title="", Bool_t returnExistingDirectory=kFALSE) override
Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...".
Bool_t cd(const char *path=nullptr) override
Change current directory to "this" directory.
TList * GetListOfKeys() const override
void CleanTargets()
Clean the pointers to this object (gDirectory, TContext, etc.)
TObject * FindObjectAny(const char *name) const override
Find object by name in the list of memory objects of the current directory or its sub-directories.
Long64_t fSeekKeys
Location of Keys record on file.
void WriteKeys() override
Write Keys linked list on the file.
TFile * GetFile() const override
Int_t fBufferSize
Default buffer size to create new TKeys.
Int_t Sizeof() const override
Return the size in bytes of the directory header.
TObject * CloneObject(const TObject *obj, Bool_t autoadd=kTRUE) override
Make a clone of an object using the Streamer facility.
TDirectory * GetDirectory(const char *apath, Bool_t printError=false, const char *funcname="GetDirectory") override
Find a directory named "apath".
Long64_t fSeekParent
Location of parent directory on file.
Int_t WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option="", Int_t bufsize=0) override
Write object from pointer of class classname in this directory.
void BuildDirectoryFile(TFile *motherFile, TDirectory *motherDir)
Initialise directory to defaults.
void rmdir(const char *name) override
Removes subdirectory from the directory.
Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsize=0) override
Write all objects in memory to disk.
Long64_t fSeekDir
Location of directory on file.
Int_t fNbytesName
Number of bytes in TNamed at creation time.
TDatime fDatimeC
Date and time when directory is created.
Bool_t fWritable
True if directory is writable.
Int_t WriteTObject(const TObject *obj, const char *name=nullptr, Option_t *option="", Int_t bufsize=0) override
Write object obj to this directory.
Int_t ReadTObject(TObject *obj, const char *keyname) override
Read object with keyname from the current directory.
TFile * OpenFile(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0) override
Interface to TFile::Open.
Int_t GetBufferSize() const override
Return the buffer size to create new TKeys.
Int_t SaveObjectAs(const TObject *obj, const char *filename="", Option_t *option="") const override
Save object in filename.
TObject * Get(const char *namecycle) override
Return pointer to object identified by namecycle.
TDirectoryFile()
Default TDirectoryFile constructor.
TKey * FindKeyAny(const char *keyname) const override
Find key with name keyname in the current directory or its subdirectories.
void FillBuffer(char *&buffer) override
Encode directory header into output buffer.
void WriteDirHeader() override
Overwrite the Directory header record.
void SetWritable(Bool_t writable=kTRUE) override
Set the new value of fWritable recursively.
void ReadAll(Option_t *option="") override
Read objects from a ROOT file directory into memory.
TList * fKeys
Pointer to keys list in memory.
void ls(Option_t *option="") const override
List Directory contents.
TDirectory::TContext keeps track and restore the current directory.
Definition: TDirectory.h:89
Describe directory structure in memory.
Definition: TDirectory.h:45
void Delete(const char *namecycle="") override
Delete Objects or/and keys in a directory.
Definition: TDirectory.cxx:660
virtual TList * GetList() const
Definition: TDirectory.h:213
virtual Int_t AppendKey(TKey *)
Definition: TDirectory.h:176
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
Definition: TDirectory.cxx:407
virtual void ReadAll(Option_t *="")
Definition: TDirectory.h:237
virtual TObject * Get(const char *namecycle)
Return pointer to object identified by namecycle.
Definition: TDirectory.cxx:814
void CleanTargets()
Clean the pointers to this object (gDirectory, TContext, etc.).
Definition: TDirectory.cxx:253
virtual void Append(TObject *obj, Bool_t replace=kFALSE)
Append object to this directory.
Definition: TDirectory.cxx:191
static void DecodeNameCycle(const char *namecycle, char *name, Short_t &cycle, const size_t namesize=0)
Decode a namecycle "aap;2" into name "aap" and cycle "2".
virtual TFile * GetFile() const
Definition: TDirectory.h:211
virtual TKey * GetKey(const char *, Short_t=9999) const
Definition: TDirectory.h:212
TUUID fUUID
Definition: TDirectory.h:139
TDirectory * GetMotherDir() const
Definition: TDirectory.h:216
TObject * fMother
Definition: TDirectory.h:137
void GetObject(const char *namecycle, T *&ptr)
Get an object with proper type checking.
Definition: TDirectory.h:203
virtual void * GetObjectChecked(const char *namecycle, const char *classname)
See documentation of TDirectory::GetObjectCheck(const char *namecycle, const TClass *cl)
Definition: TDirectory.cxx:877
TList * fList
Definition: TDirectory.h:138
virtual TKey * FindKeyAny(const char *) const
Definition: TDirectory.h:189
virtual Bool_t cd(const char *path=nullptr)
Change current directory to "this" directory.
Definition: TDirectory.cxx:504
virtual TObject * FindObjectAny(const char *name) const
Find object by name in the list of memory objects of the current directory or its sub-directories.
Definition: TDirectory.cxx:744
Streamer around an arbitrary STL like container, which implements basic container functionality.
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition: TFile.h:54
virtual void Seek(Long64_t offset, ERelativeTo pos=kBeg)
Seek to a specific position in the file. Pos it either kBeg, kCur or kEnd.
Definition: TFile.cxx:2200
Int_t GetVersion() const
Definition: TFile.h:237
Bool_t IsBinary() const
Definition: TFile.h:251
@ kStartBigFile
Definition: TFile.h:192
virtual Int_t DirReadKeys(TDirectory *)
Definition: TFile.h:167
TList * GetListOfFree() const
Definition: TFile.h:229
Int_t GetBestBuffer() const
Return the best buffer size of objects on this file.
Definition: TFile.cxx:1113
virtual TKey * CreateKey(TDirectory *mother, const TObject *obj, const char *name, Int_t bufsize)
Creates key for object and converts data to buffer.
Definition: TFile.cxx:986
virtual Long64_t GetSize() const
Returns the current file size.
Definition: TFile.cxx:1275
virtual Long64_t GetEND() const
Definition: TFile.h:223
void SumBuffer(Int_t bufsize)
Increment statistics for buffer sizes of objects in this file.
Definition: TFile.cxx:2343
static TFile *& CurrentFile()
Return the current ROOT file if any.
Definition: TFile.cxx:1006
virtual const TUrl * GetEndpointUrl() const
Definition: TFile.h:227
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition: TFile.cxx:4011
@ kReproducible
Definition: TFile.h:189
@ kWriteError
Definition: TFile.h:186
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition: TFile.cxx:1696
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition: THashList.h:34
void Reset()
Definition: TCollection.h:254
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:28
virtual Long64_t GetSeekKey() const
Definition: TKey.h:90
virtual void FillBuffer(char *&buffer)
Encode key header into output buffer.
Definition: TKey.cxx:601
virtual void Delete(Option_t *option="")
Delete an object from the file.
Definition: TKey.cxx:538
Int_t GetKeylen() const
Definition: TKey.h:85
Int_t GetObjlen() const
Definition: TKey.h:88
Int_t GetNbytes() const
Definition: TKey.h:87
Short_t GetKeep() const
Returns the "KEEP" status.
Definition: TKey.cxx:593
virtual const char * GetClassName() const
Definition: TKey.h:76
virtual Bool_t ReadFile()
Read the key structure from the file.
Definition: TKey.cxx:1265
virtual Int_t WriteFile(Int_t cycle=1, TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1450
void ReadKeyBuffer(char *&buffer)
Decode input buffer.
Definition: TKey.cxx:1222
virtual Long64_t GetSeekPdir() const
Definition: TKey.h:91
void SetMotherDir(TDirectory *dir)
Definition: TKey.h:113
virtual void ls(Bool_t current) const
List Key contents.
Definition: TKey.cxx:694
Short_t GetCycle() const
Return cycle number associated to this key.
Definition: TKey.cxx:577
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition: TKey.cxx:750
virtual char * GetBuffer() const
Definition: TKey.h:79
virtual Int_t Sizeof() const
Return the size in bytes of the key header structure.
Definition: TKey.cxx:1336
A doubly linked list.
Definition: TList.h:44
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:822
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:578
virtual TObjLink * FirstLink() const
Definition: TList.h:108
virtual void AddBefore(const TObject *before, TObject *obj)
Insert object before object before in the list.
Definition: TList.cxx:196
virtual TObject * Before(const TObject *obj) const
Returns the object before object obj.
Definition: TList.cxx:371
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:470
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:659
This class implements a shared memory region mapped to a file.
Definition: TMapFile.h:25
void Add(const TObject *obj, const char *name="")
Add an object to the list of objects to be stored in shared memory.
Definition: TMapFile.cxx:597
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
TString fTitle
Definition: TNamed.h:33
TString fName
Definition: TNamed.h:32
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Mother of all ROOT objects.
Definition: TObject.h:37
virtual Bool_t IsFolder() const
Returns kTRUE in case object contains browsable objects (like containers or lists of other objects).
Definition: TObject.cxx:475
virtual Int_t Write(const char *name=0, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition: TObject.cxx:798
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:359
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:130
@ kOnlyPrepStep
Used to request that the class specific implementation of TObject::Write just prepare the objects to ...
Definition: TObject.h:102
virtual void Delete(Option_t *option="")
Delete this object.
Definition: TObject.cxx:171
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:696
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:445
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:893
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:921
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition: TObject.cxx:494
void ResetBit(UInt_t f)
Definition: TObject.h:186
@ kCanDelete
if object in a list can be deleted
Definition: TObject.h:58
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition: TObject.h:61
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:867
static Int_t IncreaseDirLevel()
Increase the indentation level for ls().
Definition: TROOT.cxx:2795
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition: TROOT.cxx:2803
static Int_t DecreaseDirLevel()
Decrease the indentation level for ls().
Definition: TROOT.cxx:2699
Regular expression class.
Definition: TRegexp.h:31
Int_t GetOffset() const
virtual Int_t GetExecID() const
Returns the TExec id for the EXEC instruction in the comment field of a TRef data member.
Describes a persistent version of a class.
Definition: TStreamerInfo.h:39
TObjArray * GetElements() const
Basic string class.
Definition: TString.h:136
Ssiz_t Length() const
Definition: TString.h:410
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1150
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1131
const char * Data() const
Definition: TString.h:369
@ kBoth
Definition: TString.h:267
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:615
Bool_t IsNull() const
Definition: TString.h:407
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2314
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:624
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:639
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition: TSystem.cxx:1296
This class defines a UUID (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDent...
Definition: TUUID.h:42
const char * AsString() const
Return UUID as string. Copy string immediately since it will be reused.
Definition: TUUID.cxx:570
Int_t Sizeof() const
Definition: TUUID.h:85
void FillBuffer(char *&buffer)
Stream UUID into output buffer.
Definition: TUUID.cxx:274
void StreamerV1(TBuffer &b)
Stream UUID from input buffer.
Definition: TUUID.cxx:308
Abstract Interface class describing Streamer information for one class.
virtual TClass * GetClass() const =0
const Int_t n
Definition: legend1.C:16
void(* DirAutoAdd_t)(void *, TDirectory *)
Definition: Rtypes.h:113
static constexpr double s
Definition: first.py:1
TCanvas * slash()
Definition: slash.C:1