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