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