Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TDirectoryFile.cxx
Go to the documentation of this file.
1// @(#)root/io:$Id$
2// Author: Rene Brun 22/01/2007
3
4/*************************************************************************
5 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/**
13 \class TDirectoryFile
14 \ingroup IO
15
16 A ROOT file is structured in Directories (like a file system).
17 Each Directory has a list of Keys (see TKeys) and a list of objects
18 in memory. A Key is a small object that describes the type and location
19 of a persistent object in a file. The persistent object may be a directory.
20Begin_Macro
21../../../tutorials/io/fildir.C
22End_Macro
23 The structure of a file is shown in TFile::TFile
24*/
25
26#include <iostream>
27#include "Strlen.h"
28#include "strlcpy.h"
29#include "TDirectoryFile.h"
30#include "TFile.h"
31#include "TBufferFile.h"
32#include "TBufferJSON.h"
33#include "TMapFile.h"
34#include "TClassTable.h"
35#include "TInterpreter.h"
36#include "THashList.h"
37#include "TBrowser.h"
38#include "TFree.h"
39#include "TKey.h"
40#include "TStreamerInfo.h"
41#include "TROOT.h"
42#include "TError.h"
43#include "Bytes.h"
44#include "TClass.h"
45#include "TRegexp.h"
46#include "TSystem.h"
47#include "TStreamerElement.h"
48#include "TProcessUUID.h"
49#include "TVirtualMutex.h"
52const UInt_t kIsBigFile = BIT(16);
53const Int_t kMaxLen = 2048;
54
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
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
107
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 }
155 fSeekParent = motherdir->GetSeekDir();
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()) {
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
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;
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.
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();
327}
328
329////////////////////////////////////////////////////////////////////////////////
330/// Change current directory to "this" directory.
331///
332/// Returns kTRUE in case of success.
335{
336 Bool_t ok = TDirectory::cd();
337 if (ok)
339 return ok;
340}
341
342////////////////////////////////////////////////////////////////////////////////
343/// Change current directory the directory described by the path if given one.
344/// change the current directory to "path". The absolute path syntax is:
345///
346/// file.root:/dir1/dir2
347///
348/// where file.root is the file and /dir1/dir2 the desired subdirectory
349/// in the file. Relative syntax is relative to "this" directory. E.g:
350/// ../aa. Returns kTRUE in case of success.
352Bool_t TDirectoryFile::cd(const char *path)
353{
354 Bool_t ok = TDirectory::cd(path);
355 if (ok)
357 return ok;
358}
359
360////////////////////////////////////////////////////////////////////////////////
361/// Clean the pointers to this object (gDirectory, TContext, etc.)
364{
365 // After CleanTargets either gFile was changed appropriately
366 // by a cd() or needs to be set to zero.
367 if (gFile == this) {
368 gFile = nullptr;
369 }
370
372}
373
374////////////////////////////////////////////////////////////////////////////////
375/// Make a clone of an object using the Streamer facility.
376///
377/// If the object derives from TNamed, this function is called
378/// by TNamed::Clone. TNamed::Clone uses the optional argument newname to set
379/// a new name to the newly created object.
380///
381/// If autoadd is true and if the object class has a
382/// DirectoryAutoAdd function, it will be called at the end of the
383/// function with the parameter gDirectory. This usually means that
384/// the object will be appended to the current ROOT directory.
386TObject *TDirectoryFile::CloneObject(const TObject *obj, Bool_t autoadd /* = kTRUE */)
387{
388 // if no default ctor return immediately (error issued by New())
389 char *pobj = (char*)obj->IsA()->New();
390 if (!pobj) return nullptr;
391
392 Int_t baseOffset = obj->IsA()->GetBaseClassOffset(TObject::Class());
393 if (baseOffset==-1) {
394 // cl does not inherit from TObject.
395 // Since this is not supported in this function, the only reason we could reach this code
396 // is because something is screwed up in the ROOT code.
397 Fatal("CloneObject","Incorrect detection of the inheritance from TObject for class %s.\n",
398 obj->IsA()->GetName());
399 }
401
402 //create a buffer where the object will be streamed
403 {
404 // NOTE: do we still need to make this change to gFile?
405 // NOTE: This can not be 'gDirectory=0' as at least roofit expect gDirectory to not be null
406 // during the streaming ....
407 TFile *filsav = gFile;
408 gFile = nullptr;
409 const Int_t bufsize = 10000;
411 buffer.MapObject(obj); //register obj in map to handle self reference
412 {
414 ((TObject*)obj)->ResetBit(kIsReferenced);
415
416 ((TObject*)obj)->Streamer(buffer);
417
418 if (isRef) ((TObject*)obj)->SetBit(kIsReferenced);
419 }
420
421 // read new object from buffer
422 buffer.SetReadMode();
423 buffer.ResetMap();
424 buffer.SetBufferOffset(0);
425 buffer.MapObject(newobj); //register obj in map to handle self reference
426 newobj->Streamer(buffer);
427 newobj->ResetBit(kIsReferenced);
428 newobj->ResetBit(kCanDelete);
429 gFile = filsav;
430 }
431
432 if (autoadd) {
433 ROOT::DirAutoAdd_t func = obj->IsA()->GetDirectoryAutoAdd();
434 if (func) {
435 func(newobj,this);
436 }
437 }
438 return newobj;
439}
440
441////////////////////////////////////////////////////////////////////////////////
442/// Scan the memory lists of all files for an object with name
445{
446 TFile *f;
448 TIter next(gROOT->GetListOfFiles());
449 while ((f = (TFile*)next())) {
450 TObject *obj = f->GetList()->FindObject(name);
451 if (obj) return obj;
452 }
453 return nullptr;
454}
455
456////////////////////////////////////////////////////////////////////////////////
457/// Find a directory named "apath".
458///
459/// It apath is null or empty, returns "this" directory.
460/// Otherwise use the name "apath" to find a directory.
461/// The absolute path syntax is:
462///
463/// file.root:/dir1/dir2
464///
465/// where file.root is the file and /dir1/dir2 the desired subdirectory
466/// in the file. Relative syntax is relative to "this" directory. E.g:
467/// ../aa.
468/// Returns 0 in case path does not exist.
469/// If printError is true, use Error with 'funcname' to issue an error message.
472 Bool_t printError, const char *funcname)
473{
474 Int_t nch = 0;
475 if (apath) nch = strlen(apath);
476 if (!nch) {
477 return this;
478 }
479
480 if (funcname==0 || strlen(funcname)==0) funcname = "GetDirectory";
481
482 TDirectory *result = this;
483
484 char *path = new char[nch+1]; path[0] = 0;
485 if (nch) strlcpy(path,apath,nch+1);
486 char *s = (char*)strchr(path, ':');
487 if (s) {
488 *s = '\0';
490 TDirectory *f = (TDirectory *)gROOT->GetListOfFiles()->FindObject(path);
491 // Check if this is a duplicate (2nd opening) on this file and prefer
492 // this file.
493 if (GetFile()) {
494 auto url = GetFile()->GetEndpointUrl();
495 if (f && 0 == url->Compare(f->GetFile()->GetEndpointUrl())) {
496 result = GetDirectory(s+1,printError,funcname);
497 delete [] path;
498 return result;
499 }
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 nullptr;
510 }
511 }
512
513 // path starts with a slash (assumes current file)
514 if (path[0] == '/') {
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, "..")) {
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 nullptr;
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, "..")) {
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 nullptr;
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;
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
595}
596
597////////////////////////////////////////////////////////////////////////////////
598/// Delete Objects or/and keys in the current directory.
599///
600/// \param[in] namecycle Encodes the name and cycle of the objects to delete in
601/// the current directory (e.g. the top directory of a TFile)
602/// - <em>namecycle</em> has the format <em>name;cycle</em>.
603/// - <em>namecycle</em>="" is same as <em>namecycle</em>="T*"
604/// - <em>name</em>="*" means all objects, use "T*" to also delete subdirectories
605/// - <em>cycle</em>="*" means all cycles (memory and keys)
606/// - <em>cycle</em>="" or <em>cycle</em>="9999" ==> apply to a memory object
607/// - When <em>name</em>="*"" use "T*" to delete subdirectories also
608///
609/// To delete one directory, you must specify the directory cycle,
610/// eg. file.Delete("dir1;1");
611///
612/// Examples:
613/// | Pattern | Description |
614/// |---------|-------------|
615/// | foo | delete object named foo in memory |
616/// | foo* | delete all objects with a name starting with foo |
617/// | foo;1 | delete cycle 1 of foo on file |
618/// | foo;* | delete all cycles of foo on file and also from memory |
619/// | *;2 | delete all objects on file having the cycle 2 |
620/// | *;* | delete all objects from memory and file |
621/// | T*;* | delete all objects from memory and file and all subdirectories |
622///
623/// \note For some objects, this method, which is used e.g. by rootrm,
624/// properly deletes the specified cycles of the object, but does not free any ‘dependent’
625/// data records (unless it is a TDirectoryFile). In other words, in these cases, Delete
626/// does not free all subdata records, but rather orphans them, ie. the file size is not
627/// reduced, and there is later no option to shrink it nor recover the disappeared ‘dependent’
628/// items. For example, deleting a TTree does not free up space from the directory since the
629/// underlying basket records are not recursively deleted. If this is wanted, one can call
630/// TTree::Delete("all") before calling TDirectoryFile::Delete(); file size won't
631/// shrink either, but more space will be left open for overwriting with other objects.
632/// See also Purge() documentation. A workaround to reduce filesize is to clone all
633/// objects (excluding those to be deleted) into a new TFile.
634///
635/// ## WARNING
636/// If the key to be deleted contains special characters ("+","^","?", etc)
637/// that have a special meaning for the regular expression parser (see TRegexp)
638/// then you must specify 2 backslash characters to escape the regular expression.
639/// For example, if the key to be deleted is namecycle = "C++", you must call
640///
641/// mydir.Delete("C\\+\\+"));
642///
644void TDirectoryFile::Delete(const char *namecycle)
645{
646 if (gDebug)
647 Info("Delete","Call for this = %s namecycle = %s",
648 GetName(), (namecycle ? namecycle : "null"));
649
651 Short_t cycle;
652 char name[kMaxLen];
653 const char *nmcy = (namecycle) ? namecycle : "";
655
656 Int_t deleteall = 0;
657 Int_t deletetree = 0;
658 if(strcmp(name,"*") == 0) deleteall = 1;
659 if(strcmp(name,"*T") == 0){ deleteall = 1; deletetree = 1;}
660 if(strcmp(name,"T*") == 0){ deleteall = 1; deletetree = 1;}
661 if(namecycle==0 || !namecycle[0]){ deleteall = 1; deletetree = 1;}
662 TRegexp re(name,kTRUE);
663 TString s;
664 Int_t deleteOK = 0;
665
666//*-*---------------------Case of Object in memory---------------------
667// ========================
668 if (cycle >= 9999 ) {
669 TNamed *idcur;
670 TIter next(fList);
671 while ((idcur = (TNamed *) next())) {
672 deleteOK = 0;
673 s = idcur->GetName();
674 if (deleteall || s.Index(re) != kNPOS) {
675 deleteOK = 1;
676 if (idcur->IsA() == TDirectoryFile::Class()) {
677 deleteOK = 2;
678 if (!deletetree && deleteall) deleteOK = 0;
679 }
680 }
681 if (deleteOK != 0) {
683 if (deleteOK==2) {
684 // read subdirectories to correctly delete them
685 if (deletetree)
686 ((TDirectory*) idcur)->ReadAll("dirs");
687 idcur->Delete(deletetree ? "T*;*" : "*");
688 delete idcur;
689 } else
690 idcur->Delete(name);
691 }
692 }
693// if (deleteOK == 2) {
694// Info("Delete","Dir:%lx %s", fList->FindObject(name), name);
695// delete fList->FindObject(name); //deleting a TDirectory
696// }
697 }
698//*-*---------------------Case of Key---------------------
699// ===========
700 if (cycle != 9999 ) {
701 if (IsWritable()) {
702 TKey *key;
704 while ((key = (TKey *) nextkey())) {
705 deleteOK = 0;
706 s = key->GetName();
707 if (deleteall || s.Index(re) != kNPOS) {
708 if (cycle == key->GetCycle()) deleteOK = 1;
709 if (cycle > 9999) deleteOK = 1;
710 //if (!strcmp(key->GetClassName(),"TDirectory")) {
711 if (strstr(key->GetClassName(),"TDirectory")) {
712 deleteOK = 2;
713 if (!deletetree && deleteall) deleteOK = 0;
714 if (cycle == key->GetCycle()) deleteOK = 2;
715 }
716 }
717 if (deleteOK) {
718 if (deleteOK==2) {
719 // read directory with subdirectories to correctly delete and free key structure
720 TDirectory* dir = GetDirectory(key->GetName(), kTRUE, "Delete");
721 if (dir!=0) {
722 dir->Delete("T*;*");
723 fList->Remove(dir);
724 delete dir;
725 }
726 }
727
728 key->Delete();
729 fKeys->Remove(key);
731 delete key;
732 }
733 }
734 TFile* f = GetFile();
735 if (fModified && (f!=0)) {
736 WriteKeys(); //*-* Write new keys structure
737 WriteDirHeader(); //*-* Write new directory header
738 f->WriteFree(); //*-* Write new free segments list
739 f->WriteHeader(); //*-* Write new file header
740 }
741 }
742 }
743}
744
745////////////////////////////////////////////////////////////////////////////////
746/// Encode directory header into output buffer
748void TDirectoryFile::FillBuffer(char *&buffer)
749{
754 {
755 // One of the address is larger than 2GB we need to use longer onfile
756 // integer, thus we increase the version number.
757 // Note that fSeekDir and fSeekKey are not necessarily correlated, if
758 // some object are 'removed' from the file and the holes are reused.
759 version += 1000;
760 }
761 tobuf(buffer, version);
763 if (reproducible) {
764 TDatime((UInt_t) 1).FillBuffer(buffer);
765 TDatime((UInt_t) 1).FillBuffer(buffer);
766 } else {
767 fDatimeC.FillBuffer(buffer);
768 fDatimeM.FillBuffer(buffer);
769 }
770 tobuf(buffer, fNbytesKeys);
771 tobuf(buffer, fNbytesName);
772 if (version > 1000) {
773 tobuf(buffer, fSeekDir);
774 tobuf(buffer, fSeekParent);
775 tobuf(buffer, fSeekKeys);
776 } else {
777 tobuf(buffer, (Int_t)fSeekDir);
778 tobuf(buffer, (Int_t)fSeekParent);
779 tobuf(buffer, (Int_t)fSeekKeys);
780 }
781 if (reproducible)
782 TUUID("00000000-0000-0000-0000-000000000000").FillBuffer(buffer);
783 else
784 fUUID.FillBuffer(buffer);
785 if (fFile && fFile->GetVersion() < 40000) return;
786 if (version <=1000) for (Int_t i=0;i<3;i++) tobuf(buffer,Int_t(0));
787}
788
789////////////////////////////////////////////////////////////////////////////////
790/// Find key with name `keyname` in the current directory.
791/// `keyname` may be of the form name;cycle.
792/// See GetKey() for details on the semantics of this form.
794TKey *TDirectoryFile::FindKey(const char *keyname) const
795{
796 Short_t cycle;
797 char name[kMaxLen];
798
800 return GetKey(name,cycle);
801}
802
803////////////////////////////////////////////////////////////////////////////////
804/// Find key with name `keyname` in the current directory or
805/// its subdirectories.
806/// `keyname` may be of the form name;cycle.
807/// See GetKey() for details on the semantics of this form.
808///
809/// NOTE: that If a key is found, the directory containing the key becomes
810/// the current directory
812TKey *TDirectoryFile::FindKeyAny(const char *keyname) const
813{
815 Short_t cycle;
816 char name[kMaxLen];
817
819
820 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
821 if (!listOfKeys) {
822 Error("FindKeyAny", "Unexpected type of TDirectoryFile::fKeys!");
823 return nullptr;
824 }
825
826 if (const TList *keyList = listOfKeys->GetListForObject(name)) {
827 for (auto key: TRangeDynCast<TKey>(*keyList)) {
828 if (key && !strcmp(key->GetName(), name)
829 && (cycle == 9999 || cycle >= key->GetCycle())) {
830 const_cast<TDirectoryFile*>(this)->cd(); // may be we should not make cd ???
831 return key;
832 }
833 }
834 }
835
836 //try with subdirectories
837 TIter next(GetListOfKeys());
838 TKey *key;
839 while ((key = (TKey *) next())) {
840 //if (!strcmp(key->GetClassName(),"TDirectory")) {
841 if (strstr(key->GetClassName(),"TDirectory")) {
843 const_cast<TDirectoryFile*>(this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
844 TKey *k = subdir ? subdir->FindKeyAny(keyname) : nullptr;
845 if (k) return k;
846 }
847 }
848 if (dirsav) dirsav->cd();
849 return nullptr;
850}
851
852////////////////////////////////////////////////////////////////////////////////
853/// Find object by name in the list of memory objects of the current
854/// directory or its sub-directories.
855///
856/// After this call the current directory is not changed.
857/// To automatically set the current directory where the object is found,
858/// use FindKeyAny(aname)->ReadObj().
861{
862 //object may be already in the list of objects in memory
864 if (obj) return obj;
865
867 Short_t cycle;
868 char name[kMaxLen];
869
871
872 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
873 if (!listOfKeys) {
874 Error("FindObjectAny", "Unexpected type of TDirectoryFile::fKeys!");
875 return nullptr;
876 }
877
878 if (const TList *keyList = listOfKeys->GetListForObject(name)) {
879 for (auto key: TRangeDynCast<TKey>(*keyList)) {
880 if (key && !strcmp(key->GetName(), name)
881 && (cycle == 9999 || cycle >= key->GetCycle())) {
882 return key->ReadObj();
883 }
884 }
885 }
886
887 //try with subdirectories
888 TIter next(GetListOfKeys());
889 TKey *key;
890 while ((key = (TKey *) next())) {
891 //if (!strcmp(key->GetClassName(),"TDirectory")) {
892 if (strstr(key->GetClassName(),"TDirectory")) {
894 ((TDirectory*)this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
895 TKey *k = subdir ? subdir->FindKeyAny(aname) : nullptr;
896 if (k) { if (dirsav) dirsav->cd(); return k->ReadObj();}
897 }
898 }
899 if (dirsav) dirsav->cd();
900 return nullptr;
901}
902
903////////////////////////////////////////////////////////////////////////////////
904/// Return pointer to object identified by namecycle.
905///
906/// Properties:
907/// - namecycle has the format name;cycle
908/// - name = * is illegal, cycle = * is illegal
909/// - cycle = "" or cycle = 9999 ==> apply to a memory object
910///
911/// Examples:
912/// | %Pattern | Explanation |
913/// |----------|-------------|
914/// | foo | get object named foo in memory if object is not in memory, try with highest cycle from file |
915/// | foo;1 | get cycle 1 of foo on file |
916///
917/// The retrieved object should in principle derive from TObject.
918/// If not, the function TDirectoryFile::Get<T> should be called.
919/// However, this function will still work for a non-TObject, provided that
920/// the calling application cast the return type to the correct type (which
921/// is the actual type of the object).
922///
923/// ### The Get<T> Method
924/// The method Get<T> offers better protection and avoids the need for any
925/// cast:
926/// ~~~{.cpp}
927/// auto objPtr = directory->Get<MyClass>("some object");
928/// if (objPtr) { ... the object exist and inherits from MyClass ... }
929/// ~~~
930///
931/// ### Very important note about inheritance
932/// In case the class of this object derives from TObject but not
933/// as a first inheritance, one must use dynamic_cast<>().
934///
935/// #### Example 1 - Normal case:
936///
937/// class MyClass : public TObject, public AnotherClass
938///
939/// then on return, one can adopt a C style cast:
940///
941/// auto objPtr = (MyClass*)directory->Get("some object of MyClass");
942///
943/// #### Example 2 - Special case:
944///
945/// class MyClass : public AnotherClass, public TObject
946///
947/// then on return, one must do:
948///
949/// auto objPtr = dynamic_cast<MyClass*>(directory->Get("some object of MyClass"));
950///
951/// Of course, dynamic_cast<> can also be used in the example 1.
952///
955{
956 Short_t cycle;
957 char name[kMaxLen];
958
960 Int_t nch = strlen(name);
961 for (Int_t i = nch-1; i > 0; i--) {
962 if (name[i] == '/') {
963 name[i] = 0;
965 const char *subnamecycle = namecycle + i + 1;
966 name[i] = '/';
967 return dirToSearch?dirToSearch->Get(subnamecycle):0;
968 }
969 }
970 const char *namobj = name;
971
972//*-*---------------------Case of Object in memory---------------------
973// ========================
974 TObject *idcur = fList ? fList->FindObject(namobj) : nullptr;
975 if (idcur) {
976 if (idcur==this && strlen(namobj)!=0) {
977 // The object has the same name has the directory and
978 // that's what we picked-up! We just need to ignore
979 // it ...
980 idcur = nullptr;
981 } else if (cycle == 9999) {
982 return idcur;
983 } else {
984 if (idcur->InheritsFrom(TCollection::Class()))
985 idcur->Delete(); // delete also list elements
986 delete idcur;
987 idcur = nullptr;
988 }
989 }
990
991//*-*---------------------Case of Key---------------------
992// ===========
993 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
994 if (!listOfKeys) {
995 Error("Get", "Unexpected type of TDirectoryFile::fKeys!");
996 return nullptr;
997 }
998
999 if (const TList *keyList = listOfKeys->GetListForObject(namobj)) {
1000 for (auto key: TRangeDynCast<TKey>(*keyList)) {
1001 if (key && !strcmp(key->GetName(), namobj)
1002 && (cycle == 9999 || cycle == key->GetCycle())) {
1004 return key->ReadObj();
1005 }
1006 }
1007 }
1008
1009 return nullptr;
1010}
1011
1012////////////////////////////////////////////////////////////////////////////////
1013/// Return pointer to object identified by namecycle.
1014///
1015/// The returned object may or may not derive from TObject.
1016///
1017/// - namecycle has the format name;cycle
1018/// - name = * is illegal, cycle = * is illegal
1019/// - cycle = "" or cycle = 9999 ==> apply to a memory object
1020///
1021/// ## Very important note
1022/// The calling application must cast the returned object to
1023/// the final type, e.g.
1024///
1025/// auto objPtr = (MyClass*)directory->GetObject("some object of MyClass");
1028{
1029 return GetObjectChecked(namecycle,(TClass*)nullptr);
1030}
1031
1032////////////////////////////////////////////////////////////////////////////////
1033/// See documentation of TDirectoryFile::GetObjectCheck(const char *namecycle, const TClass *cl)
1035void *TDirectoryFile::GetObjectChecked(const char *namecycle, const char* classname)
1036{
1037 return GetObjectChecked(namecycle,TClass::GetClass(classname));
1038}
1039
1040
1041////////////////////////////////////////////////////////////////////////////////
1042/// Return pointer to object identified by namecycle if and only if the actual
1043/// object is a type suitable to be stored as a pointer to a "expectedClass"
1044/// If expectedClass is null, no check is performed.
1045///
1046/// - namecycle has the format name;cycle
1047/// - name = * is illegal, cycle = * is illegal
1048/// - cycle = "" or cycle = 9999 ==> apply to a memory object
1049///
1050/// ### Very important note
1051/// The calling application must cast the returned pointer to
1052/// the type described by the 2 arguments (i.e. cl):
1053///
1054/// auto objPtr = (MyClass*)directory->GetObjectChecked("some object of MyClass","MyClass"));
1055///
1056/// Note: We recommend using the method TDirectoryFile::Get<T>:
1057/// ~~~{.cpp}
1058/// auto objPtr = directory->Get<MyClass>("some object inheriting from MyClass");
1059/// if (objPtr) { ... we found what we are looking for ... }
1060/// ~~~
1063{
1064
1065 // If the name is invalid, issue an error message and return a nullptr
1066 if (!namecycle || '\0' == namecycle[0]) {
1067 Error("GetObjectChecked", "The provided key name is invalid.");
1068 return nullptr;
1069 }
1070
1071 Short_t cycle;
1072 char name[kMaxLen];
1073
1075 Int_t nch = strlen(name);
1076 for (Int_t i = nch-1; i > 0; i--) {
1077 if (name[i] == '/') {
1078 name[i] = 0;
1080 const char *subnamecycle = namecycle + i + 1;
1081 name[i] = '/';
1082 if (dirToSearch) {
1083 return dirToSearch->GetObjectChecked(subnamecycle, expectedClass);
1084 } else {
1085 return nullptr;
1086 }
1087 }
1088 }
1089 const char *namobj = name;
1090
1091//*-*---------------------Case of Object in memory---------------------
1092// ========================
1093 if (expectedClass==0 || expectedClass->IsTObject()) {
1094 TObject *objcur = fList ? fList->FindObject(namobj) : nullptr;
1095 if (objcur) {
1096 if (objcur==this && strlen(namobj)!=0) {
1097 // The object has the same name has the directory and
1098 // that's what we picked-up! We just need to ignore
1099 // it ...
1100 objcur = nullptr;
1101 } else if (cycle == 9999) {
1102 // Check type
1103 if (expectedClass && objcur->IsA()->GetBaseClassOffset(expectedClass) == -1) return nullptr;
1104 else return objcur;
1105 } else {
1106 if (objcur->InheritsFrom(TCollection::Class()))
1107 objcur->Delete(); // delete also list elements
1108 delete objcur;
1109 objcur = nullptr;
1110 }
1111 }
1112 }
1113
1114//*-*---------------------Case of Key---------------------
1115// ===========
1116 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
1117 if (!listOfKeys) {
1118 Error("GetObjectChecked", "Unexpected type of TDirectoryFile::fKeys!");
1119 return nullptr;
1120 }
1121
1122 if (const TList *keyList = listOfKeys->GetListForObject(namobj)) {
1123 for (auto key: TRangeDynCast<TKey>(*keyList)) {
1124 if (key && !strcmp(key->GetName(), namobj)
1125 && (cycle == 9999 || cycle == key->GetCycle())) {
1127 return key->ReadObjectAny(expectedClass);
1128 }
1129 }
1130 }
1131
1132 return nullptr;
1133}
1134
1135////////////////////////////////////////////////////////////////////////////////
1136/// Return the buffer size to create new TKeys.
1137///
1138/// If the stored fBufferSize is null, the value returned is the average
1139/// buffer size of objects in the file so far.
1142{
1143 if (fBufferSize <= 0) return fFile->GetBestBuffer();
1144 else return fBufferSize;
1145}
1146
1147
1148////////////////////////////////////////////////////////////////////////////////
1149/// Return pointer to key with name,cycle. If no key exists with the specified
1150/// cycle, returns the key with the highest cycle that is lower than the requested cycle.
1151///
1152/// if cycle = 9999 returns highest cycle
1154TKey *TDirectoryFile::GetKey(const char *name, Short_t cycle) const
1155{
1156 if (!fKeys) return nullptr;
1157
1158 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
1159 if (!listOfKeys) {
1160 Error("GetKey", "Unexpected type of TDirectoryFile::fKeys!");
1161 return nullptr;
1162 }
1163
1164 if (const TList *keyList = listOfKeys->GetListForObject(name)) {
1165 for (auto key: TRangeDynCast<TKey>(*keyList)) {
1166 if (key && !strcmp(key->GetName(), name)
1167 && (cycle == 9999 || cycle >= key->GetCycle())) {
1168 return key;
1169 }
1170 }
1171 }
1172
1173 return nullptr;
1174}
1175
1176////////////////////////////////////////////////////////////////////////////////
1177/// List Directory contents
1178///
1179/// Indentation is used to identify the directory tree
1180/// Subdirectories are listed first, then objects in memory, then objects on the file
1181///
1182/// The option can has the following format: <b>`[-d |-m][<regexp>]`</b>
1183/// Options:
1184/// - -d: only list objects in the file
1185/// - -m: only list objects in memory
1186/// The `<regexp>` will be used to match the name of the objects.
1187/// By default memory and disk objects are listed.
1190{
1192 std::cout <<ClassName()<<"*\t\t"<<GetName()<<"\t"<<GetTitle()<<std::endl;
1194
1196 TString opt = opta.Strip(TString::kBoth);
1199 TString reg;
1200 if (opt.BeginsWith("-m")) {
1201 diskobj = kFALSE;
1202 if (opt.Length() > 2) {
1203 reg = opt(2,opt.Length());
1204 }
1205 } else if (opt.BeginsWith("-d")) {
1206 memobj = kFALSE;
1207 if (opt.Length() > 2) {
1208 reg = opt(2,opt.Length());
1209 }
1210 } else if (!opt.IsNull()) {
1211 reg = opt;
1212 }
1213
1214 TRegexp re(reg, kTRUE);
1215
1216 if (memobj) {
1217 TObject *obj;
1219 while ((obj = (TObject *) nextobj())) {
1220 TString s = obj->GetName();
1221 if (!reg.IsNull() && s.Index(re) == kNPOS)
1222 continue;
1223 obj->ls(option); //*-* Loop on all the objects in memory
1224 }
1225 }
1226
1227 if (diskobj && fKeys) {
1228 //*-* Loop on all the keys
1229 for (TObjLink *lnk = fKeys->FirstLink(); lnk != nullptr; lnk = lnk->Next()) {
1230 TKey *key = (TKey*)lnk->GetObject();
1231 TString s = key->GetName();
1232 if (!reg.IsNull() && s.Index(re) == kNPOS)
1233 continue;
1234 bool first = (lnk->Prev() == nullptr) || (s != lnk->Prev()->GetObject()->GetName());
1235 bool hasbackup = (lnk->Next() != nullptr) && (s == lnk->Next()->GetObject()->GetName());
1236 if (first)
1237 if (hasbackup)
1238 key->ls(true);
1239 else
1240 key->ls();
1241 else
1242 key->ls(false);
1243 }
1244 }
1246}
1247
1248////////////////////////////////////////////////////////////////////////////////
1249/// Interface to TFile::Open
1255}
1256
1257////////////////////////////////////////////////////////////////////////////////
1258/// Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...".
1259///
1260/// @param name the name or hierarchy of the subdirectory ("a" or "a/b/c")
1261/// @param title the title of the directory. For hierarchies, this is only applied
1262/// to the innermost directory (so if `name == "a/b/c"` and `title == "my dir"`,
1263/// only `c` will have the title `"my dir"`).
1264/// @param returnExistingDirectory if key-name is already existing, the returned
1265/// value points to preexisting sub-directory if true and to `nullptr` if false.
1266/// @return a pointer to the created sub-directory, not to the top sub-directory
1267/// of the hierarchy (in the above example, the returned TDirectory * points
1268/// to "c"). In case of an error, it returns `nullptr`. In case of a preexisting
1269/// sub-directory (hierarchy) with the requested name, the return value depends
1270/// on the parameter returnExistingDirectory.
1272TDirectory *TDirectoryFile::mkdir(const char *name, const char *title, Bool_t returnExistingDirectory)
1273{
1274 if (!name || !title || !name[0]) return nullptr;
1275 if (!title[0]) title = name;
1276 if (GetKey(name)) {
1278 return (TDirectoryFile*) GetDirectory(name);
1279 else {
1280 Error("mkdir","An object with name %s exists already",name);
1281 return nullptr;
1282 }
1283 }
1284 if (const char *slash = strchr(name,'/')) {
1286 TDirectoryFile *tmpdir = nullptr;
1287 GetObject(workname.Data(), tmpdir);
1288 if (!tmpdir) {
1289 // We give all intermediate directories a default title, as `title` is only given to the innermost dir.
1290 tmpdir = (TDirectoryFile *)mkdir(workname.Data(), "");
1291 if (!tmpdir) return nullptr;
1292 }
1293 return tmpdir->mkdir(slash + 1, title, returnExistingDirectory);
1294 }
1295
1297
1298 return new TDirectoryFile(name, title, "", this);
1299}
1300
1301////////////////////////////////////////////////////////////////////////////////
1302/// Purge lowest key cycles in a directory.
1303///
1304/// By default, only the highest cycle of a key is kept. Keys for which
1305/// the "KEEP" flag has been set are not removed. See TKey::Keep().
1306/// NOTE: This does not reduce the size of a TFile--
1307/// the space is simply freed up to be overwritten.
1310{
1311 if (!IsWritable()) return;
1312
1314
1315 TKey *key;
1317
1318 while ((key = (TKey*)prev())) { // reverse loop on keys
1319 TKey *keyprev = (TKey*)GetListOfKeys()->Before(key);
1320 if (!keyprev) break;
1321 if (key->GetKeep() == 0) {
1322 if (strcmp(key->GetName(), keyprev->GetName()) == 0) {
1323 key->Delete(); // Remove from the file.
1324 delete key; // Remove from memory.
1325 }
1326 }
1327 }
1328 TFile *f = GetFile();
1329 if (fModified && f) {
1330 WriteKeys(); // Write new keys structure
1331 WriteDirHeader(); // Write new directory header
1332 f->WriteFree(); // Write new free segments list
1333 f->WriteHeader(); // Write new file header
1334 }
1335}
1336
1337////////////////////////////////////////////////////////////////////////////////
1338/// Read objects from a ROOT file directory into memory.
1339///
1340/// If an object is already in memory, the memory copy is deleted
1341/// and the object is again read from the file.
1342/// If opt=="dirs", only subdirectories will be read
1343/// If opt=="dirs*" complete directory tree will be read
1346{
1348
1349 TKey *key;
1350 TIter next(GetListOfKeys());
1351
1352 Bool_t readdirs = ((opt!=0) && ((strcmp(opt,"dirs")==0) || (strcmp(opt,"dirs*")==0)));
1353
1354 if (readdirs)
1355 while ((key = (TKey *) next())) {
1356
1357 //if (strcmp(key->GetClassName(),"TDirectory")!=0) continue;
1358 if (strstr(key->GetClassName(),"TDirectory")==0) continue;
1359
1360 TDirectory *dir = GetDirectory(key->GetName(), kTRUE, "ReadAll");
1361
1362 if ((dir!=0) && (strcmp(opt,"dirs*")==0)) dir->ReadAll("dirs*");
1363 }
1364 else
1365 while ((key = (TKey *) next())) {
1366 TObject *thing = GetList()->FindObject(key->GetName());
1367 if (thing) { delete thing; }
1368 key->ReadObj();
1369 }
1370}
1371
1372////////////////////////////////////////////////////////////////////////////////
1373/// Read the linked list of keys.
1374///
1375/// Every directory has a linked list (fKeys). This linked list has been
1376/// written on the file via WriteKeys as a single data record.
1377///
1378/// It is interesting to call this function in the following situation.
1379/// Assume another process1 is connecting this directory in Update mode
1380/// - Process1 is adding/updating objects in this directory
1381/// - You want to see the latest status from process1.
1382/// Example Process1:
1383/// ~~~{.cpp}
1384/// obj1.Write();
1385/// obj2.Write();
1386/// gDirectory->SaveSelf();
1387/// ~~~
1388///
1389/// Example Process2:
1390/// ~~~{.cpp}
1391/// gDirectory->ReadKeys();
1392/// obj1->Draw();
1393/// ~~~
1394/// This is an efficient way (without opening/closing files) to view
1395/// the latest updates of a file being modified by another process
1396/// as it is typically the case in a data acquisition system.
1399{
1400 if (!fFile || !fKeys) return 0;
1401
1402 if (!fFile->IsBinary())
1403 return fFile->DirReadKeys(this);
1404
1406
1407 char *buffer;
1408 if (forceRead) {
1409 fKeys->Delete();
1410 //In case directory was updated by another process, read new
1411 //position for the keys
1413 char *header = new char[nbytes];
1414 buffer = header;
1416 if ( fFile->ReadBuffer(buffer,nbytes) ) {
1417 // ReadBuffer return kTRUE in case of failure.
1418 delete [] header;
1419 return 0;
1420 }
1421 buffer += fNbytesName;
1423 frombuf(buffer,&versiondir);
1424 fDatimeC.ReadBuffer(buffer);
1425 fDatimeM.ReadBuffer(buffer);
1426 frombuf(buffer, &fNbytesKeys);
1427 frombuf(buffer, &fNbytesName);
1428 if (versiondir > 1000) {
1429 frombuf(buffer, &fSeekDir);
1430 frombuf(buffer, &fSeekParent);
1431 frombuf(buffer, &fSeekKeys);
1432 } else {
1434 frombuf(buffer, &sdir); fSeekDir = (Long64_t)sdir;
1436 frombuf(buffer, &skeys); fSeekKeys = (Long64_t)skeys;
1437 }
1438 delete [] header;
1439 }
1440
1441 Int_t nkeys = 0;
1442 Long64_t fsize = fFile->GetSize();
1443 if ( fSeekKeys > 0) {
1444 TKey *headerkey = new TKey(fSeekKeys, fNbytesKeys, this);
1445 headerkey->ReadFile();
1446 buffer = headerkey->GetBuffer();
1447 headerkey->ReadKeyBuffer(buffer);
1448
1449 TKey *key;
1450 frombuf(buffer, &nkeys);
1451 for (Int_t i = 0; i < nkeys; i++) {
1452 key = new TKey(this);
1453 key->ReadKeyBuffer(buffer);
1454 if (key->GetSeekKey() < 64 || key->GetSeekKey() > fsize) {
1455 Error("ReadKeys","reading illegal key, exiting after %d keys",i);
1456 fKeys->Remove(key);
1457 nkeys = i;
1458 break;
1459 }
1460 if (key->GetSeekPdir() < 64 || key->GetSeekPdir() > fsize) {
1461 Error("ReadKeys","reading illegal key, exiting after %d keys",i);
1462 fKeys->Remove(key);
1463 nkeys = i;
1464 break;
1465 }
1466 fKeys->Add(key);
1467 }
1468 delete headerkey;
1469 }
1470
1471 return nkeys;
1472}
1473
1474
1475////////////////////////////////////////////////////////////////////////////////
1476/// Read object with keyname from the current directory
1477///
1478/// Read contents of object with specified name from the current directory.
1479/// First the key with keyname is searched in the current directory,
1480/// next the key buffer is deserialized into the object.
1481/// The object must have been created before via the default constructor.
1482/// See TObject::Write().
1485{
1486 if (!fFile) { Error("ReadTObject","No file open"); return 0; }
1487 auto listOfKeys = dynamic_cast<THashList *>(GetListOfKeys());
1488 if (!listOfKeys) {
1489 Error("ReadTObject", "Unexpected type of TDirectoryFile::fKeys!");
1490 return 0;
1491 }
1492
1493 if (const TList *keyList = listOfKeys->GetListForObject(keyname)) {
1494 for (auto key: TRangeDynCast<TKey>(*keyList)) {
1495 if (key && !strcmp(key->GetName(), keyname) ) {
1496 return key->Read(obj);
1497 }
1498 }
1499 }
1500
1501 Error("ReadTObject","Key not found");
1502 return 0;
1503}
1504
1505////////////////////////////////////////////////////////////////////////////////
1506/// Reset the TDirectory after its content has been merged into another
1507/// Directory.
1508///
1509/// This returns the TDirectoryFile object back to its state
1510/// before any data has been written to the file.
1511/// The object in the in-memory list are assumed to also have been reset.
1514{
1515 // There is nothing to reset in the base class (TDirectory) since
1516 // we do want to key the list of in-memory object as is.
1517 fModified = kFALSE;
1518 // Does not change: fWritable
1519 fDatimeC.Set();
1520 fDatimeM.Set();
1521 fNbytesKeys = 0; // updated when the keys are written
1522 fNbytesName = 0; // updated by Init
1523 // Does not change (user customization): fBufferSize;
1524 fSeekDir = 0; // updated by Init
1525 fSeekParent = 0; // updated by Init
1526 fSeekKeys = 0; // updated by Init
1527 // Does not change: fFile
1528 TKey *key = fKeys ? (TKey*)fKeys->FindObject(fName) : nullptr;
1529 TClass *cl = IsA();
1530 if (key) {
1531 cl = TClass::GetClass(key->GetClassName());
1532 }
1533 // NOTE: We should check that the content is really mergeable and in
1534 // the in-mmeory list, before deleting the keys.
1535 if (fKeys) {
1536 fKeys->Delete("slow");
1537 }
1538
1540
1541 // Do the same with the sub-directories.
1542 TIter next(GetList());
1543 TObject *idcur;
1544 while ((idcur = next())) {
1545 if (idcur->IsA() == TDirectoryFile::Class()) {
1546 ((TDirectoryFile*)idcur)->ResetAfterMerge(info);
1547 }
1548 }
1549
1550}
1551
1552////////////////////////////////////////////////////////////////////////////////
1553/// Removes subdirectory from the directory
1554///
1555/// When directory is deleted, all keys in all subdirectories will be
1556/// read first and deleted from file (if exists)
1557/// Equivalent call is Delete("name;*");
1559void TDirectoryFile::rmdir(const char *name)
1560{
1561 if (!name || (*name==0)) return;
1562
1563 TString mask(name);
1564 mask += ";*";
1565 Delete(mask);
1566}
1567
1568////////////////////////////////////////////////////////////////////////////////
1569/// Save recursively all directory keys and headers
1572{
1574
1575 SaveSelf();
1576
1577 // recursively save all sub-directories
1578 if (fList && fList->FirstLink()) {
1579 auto lnk = fList->FirstLink()->shared_from_this();
1580 while (lnk) {
1581 TObject *idcur = lnk->GetObject();
1582 if (TDirectoryFile *dir = dynamic_cast<TDirectoryFile *>(idcur)) {
1583 dir->Save();
1584 }
1585 lnk = lnk->NextSP();
1586 }
1587 }
1588}
1589
1590////////////////////////////////////////////////////////////////////////////////
1591/// Save object in filename.
1592///
1593/// If filename is `nullptr` or "", a file with "<objectname>.root" is created.
1594/// The name of the key is the object name.
1595/// By default new file will be created. Using option "a", one can append object
1596/// to the existing ROOT file.
1597/// If the operation is successful, it returns the number of bytes written to the file
1598/// otherwise it returns 0.
1599/// By default a message is printed. Use option "q" to not print the message.
1600/// If filename contains ".json" extension, JSON representation of the object
1601/// will be created and saved in the text file. Such file can be used in
1602/// JavaScript ROOT (https://root.cern/js/) to display object in web browser
1603/// When creating JSON file, option string may contain compression level from 0 to 3 (default 0)
1605Int_t TDirectoryFile::SaveObjectAs(const TObject *obj, const char *filename, Option_t *option) const
1606{
1607 // option can contain single letter args: "a" for append, "q" for quiet in any combinations
1608
1609 if (!obj) return 0;
1610 TString fname, opt = option;
1611 if (filename && *filename)
1612 fname = filename;
1613 else
1614 fname.Form("%s.root", obj->GetName());
1615 opt.ToLower();
1616
1617 Int_t nbytes = 0;
1618 if (fname.Index(".json") > 0) {
1620 } else {
1621 TContext ctxt; // The TFile::Open will change the current directory.
1622 auto *local = TFile::Open(fname.Data(), opt.Contains("a") ? "update" : "recreate");
1623 if (!local) return 0;
1624 nbytes = obj->Write();
1625 delete local;
1626 }
1627 if (!opt.Contains("q") && !gSystem->AccessPathName(fname.Data()))
1628 obj->Info("SaveAs", "ROOT file %s has been created", fname.Data());
1629 return nbytes;
1630}
1631
1632////////////////////////////////////////////////////////////////////////////////
1633/// Save Directory keys and header
1634///
1635/// If the directory has been modified (fModified set), write the keys
1636/// and the directory header. This function assumes the cd is correctly set.
1637///
1638/// It is recommended to use this function in the following situation:
1639/// Assume a process1 using a directory in Update mode
1640/// - New objects or modified objects have been written to the directory.
1641/// - You do not want to close the file.
1642/// - You want your changes be visible from another process2 already connected
1643/// to this directory in read mode.
1644/// - Call this function.
1645/// - In process2, use TDirectoryFile::ReadKeys to refresh the directory.
1648{
1649 if (IsWritable() && (fModified || force) && fFile) {
1651 if (fFile->GetListOfFree())
1652 dowrite = fFile->GetListOfFree()->First() != nullptr;
1653 if (dowrite) {
1655 if (dirsav != this) cd();
1656 WriteKeys(); //*-*- Write keys record
1657 WriteDirHeader(); //*-*- Update directory record
1658 if (dirsav && dirsav != this) dirsav->cd();
1659 }
1660 }
1661}
1662
1663////////////////////////////////////////////////////////////////////////////////
1664/// Set the default buffer size when creating new TKeys.
1665///
1666/// See also TDirectoryFile::GetBufferSize
1671}
1672
1673////////////////////////////////////////////////////////////////////////////////
1674/// Find the action to be executed in the dictionary of the parent class
1675/// and store the corresponding exec number into fBits.
1676///
1677/// This function searches a data member in the class of parent with an
1678/// offset corresponding to this.
1679/// If a comment "TEXEC:" is found in the comment field of the data member,
1680/// the function stores the exec identifier of the exec statement
1681/// following this keyword.
1684{
1685 Int_t offset = (char*)ref - (char*)parent;
1686 TClass *cl = parent->IsA();
1687 cl->BuildRealData(parent);
1689 TIter next(info->GetElements());
1691 while((element = (TStreamerElement*)next())) {
1692 if (element->GetOffset() != offset) continue;
1693 Int_t execid = element->GetExecID();
1694 if (execid > 0) ref->SetBit(execid << 8);
1695 return;
1696 }
1697}
1698
1699////////////////////////////////////////////////////////////////////////////////
1700/// Set the new value of fWritable recursively
1703{
1705
1707
1708 // recursively set all sub-directories
1709 if (fList) {
1710 TObject *idcur;
1711 TIter next(fList);
1712 while ((idcur = next())) {
1713 if (idcur->InheritsFrom(TDirectoryFile::Class())) {
1715 dir->SetWritable(writable);
1716 }
1717 }
1718 }
1719}
1720
1721
1722////////////////////////////////////////////////////////////////////////////////
1723/// Return the size in bytes of the directory header
1726{
1727 Int_t nbytes = 22;
1728
1729 nbytes += fDatimeC.Sizeof();
1730 nbytes += fDatimeM.Sizeof();
1731 nbytes += fUUID.Sizeof();
1732 //assume that the file may be above 2 Gbytes if file version is > 4
1733 if (fFile && fFile->GetVersion() >= 40000) nbytes += 12;
1734 return nbytes;
1735}
1736
1737
1738////////////////////////////////////////////////////////////////////////////////
1739/// Stream a class object
1742{
1744 if (b.IsReading()) {
1745 BuildDirectoryFile((TFile*)b.GetParent(), nullptr);
1746 if (fFile && fFile->IsWritable()) fWritable = kTRUE;
1747
1748 if (fFile && !fFile->IsBinary()) {
1749 Version_t R__v = b.ReadVersion(0, 0);
1750
1752
1753 b.ClassBegin(dirclass, R__v);
1754
1755 TString sbuf;
1756
1757 b.ClassMember("CreateTime","TString");
1758 sbuf.Streamer(b);
1759 TDatime timeC(sbuf.Data());
1760 fDatimeC = timeC;
1761
1762 b.ClassMember("ModifyTime","TString");
1763 sbuf.Streamer(b);
1764 TDatime timeM(sbuf.Data());
1765 fDatimeM = timeM;
1766
1767 b.ClassMember("UUID","TString");
1768 sbuf.Streamer(b);
1769 TUUID id(sbuf.Data());
1770 fUUID = id;
1771
1772 b.ClassEnd(dirclass);
1773
1774 fSeekKeys = 0; // read keys later in the TKeySQL class
1775 } else {
1776 b >> version;
1779 b >> fNbytesKeys;
1780 b >> fNbytesName;
1781 if (version > 1000) {
1783 b >> fSeekDir;
1784 b >> fSeekParent;
1785 b >> fSeekKeys;
1786 } else {
1788 b >> sdir; fSeekDir = (Long64_t)sdir;
1791 }
1792 v = version%1000;
1793 if (v == 2) {
1795 } else if (v > 2) {
1796 fUUID.Streamer(b);
1797 }
1798 }
1799 fList->UseRWLock();
1801 gROOT->GetUUIDs()->AddUUID(fUUID,this);
1802 if (fSeekKeys) ReadKeys();
1803 } else {
1804 if (fFile && !fFile->IsBinary()) {
1805 b.WriteVersion(TDirectoryFile::Class());
1806
1807 TString sbuf;
1808
1809 b.ClassBegin(TDirectoryFile::Class());
1810
1811 b.ClassMember("CreateTime","TString");
1813 sbuf.Streamer(b);
1814
1815 b.ClassMember("ModifyTime","TString");
1816 fDatimeM.Set();
1818 sbuf.Streamer(b);
1819
1820 b.ClassMember("UUID","TString");
1821 sbuf = fUUID.AsString();
1822 sbuf.Streamer(b);
1823
1824 b.ClassEnd(TDirectoryFile::Class());
1825 } else {
1827 if (fFile && fFile->GetEND() > TFile::kStartBigFile) version += 1000;
1828 b << version;
1831 b << fNbytesKeys;
1832 b << fNbytesName;
1833 if (version > 1000) {
1834 b << fSeekDir;
1835 b << fSeekParent;
1836 b << fSeekKeys;
1837 } else {
1838 b << (Int_t)fSeekDir;
1839 b << (Int_t)fSeekParent;
1840 b << (Int_t)fSeekKeys;
1841 }
1842 fUUID.Streamer(b);
1843 if (version <=1000) for (Int_t i=0;i<3;i++) b << Int_t(0);
1844 }
1845 }
1846}
1847
1848////////////////////////////////////////////////////////////////////////////////
1849/// Write all objects in memory to disk.
1850///
1851/// Loop on all objects in memory (including subdirectories).
1852/// A new key is created in the keys linked list for each object.
1853/// For allowed options see TObject::Write().
1854/// The directory header info is rewritten on the directory header record.
1856Int_t TDirectoryFile::Write(const char *, Int_t opt, Int_t bufsize)
1857{
1858 if (!IsWritable()) return 0;
1860
1861 // Loop on all objects (including subdirs)
1862 TIter next(fList);
1863 TObject *obj;
1864 Int_t nbytes = 0;
1865 while ((obj=next())) {
1866 nbytes += obj->Write(0,opt,bufsize);
1867 }
1868 if (R__likely(!(opt & kOnlyPrepStep)))
1869 SaveSelf(kTRUE); // force save itself
1870
1871 return nbytes;
1872}
1873
1874////////////////////////////////////////////////////////////////////////////////
1875/// One can not save a const TDirectory object.
1877Int_t TDirectoryFile::Write(const char *n, Int_t opt, Int_t bufsize) const
1878{
1879 Error("Write const","A const TDirectory object should not be saved. We try to proceed anyway.");
1880 return const_cast<TDirectoryFile*>(this)->Write(n, opt, bufsize);
1881}
1882
1883////////////////////////////////////////////////////////////////////////////////
1884/// Write object obj to this directory.
1885///
1886/// The data structure corresponding to this object is serialized.
1887/// The corresponding buffer is written to this directory
1888/// with an associated key with name "name".
1889///
1890/// Writing an object to a file involves the following steps:
1891/// - Creation of a support TKey object in the directory. The TKey object
1892/// creates a TBuffer object.
1893/// - The TBuffer object is filled via the class::Streamer function.
1894/// - If the file is compressed (default) a second buffer is created to hold
1895/// the compressed buffer.
1896/// - Reservation of the corresponding space in the file by looking in the
1897/// TFree list of free blocks of the file.
1898/// - The buffer is written to the file.
1899///
1900/// By default, the buffersize will be taken from the average buffer size
1901/// of all objects written to the current file so far.
1902/// Use TDirectoryFile::SetBufferSize to force a given buffer size.
1903///
1904/// If a name is specified, it will be the name of the key.
1905/// If name is not given, the name of the key will be the name as returned
1906/// by obj->GetName().
1907///
1908/// The option can be a combination of:
1909/// - "SingleKey"
1910/// - "Overwrite"
1911/// - "WriteDelete"
1912/// Using the "Overwrite" option a previous key with the same name is
1913/// overwritten. The previous key is deleted before writing the new object.
1914/// Using the "WriteDelete" option a previous key with the same name is
1915/// deleted only after the new object has been written. This option
1916/// is safer than kOverwrite but it is slower.
1917/// The "SingleKey" option is only used by TCollection::Write() to write
1918/// a container with a single key instead of each object in the container
1919/// with its own key.
1920/// An object is read from this directory via TDirectoryFile::Get.
1921/// The function returns the total number of bytes written to the directory.
1922/// It returns 0 if the object cannot be written.
1923///
1924/// WARNING: avoid special characters like '^','$','.' in the name as they
1925/// are used by the regular expression parser (see TRegexp).
1928{
1930
1931 if (fFile==0) {
1932 const char *objname = "no name specified";
1933 if (name) objname = name;
1934 else if (obj) objname = obj->GetName();
1935 Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.",GetName(),objname);
1936 return 0;
1937 }
1938
1939 if (!fFile->IsWritable()) {
1941 // Do not print the error if the file already had a SysError.
1942 Error("WriteTObject","Directory %s is not writable", fFile->GetName());
1943 }
1944 return 0;
1945 }
1946
1947 if (!obj) return 0;
1948
1949 TString opt = option;
1950 opt.ToLower();
1951
1952 TKey *key=0, *oldkey=0;
1954 if (bufsize > 0) bsize = bufsize;
1955
1956 const char *oname;
1957 if (name && *name)
1958 oname = name;
1959 else
1960 oname = obj->GetName();
1961
1962 // Remove trailing blanks in object name
1963 Int_t nch = strlen(oname);
1964 char *newName = nullptr;
1965 if (nch && oname[nch-1] == ' ') {
1966 Warning("WriteTObject", "The key name '%s' will be stored in file without the trailing blanks.", obj->GetName());
1967 // See https://github.com/root-project/root/issues/17003
1968 newName = new char[nch+1];
1970 for (Int_t i=0;i<nch;i++) {
1971 if (newName[nch-i-1] != ' ') break;
1972 newName[nch-i-1] = 0;
1973 }
1974 oname = newName;
1975 }
1976
1977 if (opt.Contains("overwrite")) {
1978 //One must use GetKey. FindObject would return the lowest cycle of the key!
1979 //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
1980 key = GetKey(oname);
1981 if (key) {
1982 key->Delete();
1983 delete key;
1984 }
1985 }
1986 if (opt.Contains("writedelete")) {
1987 oldkey = GetKey(oname);
1988 }
1989 key = fFile->CreateKey(this, obj, oname, bsize);
1990 if (newName) delete [] newName;
1991
1992 if (!key->GetSeekKey()) {
1993 fKeys->Remove(key);
1994 delete key;
1996 return 0;
1997 }
1998 fFile->SumBuffer(key->GetObjlen());
1999 Int_t nbytes = key->WriteFile(0);
2002 return 0;
2003 }
2004 if (oldkey) {
2005 oldkey->Delete();
2006 delete oldkey;
2007 }
2009
2010 return nbytes;
2011}
2012
2013////////////////////////////////////////////////////////////////////////////////
2014/// Write object from pointer of class classname in this directory.
2015///
2016/// obj may not derive from TObject. See TDirectoryFile::WriteTObject for comments
2017///
2018/// ## Very important note
2019/// The value passed as 'obj' needs to be from a pointer to the type described by classname.
2020/// For example:
2021/// ~~~{.cpp}
2022/// TopClass *top;
2023/// BottomClass *bottom;
2024/// top = bottom;
2025/// ~~~
2026/// you can do:
2027/// ~~~{.cpp}
2028/// directory->WriteObjectAny(top,"top","name of object");
2029/// directory->WriteObjectAny(bottom,"bottom","name of object");
2030/// ~~~
2031/// <b>BUT YOU CAN NOT DO</b> the following since it will fail with multiple inheritance:
2032/// ~~~{.cpp}
2033/// directory->WriteObjectAny(top,"bottom","name of object");
2034/// ~~~
2035/// We <b>STRONGLY</b> recommend to use
2036/// ~~~{.cpp}
2037/// TopClass *top = ....;
2038/// directory->WriteObject(top,"name of object")
2039/// ~~~
2040/// See also remarks in TDirectoryFile::WriteTObject
2042Int_t TDirectoryFile::WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option, Int_t bufsize)
2043{
2044 TClass *cl = TClass::GetClass(classname);
2045 if (!cl) {
2046 TObject *info_obj = *(TObject**)obj;
2048 if (!info) {
2049 Error("WriteObjectAny","Unknown class: %s",classname);
2050 return 0;
2051 } else {
2052 cl = info->GetClass();
2053 }
2054 }
2055 return WriteObjectAny(obj,cl,name,option,bufsize);
2056}
2057
2058////////////////////////////////////////////////////////////////////////////////
2059/// Write object of class with dictionary cl in this directory.
2060///
2061/// obj may not derive from TObject
2062/// To get the TClass* cl pointer, one can use
2063///
2064/// TClass *cl = TClass::GetClass("classname");
2065///
2066/// An alternative is to call the function WriteObjectAny above.
2067/// see TDirectoryFile::WriteTObject for comments
2069Int_t TDirectoryFile::WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option, Int_t bufsize)
2070{
2072
2073 if (!fFile) return 0;
2074
2075 if (!cl) {
2076 Error("WriteObject","Unknown type for %s, it can not be written.",name);
2077 return 0;
2078 }
2079
2080 if (!fFile->IsWritable()) {
2082 // Do not print the error if the file already had a SysError.
2083 Error("WriteObject","File %s is not writable", fFile->GetName());
2084 }
2085 return 0;
2086 }
2087
2088 if (!obj) return 0;
2089
2090 const char *className = cl->GetName();
2091 const char *oname;
2092 if (name && *name)
2093 oname = name;
2094 else
2095 oname = className;
2096
2097 if (cl && cl->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(cl->GetCollectionProxy())) {
2098 Error("WriteObjectAny",
2099 "The class requested (%s) for the key name \"%s\""
2100 " is an instance of an stl collection and does not have a compiled CollectionProxy."
2101 " Please generate the dictionary for this collection (%s). No data will be written.",
2102 className, oname, className);
2103 return 0;
2104 }
2105
2106 TKey *key, *oldkey = nullptr;
2108 if (bufsize > 0) bsize = bufsize;
2109
2110 TString opt = option;
2111 opt.ToLower();
2112
2113 // Remove trailing blanks in object name
2114 Int_t nch = strlen(oname);
2115 char *newName = nullptr;
2116 if (nch && oname[nch-1] == ' ') {
2117 newName = new char[nch+1];
2119 for (Int_t i=0;i<nch;i++) {
2120 if (newName[nch-i-1] != ' ') break;
2121 newName[nch-i-1] = 0;
2122 }
2123 oname = newName;
2124 }
2125
2126 if (opt.Contains("overwrite")) {
2127 //One must use GetKey. FindObject would return the lowest cycle of the key!
2128 //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
2129 key = GetKey(oname);
2130 if (key) {
2131 key->Delete();
2132 delete key;
2133 }
2134 }
2135 if (opt.Contains("writedelete")) {
2136 oldkey = GetKey(oname);
2137 }
2138 key = fFile->CreateKey(this, obj, cl, oname, bsize);
2139 if (newName) delete [] newName;
2140
2141 if (!key->GetSeekKey()) {
2142 fKeys->Remove(key);
2143 delete key;
2144 return 0;
2145 }
2146 fFile->SumBuffer(key->GetObjlen());
2147 Int_t nbytes = key->WriteFile(0);
2148 if (fFile->TestBit(TFile::kWriteError)) return 0;
2149
2150 if (oldkey) {
2151 oldkey->Delete();
2152 delete oldkey;
2153 }
2154
2155 return nbytes;
2156}
2157
2158////////////////////////////////////////////////////////////////////////////////
2159/// Overwrite the Directory header record.
2162{
2163 TFile* f = GetFile();
2164 if (!f) return;
2165
2166 if (!f->IsBinary()) {
2167 fDatimeM.Set();
2168 f->DirWriteHeader(this);
2169 return;
2170 }
2171
2172 Int_t nbytes = TDirectoryFile::Sizeof(); //Warning ! TFile has a Sizeof()
2173 char *header = new char[nbytes];
2174 char *buffer = header;
2175 fDatimeM.Set();
2177 Long64_t pointer = fSeekDir + fNbytesName; // do not overwrite the name/title part
2178 fModified = kFALSE;
2179 f->Seek(pointer);
2180 f->WriteBuffer(header, nbytes);
2181 if (f->MustFlush()) f->Flush();
2182 delete [] header;
2183}
2184
2185////////////////////////////////////////////////////////////////////////////////
2186/// Write Keys linked list on the file.
2187///
2188/// The linked list of keys (fKeys) is written as a single data record
2191{
2192 TFile* f = GetFile();
2193 if (!f) return;
2194
2195 if (!f->IsBinary()) {
2196 f->DirWriteKeys(this);
2197 return;
2198 }
2199
2200//*-* Delete the old keys structure if it exists
2201 if (fSeekKeys != 0) {
2202 f->MakeFree(fSeekKeys, fSeekKeys + fNbytesKeys -1);
2203 }
2204//*-* Write new keys record
2205 TIter next(fKeys);
2206 TKey *key;
2207 Int_t nkeys = fKeys->GetSize();
2208 Int_t nbytes = sizeof nkeys; //*-* Compute size of all keys
2209 if (f->GetEND() > TFile::kStartBigFile) nbytes += 8;
2210 while ((key = (TKey*)next())) {
2211 nbytes += key->Sizeof();
2212 }
2213 TKey *headerkey = new TKey(fName,fTitle,IsA(),nbytes,this);
2214 if (headerkey->GetSeekKey() == 0) {
2215 delete headerkey;
2216 return;
2217 }
2218 char *buffer = headerkey->GetBuffer();
2219 next.Reset();
2220 tobuf(buffer, nkeys);
2221 while ((key = (TKey*)next())) {
2222 key->FillBuffer(buffer);
2223 }
2224
2225 fSeekKeys = headerkey->GetSeekKey();
2226 fNbytesKeys = headerkey->GetNbytes();
2227 headerkey->WriteFile();
2228 delete headerkey;
2229}
void frombuf(char *&buf, Bool_t *x)
Definition Bytes.h:278
void tobuf(char *&buf, Bool_t x)
Definition Bytes.h:55
#define R__likely(expr)
Definition RConfig.hxx:595
#define SafeDelete(p)
Definition RConfig.hxx:533
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
short Version_t
Class version identifier (short)
Definition RtypesCore.h:79
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:60
short Short_t
Signed Short integer 2 bytes (short)
Definition RtypesCore.h:53
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
#define BIT(n)
Definition Rtypes.h:91
const Bool_t kIterBackward
Definition TCollection.h:43
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
const Int_t kMaxLen
const UInt_t kIsBigFile
const Int_t kMaxLen
#define gDirectory
Definition TDirectory.h:385
#define gFile
Definition TFile.h:430
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t mask
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void reg
char name[80]
Definition TGX11.cxx:110
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:627
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:411
R__EXTERN TSystem * gSystem
Definition TSystem.h:572
#define R__LOCKGUARD(mutex)
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition TBufferFile.h:47
void MapObject(const TObject *obj, UInt_t offset=1) override
Add object to the fMap container.
void ResetMap() override
Delete existing fMap and reset map counter.
static Int_t ExportToFile(const char *filename, const TObject *obj, const char *option=nullptr)
Convert object into JSON and store in text file Returns size of the produce file Used in TObject::Sav...
Buffer base class used for serializing objects.
Definition TBuffer.h:43
@ kWrite
Definition TBuffer.h:73
void SetBufferOffset(Int_t offset=0)
Definition TBuffer.h:93
void SetReadMode()
Set buffer in read mode.
Definition TBuffer.cxx:301
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2036
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:4626
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2902
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:2973
static TClass * Class()
virtual bool UseRWLock(Bool_t enable=true)
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.
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
virtual void Streamer(TBuffer &)
Stream a object of type TDatime.
Definition TDatime.cxx:415
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).
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.
Bool_t cd() override
Change current directory to "this" directory.
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.
static TClass * Class()
Bool_t IsWritable() const override
void Streamer(TBuffer &) override
Stream a class object.
void Delete(const char *namecycle="") override
Delete Objects or/and keys in the current 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.
~TDirectoryFile() override
Destructor.
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/...".
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.
static constexpr Version_t Class_Version()
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.
TClass * IsA() const override
void ReadAll(Option_t *option="") override
Read objects from a ROOT file directory into memory.
TList * fKeys
Pointer to keys list in memory.
void ls(Option_t *option="") const override
List Directory contents.
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
Describe directory structure in memory.
Definition TDirectory.h:45
static TClass * Class()
void Delete(const char *namecycle="") override
Delete Objects or/and keys in a directory.
virtual TList * GetList() const
Definition TDirectory.h:223
virtual void ReadAll(Option_t *="")
Definition TDirectory.h:248
static size_t DecodeNameCycle(const char *namecycle, char *name, Short_t &cycle, const size_t namesize=0)
Decode a namecycle "aap;2" contained in the null-terminated string buffer into name "aap" and cycle 2...
void CleanTargets()
Clean the pointers to this object (gDirectory, TContext, etc.).
virtual void Append(TObject *obj, Bool_t replace=kFALSE)
Append object to this directory.
TObject * FindObject(const char *name) const override
Find object by name in the list of memory objects.
virtual Bool_t cd()
Change current directory to "this" directory.
TUUID fUUID
Definition TDirectory.h:143
TDirectory * GetMotherDir() const
Definition TDirectory.h:226
TObject * fMother
Definition TDirectory.h:141
void GetObject(const char *namecycle, T *&ptr)
Get an object with proper type checking.
Definition TDirectory.h:213
TList * fList
Definition TDirectory.h:142
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.
Streamer around an arbitrary STL like container, which implements basic container functionality.
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:131
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:2304
Int_t GetVersion() const
Definition TFile.h:324
Bool_t IsBinary() const
Definition TFile.h:338
virtual Int_t DirReadKeys(TDirectory *)
Definition TFile.h:243
TList * GetListOfFree() const
Definition TFile.h:316
Int_t GetBestBuffer() const
Return the best buffer size of objects on this file.
Definition TFile.cxx:1172
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:1055
virtual Long64_t GetSize() const
Returns the current file size.
Definition TFile.cxx:1336
virtual Long64_t GetEND() const
Definition TFile.h:310
void SumBuffer(Int_t bufsize)
Increment statistics for buffer sizes of objects in this file.
Definition TFile.cxx:2447
static TFile *& CurrentFile()
Return the current ROOT file if any.
Definition TFile.cxx:1075
virtual const TUrl * GetEndpointUrl() const
Definition TFile.h:314
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:3764
@ kReproducible
Definition TFile.h:272
@ kWriteError
Definition TFile.h:269
@ kStartBigFile
Definition TFile.h:279
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition TFile.cxx:1800
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition THashList.h:34
void Reset()
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
void Delete(Option_t *option="") override
Delete an object from the file.
Definition TKey.cxx:540
virtual Long64_t GetSeekKey() const
Definition TKey.h:89
Int_t Sizeof() const override
Return the size in bytes of the key header structure.
Definition TKey.cxx:1345
Int_t GetKeylen() const
Definition TKey.h:84
Int_t GetObjlen() const
Definition TKey.h:87
Short_t GetKeep() const
Returns the "KEEP" status.
Definition TKey.cxx:595
virtual const char * GetClassName() const
Definition TKey.h:75
void ReadKeyBuffer(char *&buffer)
Decode input buffer.
Definition TKey.cxx:1234
virtual Long64_t GetSeekPdir() const
Definition TKey.h:90
void SetMotherDir(TDirectory *dir)
Definition TKey.h:112
virtual void ls(Bool_t current) const
List Key contents.
Definition TKey.cxx:696
Short_t GetCycle() const
Return cycle number associated to this key.
Definition TKey.cxx:579
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition TKey.cxx:760
virtual Int_t WriteFile(Int_t cycle=1, TFile *f=nullptr)
Write the encoded object supported by this key.
Definition TKey.cxx:1459
virtual char * GetBuffer() const
Definition TKey.h:78
void FillBuffer(char *&buffer) override
Encode key header into output buffer.
Definition TKey.cxx:603
A doubly linked list.
Definition TList.h:38
TObject * Before(const TObject *obj) const override
Returns the object before object obj.
Definition TList.cxx:501
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:708
void Add(TObject *obj) override
Definition TList.h:81
TObject * Remove(TObject *obj) override
Remove object from the list.
Definition TList.cxx:952
TObject * First() const override
Return the first object in the list. Returns 0 when list is empty.
Definition TList.cxx:789
void AddBefore(const TObject *before, TObject *obj) override
Insert object before object before in the list.
Definition TList.cxx:193
virtual TObjLink * FirstLink() const
Definition TList.h:107
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:600
This class implements a shared memory region mapped to a file.
Definition TMapFile.h:26
static TClass * Class()
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
TString fTitle
Definition TNamed.h:33
TString fName
Definition TNamed.h:32
Mother of all ROOT objects.
Definition TObject.h:41
virtual Bool_t IsFolder() const
Returns kTRUE in case object contains browsable objects (like containers or lists of other objects).
Definition TObject.cxx:573
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:457
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:202
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1074
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition TObject.cxx:421
static TClass * Class()
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition TObject.cxx:981
@ kOnlyPrepStep
Used to request that the class specific implementation of TObject::Write just prepare the objects to ...
Definition TObject.h:112
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:881
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:543
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1088
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1116
virtual TClass * IsA() const
Definition TObject.h:246
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition TObject.cxx:592
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:68
@ kIsReferenced
if object is referenced by a TRef or TRefArray
Definition TObject.h:71
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1062
static Int_t IncreaseDirLevel()
Increase the indentation level for ls().
Definition TROOT.cxx:2893
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition TROOT.cxx:2901
static Int_t DecreaseDirLevel()
Decrease the indentation level for ls().
Definition TROOT.cxx:2750
Regular expression class.
Definition TRegexp.h:31
Describe one element (data member) to be Streamed.
Describes a persistent version of a class.
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:425
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
@ kBoth
Definition TString.h:284
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition TString.h:632
Bool_t IsNull() const
Definition TString.h:422
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:641
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:660
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:1307
This class defines a UUID (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDent...
Definition TUUID.h:42
virtual void Streamer(TBuffer &)
const char * AsString() const
Return UUID as string. Copy string immediately since it will be reused.
Definition TUUID.cxx:570
Int_t Sizeof() const
Definition TUUID.h:85
void FillBuffer(char *&buffer)
Stream UUID into output buffer.
Definition TUUID.cxx:274
void StreamerV1(TBuffer &b)
Stream UUID from input buffer.
Definition TUUID.cxx:308
Abstract Interface class describing Streamer information for one class.
const Int_t n
Definition legend1.C:16
void(* DirAutoAdd_t)(void *, TDirectory *)
Definition Rtypes.h:120
TCanvas * slash()
Definition slash.C:1