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