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