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 result = GetDirectory(s+1,printError,funcname);
484 delete [] path;
485 return result;
486 }
487 }
488 if (!f && !strcmp(gROOT->GetName(), path)) f = gROOT;
489 if (s) *s = ':';
490 if (f) {
491 result = f;
492 if (s && *(s+1)) result = f->GetDirectory(s+1,printError,funcname);
493 delete [] path; return result;
494 } else {
495 if (printError) Error(funcname, "No such file %s", path);
496 delete [] path; return nullptr;
497 }
498 }
499
500 // path starts with a slash (assumes current file)
501 if (path[0] == '/') {
502 TDirectory *td = fFile;
503 if (!fFile) td = gROOT;
504 result = td->GetDirectory(path+1,printError,funcname);
505 delete [] path; return result;
506 }
507
508 TDirectoryFile *obj;
509 char *slash = (char*)strchr(path,'/');
510 if (!slash) { // we are at the lowest level
511 if (!strcmp(path, "..")) {
512 result = GetMotherDir();
513 delete [] path; return result;
514 }
515 GetObject(path,obj);
516 if (!obj) {
517 if (printError) Error(funcname,"Unknown directory %s", path);
518 delete [] path; return nullptr;
519 }
520
521 delete [] path; return obj;
522 }
523
524 TString subdir(path);
525 slash = (char*)strchr(subdir.Data(),'/');
526 *slash = 0;
527 //Get object with path from current directory/file
528 if (!strcmp(subdir, "..")) {
529 TDirectory* mom = GetMotherDir();
530 if (mom)
531 result = mom->GetDirectory(slash+1,printError,funcname);
532 delete [] path; return result;
533 }
534 GetObject(subdir,obj);
535 if (!obj) {
536 if (printError) Error(funcname,"Unknown directory %s", subdir.Data());
537 delete [] path; return nullptr;
538 }
539
540 result = ((TDirectory*)obj)->GetDirectory(slash+1,printError,funcname);
541 delete [] path; return result;
542}
543
544////////////////////////////////////////////////////////////////////////////////
545/// Delete all objects from memory and directory structure itself.
548{
549 if (!fList || !fSeekDir) {
550 return;
551 }
552
553 // Save the directory key list and header
554 Save();
555
556 Bool_t nodelete = option ? (!strcmp(option, "nodelete") ? kTRUE : kFALSE) : kFALSE;
557
558 if (!nodelete) {
559 Bool_t fast = kTRUE;
560 TObjLink *lnk = fList->FirstLink();
561 while (lnk) {
562 if (lnk->GetObject()->IsA() == TDirectoryFile::Class()) {fast = kFALSE;break;}
563 lnk = lnk->Next();
564 }
565 // Delete objects from directory list, this in turn, recursively closes all
566 // sub-directories (that were allocated on the heap)
567 // if this dir contains subdirs, we must use the slow option for Delete!
568 // we must avoid "slow" as much as possible, in particular Delete("slow")
569 // with a large number of objects (eg >10^5) would take for ever.
570 {
571 if (fast) fList->Delete();
572 else fList->Delete("slow");
573 }
574 }
575
576 // Delete keys from key list (but don't delete the list header)
577 if (fKeys) {
578 fKeys->Delete("slow");
579 }
580
582}
583
584////////////////////////////////////////////////////////////////////////////////
585/// Delete Objects or/and keys in a directory
586///
587/// Properties of the namecycle string:
588/// - namecycle has the format name;cycle
589/// - namecycle = "" is same as namecycle ="T*"
590/// - name = * means all
591/// - cycle = * means all cycles (memory and keys)
592/// - cycle = "" or cycle = 9999 ==> apply to a memory object
593/// When name=* use T* to delete subdirectories also
594///
595/// To delete one directory, you must specify the directory cycle,
596/// eg. file.Delete("dir1;1");
597///
598/// Examples:
599/// | Pattern | Description |
600/// |---------|-------------|
601/// | foo | delete object named foo in memory |
602/// | foo* | delete all objects with a name starting with foo |
603/// | foo;1 | delete cycle 1 of foo on file |
604/// | foo;* | delete all cycles of foo on file and also from memory |
605/// | *;2 | delete all objects on file having the cycle 2 |
606/// | *;* | delete all objects from memory and file |
607/// | T*;* | delete all objects from memory and file and all subdirectories |
608///
609/// ## WARNING
610/// If the key to be deleted contains special characters ("+","^","?", etc
611/// that have a special meaning for the regular expression parser (see TRegexp)
612/// then you must specify 2 backslash characters to escape the regular expression.
613/// For example, if the key to be deleted is namecycle = "C++", you must call
614///
615/// mydir.Delete("C\\+\\+"));
616///
618void TDirectoryFile::Delete(const char *namecycle)
619{
620 if (gDebug)
621 Info("Delete","Call for this = %s namecycle = %s",
622 GetName(), (namecycle ? namecycle : "null"));
623
624 TDirectory::TContext ctxt(this);
625 Short_t cycle;
626 char name[kMaxLen];
627 const char *nmcy = (namecycle) ? namecycle : "";
628 DecodeNameCycle(nmcy, name, cycle, kMaxLen);
629
630 Int_t deleteall = 0;
631 Int_t deletetree = 0;
632 if(strcmp(name,"*") == 0) deleteall = 1;
633 if(strcmp(name,"*T") == 0){ deleteall = 1; deletetree = 1;}
634 if(strcmp(name,"T*") == 0){ deleteall = 1; deletetree = 1;}
635 if(namecycle==0 || !namecycle[0]){ deleteall = 1; deletetree = 1;}
636 TRegexp re(name,kTRUE);
637 TString s;
638 Int_t deleteOK = 0;
639
640//*-*---------------------Case of Object in memory---------------------
641// ========================
642 if (cycle >= 9999 ) {
643 TNamed *idcur;
644 TIter next(fList);
645 while ((idcur = (TNamed *) next())) {
646 deleteOK = 0;
647 s = idcur->GetName();
648 if (deleteall || s.Index(re) != kNPOS) {
649 deleteOK = 1;
650 if (idcur->IsA() == TDirectoryFile::Class()) {
651 deleteOK = 2;
652 if (!deletetree && deleteall) deleteOK = 0;
653 }
654 }
655 if (deleteOK != 0) {
656 fList->Remove(idcur);
657 if (deleteOK==2) {
658 // read subdirectories to correctly delete them
659 if (deletetree)
660 ((TDirectory*) idcur)->ReadAll("dirs");
661 idcur->Delete(deletetree ? "T*;*" : "*");
662 delete idcur;
663 } else
664 idcur->Delete(name);
665 }
666 }
667// if (deleteOK == 2) {
668// Info("Delete","Dir:%lx %s", fList->FindObject(name), name);
669// delete fList->FindObject(name); //deleting a TDirectory
670// }
671 }
672//*-*---------------------Case of Key---------------------
673// ===========
674 if (cycle != 9999 ) {
675 if (IsWritable()) {
676 TKey *key;
677 TIter nextkey(GetListOfKeys());
678 while ((key = (TKey *) nextkey())) {
679 deleteOK = 0;
680 s = key->GetName();
681 if (deleteall || s.Index(re) != kNPOS) {
682 if (cycle == key->GetCycle()) deleteOK = 1;
683 if (cycle > 9999) deleteOK = 1;
684 //if (!strcmp(key->GetClassName(),"TDirectory")) {
685 if (strstr(key->GetClassName(),"TDirectory")) {
686 deleteOK = 2;
687 if (!deletetree && deleteall) deleteOK = 0;
688 if (cycle == key->GetCycle()) deleteOK = 2;
689 }
690 }
691 if (deleteOK) {
692 if (deleteOK==2) {
693 // read directory with subdirectories to correctly delete and free key structure
694 TDirectory* dir = GetDirectory(key->GetName(), kTRUE, "Delete");
695 if (dir!=0) {
696 dir->Delete("T*;*");
697 fList->Remove(dir);
698 delete dir;
699 }
700 }
701
702 key->Delete();
703 fKeys->Remove(key);
705 delete key;
706 }
707 }
708 TFile* f = GetFile();
709 if (fModified && (f!=0)) {
710 WriteKeys(); //*-* Write new keys structure
711 WriteDirHeader(); //*-* Write new directory header
712 f->WriteFree(); //*-* Write new free segments list
713 f->WriteHeader(); //*-* Write new file header
714 }
715 }
716 }
717}
718
719////////////////////////////////////////////////////////////////////////////////
720/// Encode directory header into output buffer
722void TDirectoryFile::FillBuffer(char *&buffer)
723{
724 Version_t version = TDirectoryFile::Class_Version();
728 {
729 // One of the address is larger than 2GB we need to use longer onfile
730 // integer, thus we increase the version number.
731 // Note that fSeekDir and fSeekKey are not necessarily correlated, if
732 // some object are 'removed' from the file and the holes are reused.
733 version += 1000;
734 }
735 tobuf(buffer, version);
736 const bool reproducible = TestBit(TFile::kReproducible) || (fFile && fFile->TestBit(TFile::kReproducible));
737 if (reproducible) {
738 TDatime((UInt_t) 1).FillBuffer(buffer);
739 TDatime((UInt_t) 1).FillBuffer(buffer);
740 } else {
741 fDatimeC.FillBuffer(buffer);
742 fDatimeM.FillBuffer(buffer);
743 }
744 tobuf(buffer, fNbytesKeys);
745 tobuf(buffer, fNbytesName);
746 if (version > 1000) {
747 tobuf(buffer, fSeekDir);
748 tobuf(buffer, fSeekParent);
749 tobuf(buffer, fSeekKeys);
750 } else {
751 tobuf(buffer, (Int_t)fSeekDir);
752 tobuf(buffer, (Int_t)fSeekParent);
753 tobuf(buffer, (Int_t)fSeekKeys);
754 }
755 if (reproducible)
756 TUUID("00000000-0000-0000-0000-000000000000").FillBuffer(buffer);
757 else
758 fUUID.FillBuffer(buffer);
759 if (fFile && fFile->GetVersion() < 40000) return;
760 if (version <=1000) for (Int_t i=0;i<3;i++) tobuf(buffer,Int_t(0));
761}
762
763////////////////////////////////////////////////////////////////////////////////
764/// Find key with name keyname in the current directory
766TKey *TDirectoryFile::FindKey(const char *keyname) const
767{
768 Short_t cycle;
769 char name[kMaxLen];
770
771 DecodeNameCycle(keyname, name, cycle, kMaxLen);
772 return GetKey(name,cycle);
773}
774
775////////////////////////////////////////////////////////////////////////////////
776/// Find key with name keyname in the current directory or
777/// its subdirectories.
778///
779/// NOTE: that If a key is found, the directory containing the key becomes
780/// the current directory
782TKey *TDirectoryFile::FindKeyAny(const char *keyname) const
783{
784 TDirectory *dirsav = gDirectory;
785 Short_t cycle;
786 char name[kMaxLen];
787
788 DecodeNameCycle(keyname, name, cycle, kMaxLen);
789
790 TIter next(GetListOfKeys());
791 TKey *key;
792 while ((key = (TKey *) next())) {
793 if (!strcmp(name, key->GetName()))
794 if ((cycle == 9999) || (cycle >= key->GetCycle())) {
795 const_cast<TDirectoryFile*>(this)->cd(); // may be we should not make cd ???
796 return key;
797 }
798 }
799 //try with subdirectories
800 next.Reset();
801 while ((key = (TKey *) next())) {
802 //if (!strcmp(key->GetClassName(),"TDirectory")) {
803 if (strstr(key->GetClassName(),"TDirectory")) {
804 TDirectory* subdir =
805 const_cast<TDirectoryFile*>(this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
806 TKey *k = subdir ? subdir->FindKeyAny(keyname) : nullptr;
807 if (k) return k;
808 }
809 }
810 if (dirsav) dirsav->cd();
811 return nullptr;
812}
813
814////////////////////////////////////////////////////////////////////////////////
815/// Find object by name in the list of memory objects of the current
816/// directory or its sub-directories.
817///
818/// After this call the current directory is not changed.
819/// To automatically set the current directory where the object is found,
820/// use FindKeyAny(aname)->ReadObj().
822TObject *TDirectoryFile::FindObjectAny(const char *aname) const
823{
824 //object may be already in the list of objects in memory
826 if (obj) return obj;
827
828 TDirectory *dirsav = gDirectory;
829 Short_t cycle;
830 char name[kMaxLen];
831
832 DecodeNameCycle(aname, name, cycle, kMaxLen);
833
834 TIter next(GetListOfKeys());
835 TKey *key;
836 //may be a key in the current directory
837 while ((key = (TKey *) next())) {
838 if (!strcmp(name, key->GetName())) {
839 if (cycle == 9999) return key->ReadObj();
840 if (cycle >= key->GetCycle()) return key->ReadObj();
841 }
842 }
843 //try with subdirectories
844 next.Reset();
845 while ((key = (TKey *) next())) {
846 //if (!strcmp(key->GetClassName(),"TDirectory")) {
847 if (strstr(key->GetClassName(),"TDirectory")) {
848 TDirectory* subdir =
849 ((TDirectory*)this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
850 TKey *k = subdir ? subdir->FindKeyAny(aname) : nullptr;
851 if (k) { if (dirsav) dirsav->cd(); return k->ReadObj();}
852 }
853 }
854 if (dirsav) dirsav->cd();
855 return nullptr;
856}
857
858////////////////////////////////////////////////////////////////////////////////
859/// Return pointer to object identified by namecycle.
860///
861/// Properties:
862/// - namecycle has the format name;cycle
863/// - name = * is illegal, cycle = * is illegal
864/// - cycle = "" or cycle = 9999 ==> apply to a memory object
865///
866/// Examples:
867/// | Pattern | Explanation |
868/// |---------|-------------|
869/// | foo | get object named foo in memory if object is not in memory, try with highest cycle from file |
870/// | foo;1 | get cycle 1 of foo on file |
871///
872/// The retrieved object should in principle derive from TObject.
873/// If not, the function TDirectoryFile::Get<T> should be called.
874/// However, this function will still work for a non-TObject, provided that
875/// the calling application cast the return type to the correct type (which
876/// is the actual type of the object).
877///
878/// ### The Get<T> Method
879/// The method Get<T> offers better protection and avoids the need for any
880/// cast:
881/// ~~~{.cpp}
882/// auto objPtr = directory->Get<MyClass>("some object");
883/// if (objPtr) { ... the object exist and inherits from MyClass ... }
884/// ~~~
885///
886/// ### Very important note about inheritance
887/// In case the class of this object derives from TObject but not
888/// as a first inheritance, one must use dynamic_cast<>().
889///
890/// #### Example 1 - Normal case:
891///
892/// class MyClass : public TObject, public AnotherClass
893///
894/// then on return, one can adopt a C style cast:
895///
896/// auto objPtr = (MyClass*)directory->Get("some object of MyClass");
897///
898/// #### Example 2 - Special case:
899///
900/// class MyClass : public AnotherClass, public TObject
901///
902/// then on return, one must do:
903///
904/// auto objPtr = dynamic_cast<MyClass*>(directory->Get("some object of MyClass"));
905///
906/// Of course, dynamic_cast<> can also be used in the example 1.
907///
909TObject *TDirectoryFile::Get(const char *namecycle)
910{
911 Short_t cycle;
912 char name[kMaxLen];
913
914 DecodeNameCycle(namecycle, name, cycle, kMaxLen);
915 Int_t nch = strlen(name);
916 for (Int_t i = nch-1; i > 0; i--) {
917 if (name[i] == '/') {
918 name[i] = 0;
919 TDirectory* dirToSearch=GetDirectory(name);
920 const char *subnamecycle = namecycle + i + 1;
921 name[i] = '/';
922 return dirToSearch?dirToSearch->Get(subnamecycle):0;
923 }
924 }
925 const char *namobj = name;
926
927//*-*---------------------Case of Object in memory---------------------
928// ========================
929 TObject *idcur = fList ? fList->FindObject(namobj) : nullptr;
930 if (idcur) {
931 if (idcur==this && strlen(namobj)!=0) {
932 // The object has the same name has the directory and
933 // that's what we picked-up! We just need to ignore
934 // it ...
935 idcur = nullptr;
936 } else if (cycle == 9999) {
937 return idcur;
938 } else {
939 if (idcur->InheritsFrom(TCollection::Class()))
940 idcur->Delete(); // delete also list elements
941 delete idcur;
942 idcur = nullptr;
943 }
944 }
945
946//*-*---------------------Case of Key---------------------
947// ===========
948 TKey *key;
949 TIter nextkey(GetListOfKeys());
950 while ((key = (TKey *) nextkey())) {
951 if (strcmp(namobj,key->GetName()) == 0) {
952 if ((cycle == 9999) || (cycle == key->GetCycle())) {
953 TDirectory::TContext ctxt(this);
954 idcur = key->ReadObj();
955 break;
956 }
957 }
958 }
959
960 return idcur;
961}
962
963////////////////////////////////////////////////////////////////////////////////
964/// Return pointer to object identified by namecycle.
965///
966/// The returned object may or may not derive from TObject.
967///
968/// - namecycle has the format name;cycle
969/// - name = * is illegal, cycle = * is illegal
970/// - cycle = "" or cycle = 9999 ==> apply to a memory object
971///
972/// ## Very important note
973/// The calling application must cast the returned object to
974/// the final type, e.g.
975///
976/// auto objPtr = (MyClass*)directory->GetObject("some object of MyClass");
978void *TDirectoryFile::GetObjectUnchecked(const char *namecycle)
979{
980 return GetObjectChecked(namecycle,(TClass*)nullptr);
981}
982
983////////////////////////////////////////////////////////////////////////////////
984/// See documentation of TDirectoryFile::GetObjectCheck(const char *namecycle, const TClass *cl)
986void *TDirectoryFile::GetObjectChecked(const char *namecycle, const char* classname)
987{
988 return GetObjectChecked(namecycle,TClass::GetClass(classname));
989}
990
991
992////////////////////////////////////////////////////////////////////////////////
993/// Return pointer to object identified by namecycle if and only if the actual
994/// object is a type suitable to be stored as a pointer to a "expectedClass"
995/// If expectedClass is null, no check is performed.
996///
997/// - namecycle has the format name;cycle
998/// - name = * is illegal, cycle = * is illegal
999/// - cycle = "" or cycle = 9999 ==> apply to a memory object
1000///
1001/// ### Very important note
1002/// The calling application must cast the returned pointer to
1003/// the type described by the 2 arguments (i.e. cl):
1004///
1005/// auto objPtr = (MyClass*)directory->GetObjectChecked("some object of MyClass","MyClass"));
1006///
1007/// Note: We recommend using the method TDirectoryFile::Get<T>:
1008/// ~~~{.cpp}
1009/// auto objPtr = directory->Get<MyClass>("some object inheriting from MyClass");
1010/// if (objPtr) { ... we found what we are looking for ... }
1011/// ~~~
1013void *TDirectoryFile::GetObjectChecked(const char *namecycle, const TClass* expectedClass)
1014{
1015
1016 // If the name is invalid, issue an error message and return a nullptr
1017 if (!namecycle || '\0' == namecycle[0]) {
1018 Error("GetObjectChecked", "The provided key name is invalid.");
1019 return nullptr;
1020 }
1021
1022 Short_t cycle;
1023 char name[kMaxLen];
1024
1025 DecodeNameCycle(namecycle, name, cycle, kMaxLen);
1026 Int_t nch = strlen(name);
1027 for (Int_t i = nch-1; i > 0; i--) {
1028 if (name[i] == '/') {
1029 name[i] = 0;
1030 TDirectory* dirToSearch=GetDirectory(name);
1031 const char *subnamecycle = namecycle + i + 1;
1032 name[i] = '/';
1033 if (dirToSearch) {
1034 return dirToSearch->GetObjectChecked(subnamecycle, expectedClass);
1035 } else {
1036 return nullptr;
1037 }
1038 }
1039 }
1040 const char *namobj = name;
1041
1042//*-*---------------------Case of Object in memory---------------------
1043// ========================
1044 if (expectedClass==0 || expectedClass->IsTObject()) {
1045 TObject *objcur = fList ? fList->FindObject(namobj) : nullptr;
1046 if (objcur) {
1047 if (objcur==this && strlen(namobj)!=0) {
1048 // The object has the same name has the directory and
1049 // that's what we picked-up! We just need to ignore
1050 // it ...
1051 objcur = nullptr;
1052 } else if (cycle == 9999) {
1053 // Check type
1054 if (expectedClass && objcur->IsA()->GetBaseClassOffset(expectedClass) == -1) return nullptr;
1055 else return objcur;
1056 } else {
1057 if (objcur->InheritsFrom(TCollection::Class()))
1058 objcur->Delete(); // delete also list elements
1059 delete objcur;
1060 objcur = nullptr;
1061 }
1062 }
1063 }
1064
1065//*-*---------------------Case of Key---------------------
1066// ===========
1067 void *idcur = nullptr;
1068 TKey *key;
1069 TIter nextkey(GetListOfKeys());
1070 while ((key = (TKey *) nextkey())) {
1071 if (strcmp(namobj,key->GetName()) == 0) {
1072 if ((cycle == 9999) || (cycle == key->GetCycle())) {
1073 TDirectory::TContext ctxt(this);
1074 idcur = key->ReadObjectAny(expectedClass);
1075 break;
1076 }
1077 }
1078 }
1079
1080 return idcur;
1081}
1082
1083////////////////////////////////////////////////////////////////////////////////
1084/// Return the buffer size to create new TKeys.
1085///
1086/// If the stored fBufferSize is null, the value returned is the average
1087/// buffer size of objects in the file so far.
1090{
1091 if (fBufferSize <= 0) return fFile->GetBestBuffer();
1092 else return fBufferSize;
1093}
1094
1095
1096////////////////////////////////////////////////////////////////////////////////
1097/// Return pointer to key with name,cycle
1098///
1099/// if cycle = 9999 returns highest cycle
1101TKey *TDirectoryFile::GetKey(const char *name, Short_t cycle) const
1102{
1103 if (!fKeys) return nullptr;
1104
1105 // TIter::TIter() already checks for null pointers
1106 TIter next( ((THashList *)(GetListOfKeys()))->GetListForObject(name) );
1107
1108 TKey *key;
1109 while (( key = (TKey *)next() )) {
1110 if (!strcmp(name, key->GetName())) {
1111 if ((cycle == 9999) || (cycle >= key->GetCycle()))
1112 return key;
1113 }
1114 }
1115
1116 return nullptr;
1117}
1118
1119////////////////////////////////////////////////////////////////////////////////
1120/// List Directory contents
1121///
1122/// Indentation is used to identify the directory tree
1123/// Subdirectories are listed first, then objects in memory, then objects on the file
1124///
1125/// The option can has the following format: <b>[-d |-m][<regexp>]</b>
1126/// Options:
1127/// - -d: only list objects in the file
1128/// - -m: only list objects in memory
1129/// The <regexp> will be used to match the name of the objects.
1130/// By default memory and disk objects are listed.
1132void TDirectoryFile::ls(Option_t *option) const
1133{
1135 std::cout <<ClassName()<<"*\t\t"<<GetName()<<"\t"<<GetTitle()<<std::endl;
1137
1138 TString opta = option;
1139 TString opt = opta.Strip(TString::kBoth);
1140 Bool_t memobj = kTRUE;
1141 Bool_t diskobj = kTRUE;
1142 TString reg = "*";
1143 if (opt.BeginsWith("-m")) {
1144 diskobj = kFALSE;
1145 if (opt.Length() > 2)
1146 reg = opt(2,opt.Length());
1147 } else if (opt.BeginsWith("-d")) {
1148 memobj = kFALSE;
1149 if (opt.Length() > 2)
1150 reg = opt(2,opt.Length());
1151 } else if (!opt.IsNull())
1152 reg = opt;
1153
1154 TRegexp re(reg, kTRUE);
1155
1156 if (memobj) {
1157 TObject *obj;
1158 TIter nextobj(fList);
1159 while ((obj = (TObject *) nextobj())) {
1160 TString s = obj->GetName();
1161 if (s.Index(re) == kNPOS) continue;
1162 obj->ls(option); //*-* Loop on all the objects in memory
1163 }
1164 }
1165
1166 if (diskobj) {
1167 TKey *key;
1168 TIter next(GetListOfKeys());
1169 while ((key = (TKey *) next())) {
1170 TString s = key->GetName();
1171 if (s.Index(re) == kNPOS) continue;
1172 key->ls(); //*-* Loop on all the keys
1173 }
1174 }
1176}
1177
1178////////////////////////////////////////////////////////////////////////////////
1179/// Interface to TFile::Open
1181TFile *TDirectoryFile::OpenFile(const char *name, Option_t *option,const char *ftitle, Int_t compress, Int_t netopt)
1182{
1183 return TFile::Open(name,option,ftitle,compress,netopt);
1184
1185}
1186
1187////////////////////////////////////////////////////////////////////////////////
1188/// Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...".
1189///
1190/// Returns 0 in case of error or if a sub-directory (hierarchy) with the requested
1191/// name already exists.
1192/// returnExistingDirectory returns a pointer to an already existing sub-directory instead of 0.
1193/// Returns a pointer to the created sub-directory or to the top sub-directory of
1194/// the hierarchy (in the above example, the returned TDirectory * always points
1195/// to "a").
1197TDirectory *TDirectoryFile::mkdir(const char *name, const char *title, Bool_t returnExistingDirectory)
1198{
1199 if (!name || !title || !name[0]) return nullptr;
1200 if (!title[0]) title = name;
1201 if (GetKey(name)) {
1202 if (returnExistingDirectory)
1203 return (TDirectoryFile*) GetDirectory(name);
1204 else {
1205 Error("mkdir","An object with name %s exists already",name);
1206 return nullptr;
1207 }
1208 }
1209 TDirectoryFile *newdir = nullptr;
1210 if (const char *slash = strchr(name,'/')) {
1211 TString workname(name, Long_t(slash-name));
1212 TDirectoryFile *tmpdir = nullptr;
1213 GetObject(workname.Data(), tmpdir);
1214 if (!tmpdir) {
1215 tmpdir = (TDirectoryFile*)mkdir(workname.Data(),title);
1216 if (!tmpdir) return nullptr;
1217 }
1218 if (!newdir) newdir = tmpdir;
1219 tmpdir->mkdir(slash+1);
1220 return newdir;
1221 }
1222
1223 TDirectory::TContext ctxt(this);
1224
1225 newdir = new TDirectoryFile(name, title, "", this);
1226
1227 return newdir;
1228}
1229
1230////////////////////////////////////////////////////////////////////////////////
1231/// Purge lowest key cycles in a directory.
1232///
1233/// By default, only the highest cycle of a key is kept. Keys for which
1234/// the "KEEP" flag has been set are not removed. See TKey::Keep().
1235/// NOTE: This does not reduce the size of a TFile--
1236/// the space is simply freed up to be overwritten.
1239{
1240 if (!IsWritable()) return;
1241
1242 TDirectory::TContext ctxt(this);
1243
1244 TKey *key;
1246
1247 while ((key = (TKey*)prev())) { // reverse loop on keys
1248 TKey *keyprev = (TKey*)GetListOfKeys()->Before(key);
1249 if (!keyprev) break;
1250 if (key->GetKeep() == 0) {
1251 if (strcmp(key->GetName(), keyprev->GetName()) == 0) {
1252 key->Delete(); // Remove from the file.
1253 delete key; // Remove from memory.
1254 }
1255 }
1256 }
1257 TFile *f = GetFile();
1258 if (fModified && f) {
1259 WriteKeys(); // Write new keys structure
1260 WriteDirHeader(); // Write new directory header
1261 f->WriteFree(); // Write new free segments list
1262 f->WriteHeader(); // Write new file header
1263 }
1264}
1265
1266////////////////////////////////////////////////////////////////////////////////
1267/// Read objects from a ROOT file directory into memory.
1268///
1269/// If an object is already in memory, the memory copy is deleted
1270/// and the object is again read from the file.
1271/// If opt=="dirs", only subdirectories will be read
1272/// If opt=="dirs*" complete directory tree will be read
1275{
1276 TDirectory::TContext ctxt(this);
1277
1278 TKey *key;
1279 TIter next(GetListOfKeys());
1280
1281 Bool_t readdirs = ((opt!=0) && ((strcmp(opt,"dirs")==0) || (strcmp(opt,"dirs*")==0)));
1282
1283 if (readdirs)
1284 while ((key = (TKey *) next())) {
1285
1286 //if (strcmp(key->GetClassName(),"TDirectory")!=0) continue;
1287 if (strstr(key->GetClassName(),"TDirectory")==0) continue;
1288
1289 TDirectory *dir = GetDirectory(key->GetName(), kTRUE, "ReadAll");
1290
1291 if ((dir!=0) && (strcmp(opt,"dirs*")==0)) dir->ReadAll("dirs*");
1292 }
1293 else
1294 while ((key = (TKey *) next())) {
1295 TObject *thing = GetList()->FindObject(key->GetName());
1296 if (thing) { delete thing; }
1297 key->ReadObj();
1298 }
1299}
1300
1301////////////////////////////////////////////////////////////////////////////////
1302/// Read the linked list of keys.
1303///
1304/// Every directory has a linked list (fKeys). This linked list has been
1305/// written on the file via WriteKeys as a single data record.
1306///
1307/// It is interesting to call this function in the following situation.
1308/// Assume another process1 is connecting this directory in Update mode
1309/// - Process1 is adding/updating objects in this directory
1310/// - You want to see the latest status from process1.
1311/// Example Process1:
1312/// ~~~{.cpp}
1313/// obj1.Write();
1314/// obj2.Write();
1315/// gDirectory->SaveSelf();
1316/// ~~~
1317///
1318/// Example Process2:
1319/// ~~~{.cpp}
1320/// gDirectory->ReadKeys();
1321/// obj1->Draw();
1322/// ~~~
1323/// This is an efficient way (without opening/closing files) to view
1324/// the latest updates of a file being modified by another process
1325/// as it is typically the case in a data acquisition system.
1328{
1329 if (!fFile || !fKeys) return 0;
1330
1331 if (!fFile->IsBinary())
1332 return fFile->DirReadKeys(this);
1333
1334 TDirectory::TContext ctxt(this);
1335
1336 char *buffer;
1337 if (forceRead) {
1338 fKeys->Delete();
1339 //In case directory was updated by another process, read new
1340 //position for the keys
1342 char *header = new char[nbytes];
1343 buffer = header;
1345 if ( fFile->ReadBuffer(buffer,nbytes) ) {
1346 // ReadBuffer return kTRUE in case of failure.
1347 delete [] header;
1348 return 0;
1349 }
1350 buffer += fNbytesName;
1351 Version_t versiondir;
1352 frombuf(buffer,&versiondir);
1353 fDatimeC.ReadBuffer(buffer);
1354 fDatimeM.ReadBuffer(buffer);
1355 frombuf(buffer, &fNbytesKeys);
1356 frombuf(buffer, &fNbytesName);
1357 if (versiondir > 1000) {
1358 frombuf(buffer, &fSeekDir);
1359 frombuf(buffer, &fSeekParent);
1360 frombuf(buffer, &fSeekKeys);
1361 } else {
1362 Int_t sdir,sparent,skeys;
1363 frombuf(buffer, &sdir); fSeekDir = (Long64_t)sdir;
1364 frombuf(buffer, &sparent); fSeekParent = (Long64_t)sparent;
1365 frombuf(buffer, &skeys); fSeekKeys = (Long64_t)skeys;
1366 }
1367 delete [] header;
1368 }
1369
1370 Int_t nkeys = 0;
1371 Long64_t fsize = fFile->GetSize();
1372 if ( fSeekKeys > 0) {
1373 TKey *headerkey = new TKey(fSeekKeys, fNbytesKeys, this);
1374 headerkey->ReadFile();
1375 buffer = headerkey->GetBuffer();
1376 headerkey->ReadKeyBuffer(buffer);
1377
1378 TKey *key;
1379 frombuf(buffer, &nkeys);
1380 for (Int_t i = 0; i < nkeys; i++) {
1381 key = new TKey(this);
1382 key->ReadKeyBuffer(buffer);
1383 if (key->GetSeekKey() < 64 || key->GetSeekKey() > fsize) {
1384 Error("ReadKeys","reading illegal key, exiting after %d keys",i);
1385 fKeys->Remove(key);
1386 nkeys = i;
1387 break;
1388 }
1389 if (key->GetSeekPdir() < 64 || key->GetSeekPdir() > fsize) {
1390 Error("ReadKeys","reading illegal key, exiting after %d keys",i);
1391 fKeys->Remove(key);
1392 nkeys = i;
1393 break;
1394 }
1395 fKeys->Add(key);
1396 }
1397 delete headerkey;
1398 }
1399
1400 return nkeys;
1401}
1402
1403
1404////////////////////////////////////////////////////////////////////////////////
1405/// Read object with keyname from the current directory
1406///
1407/// Read contents of object with specified name from the current directory.
1408/// First the key with keyname is searched in the current directory,
1409/// next the key buffer is deserialized into the object.
1410/// The object must have been created before via the default constructor.
1411/// See TObject::Write().
1413Int_t TDirectoryFile::ReadTObject(TObject *obj, const char *keyname)
1414{
1415 if (!fFile) { Error("Read","No file open"); return 0; }
1416 TKey *key = nullptr;
1417 TIter nextkey(GetListOfKeys());
1418 while ((key = (TKey *) nextkey())) {
1419 if (strcmp(keyname,key->GetName()) == 0) {
1420 return key->Read(obj);
1421 }
1422 }
1423 Error("Read","Key not found");
1424 return 0;
1425}
1426
1427////////////////////////////////////////////////////////////////////////////////
1428/// Reset the TDirectory after its content has been merged into another
1429/// Directory.
1430///
1431/// This returns the TDirectoryFile object back to its state
1432/// before any data has been written to the file.
1433/// The object in the in-memory list are assumed to also have been reset.
1436{
1437 // There is nothing to reset in the base class (TDirectory) since
1438 // we do want to key the list of in-memory object as is.
1439 fModified = kFALSE;
1440 // Does not change: fWritable
1441 fDatimeC.Set();
1442 fDatimeM.Set();
1443 fNbytesKeys = 0; // updated when the keys are written
1444 fNbytesName = 0; // updated by Init
1445 // Does not change (user customization): fBufferSize;
1446 fSeekDir = 0; // updated by Init
1447 fSeekParent = 0; // updated by Init
1448 fSeekKeys = 0; // updated by Init
1449 // Does not change: fFile
1450 TKey *key = fKeys ? (TKey*)fKeys->FindObject(fName) : nullptr;
1451 TClass *cl = IsA();
1452 if (key) {
1453 cl = TClass::GetClass(key->GetClassName());
1454 }
1455 // NOTE: We should check that the content is really mergeable and in
1456 // the in-mmeory list, before deleting the keys.
1457 if (fKeys) {
1458 fKeys->Delete("slow");
1459 }
1460
1462
1463 // Do the same with the sub-directories.
1464 TIter next(GetList());
1465 TObject *idcur;
1466 while ((idcur = next())) {
1467 if (idcur->IsA() == TDirectoryFile::Class()) {
1468 ((TDirectoryFile*)idcur)->ResetAfterMerge(info);
1469 }
1470 }
1471
1472}
1473
1474////////////////////////////////////////////////////////////////////////////////
1475/// Removes subdirectory from the directory
1476///
1477/// When directory is deleted, all keys in all subdirectories will be
1478/// read first and deleted from file (if exists)
1479/// Equivalent call is Delete("name;*");
1481void TDirectoryFile::rmdir(const char *name)
1482{
1483 if (!name || (*name==0)) return;
1484
1485 TString mask(name);
1486 mask += ";*";
1487 Delete(mask);
1488}
1489
1490////////////////////////////////////////////////////////////////////////////////
1491/// Save recursively all directory keys and headers
1494{
1495 TDirectory::TContext ctxt(this);
1496
1497 SaveSelf();
1498
1499 // recursively save all sub-directories
1500 if (fList && fList->FirstLink()) {
1501 auto lnk = fList->FirstLink()->shared_from_this();
1502 while (lnk) {
1503 TObject *idcur = lnk->GetObject();
1504 if (idcur && idcur->InheritsFrom(TDirectoryFile::Class())) {
1505 TDirectoryFile *dir = (TDirectoryFile *)idcur;
1506 dir->Save();
1507 }
1508 lnk = lnk->NextSP();
1509 }
1510 }
1511}
1512
1513////////////////////////////////////////////////////////////////////////////////
1514/// Save object in filename.
1515///
1516/// If filename is 0 or "", a file with "objectname.root" is created.
1517/// The name of the key is the object name.
1518/// If the operation is successful, it returns the number of bytes written to the file
1519/// otherwise it returns 0.
1520/// By default a message is printed. Use option "q" to not print the message.
1521/// If filename contains ".json" extension, JSON representation of the object
1522/// will be created and saved in the text file. Such file can be used in
1523/// JavaScript ROOT (https://root.cern.ch/js/) to display object in web browser
1524/// When creating JSON file, option string may contain compression level from 0 to 3 (default 0)
1526Int_t TDirectoryFile::SaveObjectAs(const TObject *obj, const char *filename, Option_t *option) const
1527{
1528 if (!obj) return 0;
1529 TDirectory *dirsav = gDirectory;
1530 TString fname = filename;
1531 if (!filename || !filename[0]) {
1532 fname.Form("%s.root",obj->GetName());
1533 }
1534 Int_t nbytes = 0;
1535 if (fname.Index(".json") > 0) {
1536 nbytes = TBufferJSON::ExportToFile(fname, obj, option);
1537 } else {
1538 TFile *local = TFile::Open(fname.Data(),"recreate");
1539 if (!local) return 0;
1540 nbytes = obj->Write();
1541 delete local;
1542 if (dirsav) dirsav->cd();
1543 }
1544 TString opt = option;
1545 opt.ToLower();
1546 if (!opt.Contains("q")) {
1547 if (!gSystem->AccessPathName(fname.Data())) obj->Info("SaveAs", "ROOT file %s has been created", fname.Data());
1548 }
1549 return nbytes;
1550}
1551
1552////////////////////////////////////////////////////////////////////////////////
1553/// Save Directory keys and header
1554///
1555/// If the directory has been modified (fModified set), write the keys
1556/// and the directory header. This function assumes the cd is correctly set.
1557///
1558/// It is recommended to use this function in the following situation:
1559/// Assume a process1 using a directory in Update mode
1560/// - New objects or modified objects have been written to the directory.
1561/// - You do not want to close the file.
1562/// - You want your changes be visible from another process2 already connected
1563/// to this directory in read mode.
1564/// - Call this function.
1565/// - In process2, use TDirectoryFile::ReadKeys to refresh the directory.
1568{
1569 if (IsWritable() && (fModified || force) && fFile) {
1570 Bool_t dowrite = kTRUE;
1571 if (fFile->GetListOfFree())
1572 dowrite = fFile->GetListOfFree()->First() != nullptr;
1573 if (dowrite) {
1574 TDirectory *dirsav = gDirectory;
1575 if (dirsav != this) cd();
1576 WriteKeys(); //*-*- Write keys record
1577 WriteDirHeader(); //*-*- Update directory record
1578 if (dirsav && dirsav != this) dirsav->cd();
1579 }
1580 }
1581}
1582
1583////////////////////////////////////////////////////////////////////////////////
1584/// Set the default buffer size when creating new TKeys.
1585///
1586/// See also TDirectoryFile::GetBufferSize
1589{
1590 fBufferSize = bufsize;
1591}
1592
1593////////////////////////////////////////////////////////////////////////////////
1594/// Find the action to be executed in the dictionary of the parent class
1595/// and store the corresponding exec number into fBits.
1596///
1597/// This function searches a data member in the class of parent with an
1598/// offset corresponding to this.
1599/// If a comment "TEXEC:" is found in the comment field of the data member,
1600/// the function stores the exec identifier of the exec statement
1601/// following this keyword.
1604{
1605 Int_t offset = (char*)ref - (char*)parent;
1606 TClass *cl = parent->IsA();
1607 cl->BuildRealData(parent);
1609 TIter next(info->GetElements());
1610 TStreamerElement *element;
1611 while((element = (TStreamerElement*)next())) {
1612 if (element->GetOffset() != offset) continue;
1613 Int_t execid = element->GetExecID();
1614 if (execid > 0) ref->SetBit(execid << 8);
1615 return;
1616 }
1617}
1618
1619////////////////////////////////////////////////////////////////////////////////
1620/// Set the new value of fWritable recursively
1623{
1624 TDirectory::TContext ctxt(this);
1625
1626 fWritable = writable;
1627
1628 // recursively set all sub-directories
1629 if (fList) {
1630 TObject *idcur;
1631 TIter next(fList);
1632 while ((idcur = next())) {
1633 if (idcur->InheritsFrom(TDirectoryFile::Class())) {
1634 TDirectoryFile *dir = (TDirectoryFile*)idcur;
1635 dir->SetWritable(writable);
1636 }
1637 }
1638 }
1639}
1640
1641
1642////////////////////////////////////////////////////////////////////////////////
1643/// Return the size in bytes of the directory header
1646{
1647 Int_t nbytes = 22;
1648
1649 nbytes += fDatimeC.Sizeof();
1650 nbytes += fDatimeM.Sizeof();
1651 nbytes += fUUID.Sizeof();
1652 //assume that the file may be above 2 Gbytes if file version is > 4
1653 if (fFile && fFile->GetVersion() >= 40000) nbytes += 12;
1654 return nbytes;
1655}
1656
1657
1658////////////////////////////////////////////////////////////////////////////////
1659/// Stream a class object
1660
1661void TDirectoryFile::Streamer(TBuffer &b)
1662{
1663 Version_t v,version;
1664 if (b.IsReading()) {
1665 BuildDirectoryFile((TFile*)b.GetParent(), nullptr);
1666 if (fFile && fFile->IsWritable()) fWritable = kTRUE;
1667
1668 if (fFile && !fFile->IsBinary()) {
1669 Version_t R__v = b.ReadVersion(0, 0);
1670
1671 TClass* dirclass = (R__v < 5) ? TDirectory::Class() : TDirectoryFile::Class();
1672
1673 b.ClassBegin(dirclass, R__v);
1674
1675 TString sbuf;
1676
1677 b.ClassMember("CreateTime","TString");
1678 sbuf.Streamer(b);
1679 TDatime timeC(sbuf.Data());
1680 fDatimeC = timeC;
1681
1682 b.ClassMember("ModifyTime","TString");
1683 sbuf.Streamer(b);
1684 TDatime timeM(sbuf.Data());
1685 fDatimeM = timeM;
1686
1687 b.ClassMember("UUID","TString");
1688 sbuf.Streamer(b);
1689 TUUID id(sbuf.Data());
1690 fUUID = id;
1691
1692 b.ClassEnd(dirclass);
1693
1694 fSeekKeys = 0; // read keys later in the TKeySQL class
1695 } else {
1696 b >> version;
1697 fDatimeC.Streamer(b);
1698 fDatimeM.Streamer(b);
1699 b >> fNbytesKeys;
1700 b >> fNbytesName;
1701 if (version > 1000) {
1703 b >> fSeekDir;
1704 b >> fSeekParent;
1705 b >> fSeekKeys;
1706 } else {
1707 Int_t sdir,sparent,skeys;
1708 b >> sdir; fSeekDir = (Long64_t)sdir;
1709 b >> sparent; fSeekParent = (Long64_t)sparent;
1710 b >> skeys; fSeekKeys = (Long64_t)skeys;
1711 }
1712 v = version%1000;
1713 if (v == 2) {
1715 } else if (v > 2) {
1716 fUUID.Streamer(b);
1717 }
1718 }
1719 fList->UseRWLock();
1721 gROOT->GetUUIDs()->AddUUID(fUUID,this);
1722 if (fSeekKeys) ReadKeys();
1723 } else {
1724 if (fFile && !fFile->IsBinary()) {
1725 b.WriteVersion(TDirectoryFile::Class());
1726
1727 TString sbuf;
1728
1729 b.ClassBegin(TDirectoryFile::Class());
1730
1731 b.ClassMember("CreateTime","TString");
1732 sbuf = fDatimeC.AsSQLString();
1733 sbuf.Streamer(b);
1734
1735 b.ClassMember("ModifyTime","TString");
1736 fDatimeM.Set();
1737 sbuf = fDatimeM.AsSQLString();
1738 sbuf.Streamer(b);
1739
1740 b.ClassMember("UUID","TString");
1741 sbuf = fUUID.AsString();
1742 sbuf.Streamer(b);
1743
1744 b.ClassEnd(TDirectoryFile::Class());
1745 } else {
1746 version = TDirectoryFile::Class_Version();
1747 if (fFile && fFile->GetEND() > TFile::kStartBigFile) version += 1000;
1748 b << version;
1749 fDatimeC.Streamer(b);
1750 fDatimeM.Streamer(b);
1751 b << fNbytesKeys;
1752 b << fNbytesName;
1753 if (version > 1000) {
1754 b << fSeekDir;
1755 b << fSeekParent;
1756 b << fSeekKeys;
1757 } else {
1758 b << (Int_t)fSeekDir;
1759 b << (Int_t)fSeekParent;
1760 b << (Int_t)fSeekKeys;
1761 }
1762 fUUID.Streamer(b);
1763 if (version <=1000) for (Int_t i=0;i<3;i++) b << Int_t(0);
1764 }
1765 }
1766}
1767
1768////////////////////////////////////////////////////////////////////////////////
1769/// Write all objects in memory to disk.
1770///
1771/// Loop on all objects in memory (including subdirectories).
1772/// A new key is created in the keys linked list for each object.
1773/// For allowed options see TObject::Write().
1774/// The directory header info is rewritten on the directory header record.
1776Int_t TDirectoryFile::Write(const char *, Int_t opt, Int_t bufsize)
1777{
1778 if (!IsWritable()) return 0;
1779 TDirectory::TContext ctxt(this);
1780
1781 // Loop on all objects (including subdirs)
1782 TIter next(fList);
1783 TObject *obj;
1784 Int_t nbytes = 0;
1785 while ((obj=next())) {
1786 nbytes += obj->Write(0,opt,bufsize);
1787 }
1788 if (R__likely(!(opt & kOnlyPrepStep)))
1789 SaveSelf(kTRUE); // force save itself
1790
1791 return nbytes;
1792}
1793
1794////////////////////////////////////////////////////////////////////////////////
1795/// One can not save a const TDirectory object.
1797Int_t TDirectoryFile::Write(const char *n, Int_t opt, Int_t bufsize) const
1798{
1799 Error("Write const","A const TDirectory object should not be saved. We try to proceed anyway.");
1800 return const_cast<TDirectoryFile*>(this)->Write(n, opt, bufsize);
1801}
1802
1803////////////////////////////////////////////////////////////////////////////////
1804/// Write object obj to this directory.
1805///
1806/// The data structure corresponding to this object is serialized.
1807/// The corresponding buffer is written to this directory
1808/// with an associated key with name "name".
1809///
1810/// Writing an object to a file involves the following steps:
1811/// - Creation of a support TKey object in the directory. The TKey object
1812/// creates a TBuffer object.
1813/// - The TBuffer object is filled via the class::Streamer function.
1814/// - If the file is compressed (default) a second buffer is created to hold
1815/// the compressed buffer.
1816/// - Reservation of the corresponding space in the file by looking in the
1817/// TFree list of free blocks of the file.
1818/// - The buffer is written to the file.
1819///
1820/// By default, the buffersize will be taken from the average buffer size
1821/// of all objects written to the current file so far.
1822/// Use TDirectoryFile::SetBufferSize to force a given buffer size.
1823///
1824/// If a name is specified, it will be the name of the key.
1825/// If name is not given, the name of the key will be the name as returned
1826/// by obj->GetName().
1827///
1828/// The option can be a combination of:
1829/// - "SingleKey"
1830/// - "Overwrite"
1831/// - "WriteDelete"
1832/// Using the "Overwrite" option a previous key with the same name is
1833/// overwritten. The previous key is deleted before writing the new object.
1834/// Using the "WriteDelete" option a previous key with the same name is
1835/// deleted only after the new object has been written. This option
1836/// is safer than kOverwrite but it is slower.
1837/// The "SingleKey" option is only used by TCollection::Write() to write
1838/// a container with a single key instead of each object in the container
1839/// with its own key.
1840/// An object is read from this directory via TDirectoryFile::Get.
1841/// The function returns the total number of bytes written to the directory.
1842/// It returns 0 if the object cannot be written.
1843///
1844/// WARNING: avoid special characters like '^','$','.' in the name as they
1845/// are used by the regular expression parser (see TRegexp).
1847Int_t TDirectoryFile::WriteTObject(const TObject *obj, const char *name, Option_t *option, Int_t bufsize)
1848{
1849 TDirectory::TContext ctxt(this);
1850
1851 if (fFile==0) {
1852 const char *objname = "no name specified";
1853 if (name) objname = name;
1854 else if (obj) objname = obj->GetName();
1855 Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.",GetName(),objname);
1856 return 0;
1857 }
1858
1859 if (!fFile->IsWritable()) {
1861 // Do not print the error if the file already had a SysError.
1862 Error("WriteTObject","Directory %s is not writable", fFile->GetName());
1863 }
1864 return 0;
1865 }
1866
1867 if (!obj) return 0;
1868
1869 TString opt = option;
1870 opt.ToLower();
1871
1872 TKey *key=0, *oldkey=0;
1873 Int_t bsize = GetBufferSize();
1874 if (bufsize > 0) bsize = bufsize;
1875
1876 const char *oname;
1877 if (name && *name)
1878 oname = name;
1879 else
1880 oname = obj->GetName();
1881
1882 // Remove trailing blanks in object name
1883 Int_t nch = strlen(oname);
1884 char *newName = nullptr;
1885 if (nch && oname[nch-1] == ' ') {
1886 newName = new char[nch+1];
1887 strlcpy(newName,oname,nch+1);
1888 for (Int_t i=0;i<nch;i++) {
1889 if (newName[nch-i-1] != ' ') break;
1890 newName[nch-i-1] = 0;
1891 }
1892 oname = newName;
1893 }
1894
1895 if (opt.Contains("overwrite")) {
1896 //One must use GetKey. FindObject would return the lowest cycle of the key!
1897 //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
1898 key = GetKey(oname);
1899 if (key) {
1900 key->Delete();
1901 delete key;
1902 }
1903 }
1904 if (opt.Contains("writedelete")) {
1905 oldkey = GetKey(oname);
1906 }
1907 key = fFile->CreateKey(this, obj, oname, bsize);
1908 if (newName) delete [] newName;
1909
1910 if (!key->GetSeekKey()) {
1911 fKeys->Remove(key);
1912 delete key;
1913 if (bufsize) fFile->SetBufferSize(bufsize);
1914 return 0;
1915 }
1916 fFile->SumBuffer(key->GetObjlen());
1917 Int_t nbytes = key->WriteFile(0);
1919 if (bufsize) fFile->SetBufferSize(bufsize);
1920 return 0;
1921 }
1922 if (oldkey) {
1923 oldkey->Delete();
1924 delete oldkey;
1925 }
1926 if (bufsize) fFile->SetBufferSize(bufsize);
1927
1928 return nbytes;
1929}
1930
1931////////////////////////////////////////////////////////////////////////////////
1932/// Write object from pointer of class classname in this directory.
1933///
1934/// obj may not derive from TObject. See TDirectoryFile::WriteTObject for comments
1935///
1936/// ## Very important note
1937/// The value passed as 'obj' needs to be from a pointer to the type described by classname.
1938/// For example:
1939/// ~~~{.cpp}
1940/// TopClass *top;
1941/// BottomClass *bottom;
1942/// top = bottom;
1943/// ~~~
1944/// you can do:
1945/// ~~~{.cpp}
1946/// directory->WriteObjectAny(top,"top","name of object");
1947/// directory->WriteObjectAny(bottom,"bottom","name of object");
1948/// ~~~
1949/// <b>BUT YOU CAN NOT DO</b> the following since it will fail with multiple inheritance:
1950/// ~~~{.cpp}
1951/// directory->WriteObjectAny(top,"bottom","name of object");
1952/// ~~~
1953/// We <b>STRONGLY</b> recommend to use
1954/// ~~~{.cpp}
1955/// TopClass *top = ....;
1956/// directory->WriteObject(top,"name of object")
1957/// ~~~
1958/// See also remarks in TDirectoryFile::WriteTObject
1960Int_t TDirectoryFile::WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option, Int_t bufsize)
1961{
1962 TClass *cl = TClass::GetClass(classname);
1963 if (!cl) {
1964 TObject *info_obj = *(TObject**)obj;
1965 TVirtualStreamerInfo *info = dynamic_cast<TVirtualStreamerInfo*>(info_obj);
1966 if (!info) {
1967 Error("WriteObjectAny","Unknown class: %s",classname);
1968 return 0;
1969 } else {
1970 cl = info->GetClass();
1971 }
1972 }
1973 return WriteObjectAny(obj,cl,name,option,bufsize);
1974}
1975
1976////////////////////////////////////////////////////////////////////////////////
1977/// Write object of class with dictionary cl in this directory.
1978///
1979/// obj may not derive from TObject
1980/// To get the TClass* cl pointer, one can use
1981///
1982/// TClass *cl = TClass::GetClass("classname");
1983///
1984/// An alternative is to call the function WriteObjectAny above.
1985/// see TDirectoryFile::WriteTObject for comments
1987Int_t TDirectoryFile::WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option, Int_t bufsize)
1988{
1989 TDirectory::TContext ctxt(this);
1990
1991 if (!fFile) return 0;
1992
1993 if (!cl) {
1994 Error("WriteObject","Unknown type for %s, it can not be written.",name);
1995 return 0;
1996 }
1997
1998 if (!fFile->IsWritable()) {
2000 // Do not print the error if the file already had a SysError.
2001 Error("WriteObject","File %s is not writable", fFile->GetName());
2002 }
2003 return 0;
2004 }
2005
2006 if (!obj) return 0;
2007
2008 const char *className = cl->GetName();
2009 const char *oname;
2010 if (name && *name)
2011 oname = name;
2012 else
2013 oname = className;
2014
2015 if (cl && cl->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(cl->GetCollectionProxy())) {
2016 Error("WriteObjectAny",
2017 "The class requested (%s) for the key name \"%s\""
2018 " is an instance of an stl collection and does not have a compiled CollectionProxy."
2019 " Please generate the dictionary for this collection (%s). No data will be written.",
2020 className, oname, className);
2021 return 0;
2022 }
2023
2024 TKey *key, *oldkey = nullptr;
2025 Int_t bsize = GetBufferSize();
2026 if (bufsize > 0) bsize = bufsize;
2027
2028 TString opt = option;
2029 opt.ToLower();
2030
2031 // Remove trailing blanks in object name
2032 Int_t nch = strlen(oname);
2033 char *newName = nullptr;
2034 if (nch && oname[nch-1] == ' ') {
2035 newName = new char[nch+1];
2036 strlcpy(newName,oname,nch+1);
2037 for (Int_t i=0;i<nch;i++) {
2038 if (newName[nch-i-1] != ' ') break;
2039 newName[nch-i-1] = 0;
2040 }
2041 oname = newName;
2042 }
2043
2044 if (opt.Contains("overwrite")) {
2045 //One must use GetKey. FindObject would return the lowest cycle of the key!
2046 //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
2047 key = GetKey(oname);
2048 if (key) {
2049 key->Delete();
2050 delete key;
2051 }
2052 }
2053 if (opt.Contains("writedelete")) {
2054 oldkey = GetKey(oname);
2055 }
2056 key = fFile->CreateKey(this, obj, cl, oname, bsize);
2057 if (newName) delete [] newName;
2058
2059 if (!key->GetSeekKey()) {
2060 fKeys->Remove(key);
2061 delete key;
2062 return 0;
2063 }
2064 fFile->SumBuffer(key->GetObjlen());
2065 Int_t nbytes = key->WriteFile(0);
2066 if (fFile->TestBit(TFile::kWriteError)) return 0;
2067
2068 if (oldkey) {
2069 oldkey->Delete();
2070 delete oldkey;
2071 }
2072
2073 return nbytes;
2074}
2075
2076////////////////////////////////////////////////////////////////////////////////
2077/// Overwrite the Directory header record.
2080{
2081 TFile* f = GetFile();
2082 if (!f) return;
2083
2084 if (!f->IsBinary()) {
2085 fDatimeM.Set();
2086 f->DirWriteHeader(this);
2087 return;
2088 }
2089
2090 Int_t nbytes = TDirectoryFile::Sizeof(); //Warning ! TFile has a Sizeof()
2091 char *header = new char[nbytes];
2092 char *buffer = header;
2093 fDatimeM.Set();
2095 Long64_t pointer = fSeekDir + fNbytesName; // do not overwrite the name/title part
2096 fModified = kFALSE;
2097 f->Seek(pointer);
2098 f->WriteBuffer(header, nbytes);
2099 if (f->MustFlush()) f->Flush();
2100 delete [] header;
2101}
2102
2103////////////////////////////////////////////////////////////////////////////////
2104/// Write Keys linked list on the file.
2105///
2106/// The linked list of keys (fKeys) is written as a single data record
2109{
2110 TFile* f = GetFile();
2111 if (!f) return;
2112
2113 if (!f->IsBinary()) {
2114 f->DirWriteKeys(this);
2115 return;
2116 }
2117
2118//*-* Delete the old keys structure if it exists
2119 if (fSeekKeys != 0) {
2120 f->MakeFree(fSeekKeys, fSeekKeys + fNbytesKeys -1);
2121 }
2122//*-* Write new keys record
2123 TIter next(fKeys);
2124 TKey *key;
2125 Int_t nkeys = fKeys->GetSize();
2126 Int_t nbytes = sizeof nkeys; //*-* Compute size of all keys
2127 if (f->GetEND() > TFile::kStartBigFile) nbytes += 8;
2128 while ((key = (TKey*)next())) {
2129 nbytes += key->Sizeof();
2130 }
2131 TKey *headerkey = new TKey(fName,fTitle,IsA(),nbytes,this);
2132 if (headerkey->GetSeekKey() == 0) {
2133 delete headerkey;
2134 return;
2135 }
2136 char *buffer = headerkey->GetBuffer();
2137 next.Reset();
2138 tobuf(buffer, nkeys);
2139 while ((key = (TKey*)next())) {
2140 key->FillBuffer(buffer);
2141 }
2142
2143 fSeekKeys = headerkey->GetSeekKey();
2144 fNbytesKeys = headerkey->GetNbytes();
2145 headerkey->WriteFile();
2146 delete headerkey;
2147}
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 R__likely(expr)
Definition: RConfig.hxx:605
#define SafeDelete(p)
Definition: RConfig.hxx:543
#define b(i)
Definition: RSha256.hxx:100
#define f(i)
Definition: RSha256.hxx:104
const Ssiz_t kNPOS
Definition: RtypesCore.h:113
int Int_t
Definition: RtypesCore.h:43
short Version_t
Definition: RtypesCore.h:63
unsigned int UInt_t
Definition: RtypesCore.h:44
const Bool_t kFALSE
Definition: RtypesCore.h:90
long Long_t
Definition: RtypesCore.h:52
bool Bool_t
Definition: RtypesCore.h:61
short Short_t
Definition: RtypesCore.h:37
R__EXTERN Int_t gDebug
Definition: RtypesCore.h:117
long long Long64_t
Definition: RtypesCore.h:71
const Bool_t kTRUE
Definition: RtypesCore.h:89
const char Option_t
Definition: RtypesCore.h:64
#define BIT(n)
Definition: Rtypes.h:83
#define ClassImp(name)
Definition: Rtypes.h:361
const Bool_t kIterBackward
Definition: TCollection.h:41
const Int_t kMaxLen
const UInt_t kIsBigFile
#define gDirectory
Definition: TDirectory.h:229
#define gFile
Definition: TFile.h:342
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:406
R__EXTERN TSystem * gSystem
Definition: TSystem.h:556
#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:80
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition: TClass.cxx:2000
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5908
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:4569
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2866
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:2937
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:47
Describe directory structure in memory.
Definition: TDirectory.h:40
void Delete(const char *namecycle="") override
Delete Objects or/and keys in a directory.
Definition: TDirectory.cxx:652
virtual TList * GetList() const
Definition: TDirectory.h:165
virtual Int_t AppendKey(TKey *)
Definition: TDirectory.h:130
virtual TDirectory * GetDirectory(const char *namecycle, Bool_t printError=false, const char *funcname="GetDirectory")
Find a directory using apath.
Definition: TDirectory.cxx:401
virtual void ReadAll(Option_t *="")
Definition: TDirectory.h:189
virtual TObject * Get(const char *namecycle)
Return pointer to object identified by namecycle.
Definition: TDirectory.cxx:806
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:163
virtual TKey * GetKey(const char *, Short_t=9999) const
Definition: TDirectory.h:164
TUUID fUUID
Definition: TDirectory.h:97
TDirectory * GetMotherDir() const
Definition: TDirectory.h:168
TObject * fMother
Definition: TDirectory.h:95
void GetObject(const char *namecycle, T *&ptr)
Definition: TDirectory.h:155
virtual void * GetObjectChecked(const char *namecycle, const char *classname)
See documentation of TDirectory::GetObjectCheck(const char *namecycle, const TClass *cl)
Definition: TDirectory.cxx:869
TList * fList
Definition: TDirectory.h:96
virtual TKey * FindKeyAny(const char *) const
Definition: TDirectory.h:143
virtual Bool_t cd(const char *path=nullptr)
Change current directory to "this" directory.
Definition: TDirectory.cxx:498
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:736
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:53
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:2135
Int_t GetVersion() const
Definition: TFile.h:236
Bool_t IsBinary() const
Definition: TFile.h:250
virtual Int_t DirReadKeys(TDirectory *)
Definition: TFile.h:166
@ kStartBigFile
Definition: TFile.h:191
TList * GetListOfFree() const
Definition: TFile.h:228
Int_t GetBestBuffer() const
Return the best buffer size of objects on this file.
Definition: TFile.cxx:1097
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:970
virtual Long64_t GetSize() const
Returns the current file size.
Definition: TFile.cxx:1259
virtual Long64_t GetEND() const
Definition: TFile.h:222
void SumBuffer(Int_t bufsize)
Increment statistics for buffer sizes of objects in this file.
Definition: TFile.cxx:2278
static TFile *& CurrentFile()
Return the current ROOT file if any.
Definition: TFile.cxx:990
virtual const TUrl * GetEndpointUrl() const
Definition: TFile.h:226
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:3942
@ kReproducible
Definition: TFile.h:188
@ kWriteError
Definition: TFile.h:185
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition: TFile.cxx:1631
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: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
virtual Int_t Read(const char *name)
Read contents of object with specified name from the current directory.
Definition: TKey.h:54
virtual void ls(Option_t *option="") const
List Key contents.
Definition: TKey.cxx:693
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:1253
virtual Int_t WriteFile(Int_t cycle=1, TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1438
virtual void * ReadObjectAny(const TClass *expectedClass)
To read an object (non deriving from TObject) from the file.
Definition: TKey.cxx:1003
void ReadKeyBuffer(char *&buffer)
Decode input buffer.
Definition: TKey.cxx:1210
virtual Long64_t GetSeekPdir() const
Definition: TKey.h:91
void SetMotherDir(TDirectory *dir)
Definition: TKey.h:112
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:738
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:1324
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:821
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:577
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:195
virtual TObject * Before(const TObject *obj) const
Returns the object before object obj.
Definition: TList.cxx:370
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:469
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:658
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: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:796
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:187
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:128
@ 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: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:891
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:919
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: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:865
static Int_t IncreaseDirLevel()
Increase the indentation level for ls().
Definition: TROOT.cxx:2773
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition: TROOT.cxx:2781
static Int_t DecreaseDirLevel()
Decrease the indentation level for ls().
Definition: TROOT.cxx:2677
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:46
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:1291
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:562
Int_t Sizeof() const
Definition: TUUID.h:85
void FillBuffer(char *&buffer)
Stream UUID into output buffer.
Definition: TUUID.cxx:266
void StreamerV1(TBuffer &b)
Stream UUID from input buffer.
Definition: TUUID.cxx:300
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:111
static constexpr double s
TCanvas * slash()
Definition: slash.C:1