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