Logo ROOT   6.10/09
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  const char *nmcy = (namecycle) ? namecycle : "";
613  DecodeNameCycle(nmcy, name, cycle, kMaxLen);
614 
615  Int_t deleteall = 0;
616  Int_t deletetree = 0;
617  if(strcmp(name,"*") == 0) deleteall = 1;
618  if(strcmp(name,"*T") == 0){ deleteall = 1; deletetree = 1;}
619  if(strcmp(name,"T*") == 0){ deleteall = 1; deletetree = 1;}
620  if(namecycle==0 || !namecycle[0]){ deleteall = 1; deletetree = 1;}
621  TRegexp re(name,kTRUE);
622  TString s;
623  Int_t deleteOK = 0;
624 
625 //*-*---------------------Case of Object in memory---------------------
626 // ========================
627  if (cycle >= 9999 ) {
628  TNamed *idcur;
629  TIter next(fList);
630  while ((idcur = (TNamed *) next())) {
631  deleteOK = 0;
632  s = idcur->GetName();
633  if (deleteall || s.Index(re) != kNPOS) {
634  deleteOK = 1;
635  if (idcur->IsA() == TDirectoryFile::Class()) {
636  deleteOK = 2;
637  if (!deletetree && deleteall) deleteOK = 0;
638  }
639  }
640  if (deleteOK != 0) {
641  fList->Remove(idcur);
642  if (deleteOK==2) {
643  // read subdirectories to correctly delete them
644  if (deletetree)
645  ((TDirectory*) idcur)->ReadAll("dirs");
646  idcur->Delete(deletetree ? "T*;*" : "*");
647  delete idcur;
648  } else
649  idcur->Delete(name);
650  }
651  }
652 // if (deleteOK == 2) {
653 // Info("Delete","Dir:%lx %s", fList->FindObject(name), name);
654 // delete fList->FindObject(name); //deleting a TDirectory
655 // }
656  }
657 //*-*---------------------Case of Key---------------------
658 // ===========
659  if (cycle != 9999 ) {
660  if (IsWritable()) {
661  TKey *key;
662  TIter nextkey(GetListOfKeys());
663  while ((key = (TKey *) nextkey())) {
664  deleteOK = 0;
665  s = key->GetName();
666  if (deleteall || s.Index(re) != kNPOS) {
667  if (cycle == key->GetCycle()) deleteOK = 1;
668  if (cycle > 9999) deleteOK = 1;
669  //if (!strcmp(key->GetClassName(),"TDirectory")) {
670  if (strstr(key->GetClassName(),"TDirectory")) {
671  deleteOK = 2;
672  if (!deletetree && deleteall) deleteOK = 0;
673  if (cycle == key->GetCycle()) deleteOK = 2;
674  }
675  }
676  if (deleteOK) {
677  if (deleteOK==2) {
678  // read directory with subdirectories to correctly delete and free key structure
679  TDirectory* dir = GetDirectory(key->GetName(), kTRUE, "Delete");
680  if (dir!=0) {
681  dir->Delete("T*;*");
682  fList->Remove(dir);
683  delete dir;
684  }
685  }
686 
687  key->Delete();
688  fKeys->Remove(key);
689  fModified = kTRUE;
690  delete key;
691  }
692  }
693  TFile* f = GetFile();
694  if (fModified && (f!=0)) {
695  WriteKeys(); //*-* Write new keys structure
696  WriteDirHeader(); //*-* Write new directory header
697  f->WriteFree(); //*-* Write new free segments list
698  f->WriteHeader(); //*-* Write new file header
699  }
700  }
701  }
702 }
703 
704 ////////////////////////////////////////////////////////////////////////////////
705 /// Encode directory header into output buffer
706 
707 void TDirectoryFile::FillBuffer(char *&buffer)
708 {
709  Version_t version = TDirectoryFile::Class_Version();
713  {
714  // One of the address is larger than 2GB we need to use longer onfile
715  // integer, thus we increase the verison number.
716  // Note that fSeekDir and fSeekKey are not necessarily correlated, if
717  // some object are 'removed' from the file and the holes are reused.
718  version += 1000;
719  }
720  tobuf(buffer, version);
721  fDatimeC.FillBuffer(buffer);
722  fDatimeM.FillBuffer(buffer);
723  tobuf(buffer, fNbytesKeys);
724  tobuf(buffer, fNbytesName);
725  if (version > 1000) {
726  tobuf(buffer, fSeekDir);
727  tobuf(buffer, fSeekParent);
728  tobuf(buffer, fSeekKeys);
729  } else {
730  tobuf(buffer, (Int_t)fSeekDir);
731  tobuf(buffer, (Int_t)fSeekParent);
732  tobuf(buffer, (Int_t)fSeekKeys);
733  }
734  fUUID.FillBuffer(buffer);
735  if (fFile && fFile->GetVersion() < 40000) return;
736  if (version <=1000) for (Int_t i=0;i<3;i++) tobuf(buffer,Int_t(0));
737 }
738 
739 ////////////////////////////////////////////////////////////////////////////////
740 /// Find key with name keyname in the current directory
741 
742 TKey *TDirectoryFile::FindKey(const char *keyname) const
743 {
744  Short_t cycle;
745  char name[kMaxLen];
746 
747  DecodeNameCycle(keyname, name, cycle, kMaxLen);
748  return GetKey(name,cycle);
749 }
750 
751 ////////////////////////////////////////////////////////////////////////////////
752 /// Find key with name keyname in the current directory or
753 /// its subdirectories.
754 ///
755 /// NOTE: that If a key is found, the directory containing the key becomes
756 /// the current directory
757 
758 TKey *TDirectoryFile::FindKeyAny(const char *keyname) const
759 {
760  TDirectory *dirsav = gDirectory;
761  Short_t cycle;
762  char name[kMaxLen];
763 
764  DecodeNameCycle(keyname, name, cycle, kMaxLen);
765 
766  TIter next(GetListOfKeys());
767  TKey *key;
768  while ((key = (TKey *) next())) {
769  if (!strcmp(name, key->GetName()))
770  if ((cycle == 9999) || (cycle >= key->GetCycle())) {
771  ((TDirectory*)this)->cd(); // may be we should not make cd ???
772  return key;
773  }
774  }
775  //try with subdirectories
776  next.Reset();
777  while ((key = (TKey *) next())) {
778  //if (!strcmp(key->GetClassName(),"TDirectory")) {
779  if (strstr(key->GetClassName(),"TDirectory")) {
780  TDirectory* subdir =
781  ((TDirectory*)this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
782  TKey *k = (subdir!=0) ? subdir->FindKeyAny(keyname) : 0;
783  if (k) return k;
784  }
785  }
786  if (dirsav) dirsav->cd();
787  return 0;
788 }
789 
790 ////////////////////////////////////////////////////////////////////////////////
791 /// Find object by name in the list of memory objects of the current
792 /// directory or its sub-directories.
793 ///
794 /// After this call the current directory is not changed.
795 /// To automatically set the current directory where the object is found,
796 /// use FindKeyAny(aname)->ReadObj().
797 
798 TObject *TDirectoryFile::FindObjectAny(const char *aname) const
799 {
800  //object may be already in the list of objects in memory
801  TObject *obj = TDirectory::FindObjectAny(aname);
802  if (obj) return obj;
803 
804  TDirectory *dirsav = gDirectory;
805  Short_t cycle;
806  char name[kMaxLen];
807 
808  DecodeNameCycle(aname, name, cycle, kMaxLen);
809 
810  TIter next(GetListOfKeys());
811  TKey *key;
812  //may be a key in the current directory
813  while ((key = (TKey *) next())) {
814  if (!strcmp(name, key->GetName())) {
815  if (cycle == 9999) return key->ReadObj();
816  if (cycle >= key->GetCycle()) return key->ReadObj();
817  }
818  }
819  //try with subdirectories
820  next.Reset();
821  while ((key = (TKey *) next())) {
822  //if (!strcmp(key->GetClassName(),"TDirectory")) {
823  if (strstr(key->GetClassName(),"TDirectory")) {
824  TDirectory* subdir =
825  ((TDirectory*)this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
826  TKey *k = subdir==0 ? 0 : subdir->FindKeyAny(aname);
827  if (k) { if (dirsav) dirsav->cd(); return k->ReadObj();}
828  }
829  }
830  if (dirsav) dirsav->cd();
831  return 0;
832 }
833 
834 ////////////////////////////////////////////////////////////////////////////////
835 /// Return pointer to object identified by namecycle.
836 ///
837 /// Properties:
838 /// - namecycle has the format name;cycle
839 /// - name = * is illegal, cycle = * is illegal
840 /// - cycle = "" or cycle = 9999 ==> apply to a memory object
841 ///
842 /// Examples:
843 /// | Pattern | Explanation |
844 /// |---------|-------------|
845 /// | foo | get object named foo in memory if object is not in memory, try with highest cycle from file |
846 /// | foo;1 | get cycle 1 of foo on file |
847 ///
848 /// The retrieved object should in principle derive from TObject.
849 /// If not, the function TDirectoryFile::GetObject should be called.
850 /// However, this function will still work for a non-TObject, provided that
851 /// the calling application cast the return type to the correct type (which
852 /// is the actual type of the object).
853 ///
854 /// ### The GetObjectMethod
855 /// The method GetObject offers better protection and avoids the need
856 /// for any cast:
857 /// ~~~{.cpp}
858 /// MyClass *obj;
859 /// directory->GetObject("some object",obj);
860 /// if (obj) { ... the object exist and inherits from MyClass ... }
861 /// ~~~
862 ///
863 /// ### Very important note about inheritance
864 /// In case the class of this object derives from TObject but not
865 /// as a first inheritance, one must use dynamic_cast<>().
866 ///
867 /// #### Example 1 - Normal case:
868 ///
869 /// class MyClass : public TObject, public AnotherClass
870 ///
871 /// then on return, one can adopt a C style cast:
872 ///
873 /// auto objPtr = (MyClass*)directory->Get("some object of MyClass");
874 ///
875 /// #### Example 2 - Special case:
876 ///
877 /// class MyClass : public AnotherClass, public TObject
878 ///
879 /// then on return, one must do:
880 ///
881 /// auto objPtr = dynamic_cast<MyClass*>(directory->Get("some object of MyClass"));
882 ///
883 /// Of course, dynamic_cast<> can also be used in the example 1.
884 ///
885 
886 TObject *TDirectoryFile::Get(const char *namecycle)
887 {
888  Short_t cycle;
889  char name[kMaxLen];
890 
891  DecodeNameCycle(namecycle, name, cycle, kMaxLen);
892  Int_t nch = strlen(name);
893  for (Int_t i = nch-1; i > 0; i--) {
894  if (name[i] == '/') {
895  name[i] = 0;
896  TDirectory* dirToSearch=GetDirectory(name);
897  const char *subnamecycle = namecycle + i + 1;
898  name[i] = '/';
899  return dirToSearch?dirToSearch->Get(subnamecycle):0;
900  }
901  }
902  const char *namobj = name;
903 
904 //*-*---------------------Case of Object in memory---------------------
905 // ========================
906  TObject *idcur = fList ? fList->FindObject(namobj) : nullptr;
907  if (idcur) {
908  if (idcur==this && strlen(namobj)!=0) {
909  // The object has the same name has the directory and
910  // that's what we picked-up! We just need to ignore
911  // it ...
912  idcur = 0;
913  } else if (cycle == 9999) {
914  return idcur;
915  } else {
916  if (idcur->InheritsFrom(TCollection::Class()))
917  idcur->Delete(); // delete also list elements
918  delete idcur;
919  idcur = 0;
920  }
921  }
922 
923 //*-*---------------------Case of Key---------------------
924 // ===========
925  TKey *key;
926  TIter nextkey(GetListOfKeys());
927  while ((key = (TKey *) nextkey())) {
928  if (strcmp(namobj,key->GetName()) == 0) {
929  if ((cycle == 9999) || (cycle == key->GetCycle())) {
930  TDirectory::TContext ctxt(this);
931  idcur = key->ReadObj();
932  break;
933  }
934  }
935  }
936 
937  return idcur;
938 }
939 
940 ////////////////////////////////////////////////////////////////////////////////
941 /// Return pointer to object identified by namecycle.
942 ///
943 /// The returned object may or may not derive from TObject.
944 ///
945 /// - namecycle has the format name;cycle
946 /// - name = * is illegal, cycle = * is illegal
947 /// - cycle = "" or cycle = 9999 ==> apply to a memory object
948 ///
949 /// ## Very important note
950 /// The calling application must cast the returned object to
951 /// the final type, e.g.
952 ///
953 /// auto objPtr = (MyClass*)directory->GetObject("some object of MyClass");
954 
955 void *TDirectoryFile::GetObjectUnchecked(const char *namecycle)
956 {
957  return GetObjectChecked(namecycle,(TClass*)0);
958 }
959 
960 ////////////////////////////////////////////////////////////////////////////////
961 /// See documentation of TDirectoryFile::GetObjectCheck(const char *namecycle, const TClass *cl)
962 
963 void *TDirectoryFile::GetObjectChecked(const char *namecycle, const char* classname)
964 {
965  return GetObjectChecked(namecycle,TClass::GetClass(classname));
966 }
967 
968 
969 ////////////////////////////////////////////////////////////////////////////////
970 /// Return pointer to object identified by namecycle if and only if the actual
971 /// object is a type suitable to be stored as a pointer to a "expectedClass"
972 /// If expectedClass is null, no check is performed.
973 ///
974 /// - namecycle has the format name;cycle
975 /// - name = * is illegal, cycle = * is illegal
976 /// - cycle = "" or cycle = 9999 ==> apply to a memory object
977 ///
978 /// ### Very important note
979 /// The calling application must cast the returned pointer to
980 /// the type described by the 2 arguments (i.e. cl):
981 ///
982 /// auto objPtr = (MyClass*)directory->GetObjectChecked("some object of MyClass","MyClass"));
983 ///
984 /// Note: We recommend using the method TDirectoryFile::GetObject:
985 /// ~~~{.cpp}
986 /// MyClass *obj = nullptr;
987 /// directory->GetObject("some object inheriting from MyClass",obj);
988 /// if (obj) { ... we found what we are looking for ... }
989 /// ~~~
990 
991 void *TDirectoryFile::GetObjectChecked(const char *namecycle, const TClass* expectedClass)
992 {
993  Short_t cycle;
994  char name[kMaxLen];
995 
996  DecodeNameCycle(namecycle, name, cycle, kMaxLen);
997  Int_t nch = strlen(name);
998  for (Int_t i = nch-1; i > 0; i--) {
999  if (name[i] == '/') {
1000  name[i] = 0;
1001  TDirectory* dirToSearch=GetDirectory(name);
1002  const char *subnamecycle = namecycle + i + 1;
1003  name[i] = '/';
1004  if (dirToSearch) {
1005  return dirToSearch->GetObjectChecked(subnamecycle, expectedClass);
1006  } else {
1007  return 0;
1008  }
1009  }
1010  }
1011  const char *namobj = name;
1012 
1013 //*-*---------------------Case of Object in memory---------------------
1014 // ========================
1015  if (expectedClass==0 || expectedClass->IsTObject()) {
1016  TObject *objcur = fList ? fList->FindObject(namobj) : 0;
1017  if (objcur) {
1018  if (objcur==this && strlen(namobj)!=0) {
1019  // The object has the same name has the directory and
1020  // that's what we picked-up! We just need to ignore
1021  // it ...
1022  objcur = 0;
1023  } else if (cycle == 9999) {
1024  // Check type
1025  if (expectedClass && objcur->IsA()->GetBaseClassOffset(expectedClass) == -1) return 0;
1026  else return objcur;
1027  } else {
1028  if (objcur->InheritsFrom(TCollection::Class()))
1029  objcur->Delete(); // delete also list elements
1030  delete objcur;
1031  objcur = 0;
1032  }
1033  }
1034  }
1035 
1036 //*-*---------------------Case of Key---------------------
1037 // ===========
1038  void *idcur = 0;
1039  TKey *key;
1040  TIter nextkey(GetListOfKeys());
1041  while ((key = (TKey *) nextkey())) {
1042  if (strcmp(namobj,key->GetName()) == 0) {
1043  if ((cycle == 9999) || (cycle == key->GetCycle())) {
1044  TDirectory::TContext ctxt(this);
1045  idcur = key->ReadObjectAny(expectedClass);
1046  break;
1047  }
1048  }
1049  }
1050 
1051  return idcur;
1052 }
1053 
1054 ////////////////////////////////////////////////////////////////////////////////
1055 /// Return the buffer size to create new TKeys.
1056 ///
1057 /// If the stored fBufferSize is null, the value returned is the average
1058 /// buffer size of objects in the file so far.
1059 
1062  if (fBufferSize <= 0) return fFile->GetBestBuffer();
1063  else return fBufferSize;
1064 }
1065 
1066 
1067 ////////////////////////////////////////////////////////////////////////////////
1068 /// Return pointer to key with name,cycle
1069 ///
1070 /// if cycle = 9999 returns highest cycle
1071 
1072 TKey *TDirectoryFile::GetKey(const char *name, Short_t cycle) const
1074  // TIter::TIter() already checks for null pointers
1075  TIter next( ((THashList *)(GetListOfKeys()))->GetListForObject(name) );
1076 
1077  TKey *key;
1078  while (( key = (TKey *)next() )) {
1079  if (!strcmp(name, key->GetName())) {
1080  if ((cycle == 9999) || (cycle >= key->GetCycle()))
1081  return key;
1082  }
1083  }
1084 
1085  return 0;
1086 }
1087 
1088 ////////////////////////////////////////////////////////////////////////////////
1089 /// List Directory contents
1090 ///
1091 /// Indentation is used to identify the directory tree
1092 /// Subdirectories are listed first, then objects in memory, then objects on the file
1093 ///
1094 /// The option can has the following format: <b>[-d |-m][<regexp>]</b>
1095 /// Options:
1096 /// - -d: only list objects in the file
1097 /// - -m: only list objects in memory
1098 /// The <regexp> will be used to match the name of the objects.
1099 /// By default memory and disk objects are listed.
1100 
1101 void TDirectoryFile::ls(Option_t *option) const
1104  std::cout <<ClassName()<<"*\t\t"<<GetName()<<"\t"<<GetTitle()<<std::endl;
1106 
1107  TString opta = option;
1108  TString opt = opta.Strip(TString::kBoth);
1109  Bool_t memobj = kTRUE;
1110  Bool_t diskobj = kTRUE;
1111  TString reg = "*";
1112  if (opt.BeginsWith("-m")) {
1113  diskobj = kFALSE;
1114  if (opt.Length() > 2)
1115  reg = opt(2,opt.Length());
1116  } else if (opt.BeginsWith("-d")) {
1117  memobj = kFALSE;
1118  if (opt.Length() > 2)
1119  reg = opt(2,opt.Length());
1120  } else if (!opt.IsNull())
1121  reg = opt;
1122 
1123  TRegexp re(reg, kTRUE);
1124 
1125  if (memobj) {
1126  TObject *obj;
1127  TIter nextobj(fList);
1128  while ((obj = (TObject *) nextobj())) {
1129  TString s = obj->GetName();
1130  if (s.Index(re) == kNPOS) continue;
1131  obj->ls(option); //*-* Loop on all the objects in memory
1132  }
1133  }
1134 
1135  if (diskobj) {
1136  TKey *key;
1137  TIter next(GetListOfKeys());
1138  while ((key = (TKey *) next())) {
1139  TString s = key->GetName();
1140  if (s.Index(re) == kNPOS) continue;
1141  key->ls(); //*-* Loop on all the keys
1142  }
1143  }
1145 }
1146 
1147 ////////////////////////////////////////////////////////////////////////////////
1148 /// Interface to TFile::Open
1149 
1150 TFile *TDirectoryFile::OpenFile(const char *name, Option_t *option,const char *ftitle, Int_t compress, Int_t netopt)
1152  return TFile::Open(name,option,ftitle,compress,netopt);
1153 
1154 }
1155 
1156 
1157 ////////////////////////////////////////////////////////////////////////////////
1158 /// Create a sub-directory "a" or a hierarchy of sub-directories "a/b/c/...".
1159 ///
1160 /// Returns 0 in case of error or if a sub-directory (hierarchy) with the requested
1161 /// name already exists.
1162 /// Returns a pointer to the created sub-directory or to the top sub-directory of
1163 /// the hierarchy (in the above example, the returned TDirectory * always points
1164 /// to "a").
1165 
1166 TDirectory *TDirectoryFile::mkdir(const char *name, const char *title)
1168  if (!name || !title || !name[0]) return 0;
1169  if (!title[0]) title = name;
1170  if (GetKey(name)) {
1171  Error("mkdir","An object with name %s exists already",name);
1172  return 0;
1173  }
1174  TDirectoryFile *newdir = 0;
1175  if (const char *slash = strchr(name,'/')) {
1176  Long_t size = Long_t(slash-name);
1177  char *workname = new char[size+1];
1178  strncpy(workname, name, size);
1179  workname[size] = 0;
1180  TDirectoryFile *tmpdir;
1181  GetObject(workname,tmpdir);
1182  if (!tmpdir) {
1183  tmpdir = (TDirectoryFile*)mkdir(workname,title);
1184  if (!tmpdir) return 0;
1185  }
1186  if (!newdir) newdir = tmpdir;
1187  tmpdir->mkdir(slash+1);
1188  delete[] workname;
1189  return newdir;
1190  }
1191 
1192  TDirectory::TContext ctxt(this);
1193 
1194  newdir = new TDirectoryFile(name, title, "", this);
1195 
1196  return newdir;
1197 }
1198 
1199 ////////////////////////////////////////////////////////////////////////////////
1200 /// Purge lowest key cycles in a directory.
1201 ///
1202 /// By default, only the highest cycle of a key is kept. Keys for which
1203 /// the "KEEP" flag has been set are not removed. See TKey::Keep().
1204 
1207  if (!IsWritable()) return;
1208 
1209  TDirectory::TContext ctxt(this);
1210 
1211  TKey *key;
1213 
1214  while ((key = (TKey*)prev())) { // reverse loop on keys
1215  TKey *keyprev = (TKey*)GetListOfKeys()->Before(key);
1216  if (!keyprev) break;
1217  if (key->GetKeep() == 0) {
1218  if (strcmp(key->GetName(), keyprev->GetName()) == 0) {
1219  key->Delete(); // Remove from the file.
1220  delete key; // Remove from memory.
1221  }
1222  }
1223  }
1224  TFile* f = GetFile();
1225  if (fModified && (f!=0)) {
1226  WriteKeys(); // Write new keys structure
1227  WriteDirHeader(); // Write new directory header
1228  f->WriteFree(); // Write new free segments list
1229  f->WriteHeader(); // Write new file header
1230  }
1231 }
1232 
1233 ////////////////////////////////////////////////////////////////////////////////
1234 /// Read objects from a ROOT file directory into memory.
1235 ///
1236 /// If an object is already in memory, the memory copy is deleted
1237 /// and the object is again read from the file.
1238 /// If opt=="dirs", only subdirectories will be read
1239 /// If opt=="dirs*" complete directory tree will be read
1240 
1243  TDirectory::TContext ctxt(this);
1244 
1245  TKey *key;
1246  TIter next(GetListOfKeys());
1247 
1248  Bool_t readdirs = ((opt!=0) && ((strcmp(opt,"dirs")==0) || (strcmp(opt,"dirs*")==0)));
1249 
1250  if (readdirs)
1251  while ((key = (TKey *) next())) {
1252 
1253  //if (strcmp(key->GetClassName(),"TDirectory")!=0) continue;
1254  if (strstr(key->GetClassName(),"TDirectory")==0) continue;
1255 
1256  TDirectory *dir = GetDirectory(key->GetName(), kTRUE, "ReadAll");
1257 
1258  if ((dir!=0) && (strcmp(opt,"dirs*")==0)) dir->ReadAll("dirs*");
1259  }
1260  else
1261  while ((key = (TKey *) next())) {
1262  TObject *thing = GetList()->FindObject(key->GetName());
1263  if (thing) { delete thing; }
1264  key->ReadObj();
1265  }
1266 }
1267 
1268 ////////////////////////////////////////////////////////////////////////////////
1269 /// Read the linked list of keys.
1270 ///
1271 /// Every directory has a linked list (fKeys). This linked list has been
1272 /// written on the file via WriteKeys as a single data record.
1273 ///
1274 /// It is interesting to call this function in the following situation.
1275 /// Assume another process1 is connecting this directory in Update mode
1276 /// - Process1 is adding/updating objects in this directory
1277 /// - You want to see the latest status from process1.
1278 /// Example Process1:
1279 /// ~~~{.cpp}
1280 /// obj1.Write();
1281 /// obj2.Write();
1282 /// gDirectory->SaveSelf();
1283 /// ~~~
1284 ///
1285 /// Example Process2:
1286 /// ~~~{.cpp}
1287 /// gDirectory->ReadKeys();
1288 /// obj1->Draw();
1289 /// ~~~
1290 /// This is an efficient way (without opening/closing files) to view
1291 /// the latest updates of a file being modified by another process
1292 /// as it is typically the case in a data acquisition system.
1293 
1296  if (fFile==0) return 0;
1297 
1298  if (!fFile->IsBinary())
1299  return fFile->DirReadKeys(this);
1300 
1301  TDirectory::TContext ctxt(this);
1302 
1303  char *buffer;
1304  if (forceRead) {
1305  fKeys->Delete();
1306  //In case directory was updated by another process, read new
1307  //position for the keys
1309  char *header = new char[nbytes];
1310  buffer = header;
1311  fFile->Seek(fSeekDir);
1312  if ( fFile->ReadBuffer(buffer,nbytes) ) {
1313  // ReadBuffer return kTRUE in case of failure.
1314  delete [] header;
1315  return 0;
1316  }
1317  buffer += fNbytesName;
1318  Version_t versiondir;
1319  frombuf(buffer,&versiondir);
1320  fDatimeC.ReadBuffer(buffer);
1321  fDatimeM.ReadBuffer(buffer);
1322  frombuf(buffer, &fNbytesKeys);
1323  frombuf(buffer, &fNbytesName);
1324  if (versiondir > 1000) {
1325  frombuf(buffer, &fSeekDir);
1326  frombuf(buffer, &fSeekParent);
1327  frombuf(buffer, &fSeekKeys);
1328  } else {
1329  Int_t sdir,sparent,skeys;
1330  frombuf(buffer, &sdir); fSeekDir = (Long64_t)sdir;
1331  frombuf(buffer, &sparent); fSeekParent = (Long64_t)sparent;
1332  frombuf(buffer, &skeys); fSeekKeys = (Long64_t)skeys;
1333  }
1334  delete [] header;
1335  }
1336 
1337  Int_t nkeys = 0;
1338  Long64_t fsize = fFile->GetSize();
1339  if ( fSeekKeys > 0) {
1340  TKey *headerkey = new TKey(fSeekKeys, fNbytesKeys, this);
1341  headerkey->ReadFile();
1342  buffer = headerkey->GetBuffer();
1343  headerkey->ReadKeyBuffer(buffer);
1344 
1345  TKey *key;
1346  frombuf(buffer, &nkeys);
1347  for (Int_t i = 0; i < nkeys; i++) {
1348  key = new TKey(this);
1349  key->ReadKeyBuffer(buffer);
1350  if (key->GetSeekKey() < 64 || key->GetSeekKey() > fsize) {
1351  Error("ReadKeys","reading illegal key, exiting after %d keys",i);
1352  fKeys->Remove(key);
1353  nkeys = i;
1354  break;
1355  }
1356  if (key->GetSeekPdir() < 64 || key->GetSeekPdir() > fsize) {
1357  Error("ReadKeys","reading illegal key, exiting after %d keys",i);
1358  fKeys->Remove(key);
1359  nkeys = i;
1360  break;
1361  }
1362  fKeys->Add(key);
1363  }
1364  delete headerkey;
1365  }
1366 
1367  return nkeys;
1368 }
1369 
1370 
1371 ////////////////////////////////////////////////////////////////////////////////
1372 /// Read object with keyname from the current directory
1373 ///
1374 /// Read contents of object with specified name from the current directory.
1375 /// First the key with keyname is searched in the current directory,
1376 /// next the key buffer is deserialized into the object.
1377 /// The object must have been created before via the default constructor.
1378 /// See TObject::Write().
1379 
1380 Int_t TDirectoryFile::ReadTObject(TObject *obj, const char *keyname)
1382  if (!fFile) { Error("Read","No file open"); return 0; }
1383  TKey *key = 0;
1384  TIter nextkey(GetListOfKeys());
1385  while ((key = (TKey *) nextkey())) {
1386  if (strcmp(keyname,key->GetName()) == 0) {
1387  return key->Read(obj);
1388  }
1389  }
1390  Error("Read","Key not found");
1391  return 0;
1392 }
1393 
1394 ////////////////////////////////////////////////////////////////////////////////
1395 /// Reset the TDirectory after its content has been merged into another
1396 /// Directory.
1397 ///
1398 /// This returns the TDirectoryFile object back to its state
1399 /// before any data has been written to the file.
1400 /// The object in the in-memory list are assumed to also have been reset.
1401 
1404  // There is nothing to reset in the base class (TDirectory) since
1405  // we do want to key the list of in-memory object as is.
1406  fModified = kFALSE;
1407  // Does not change: fWritable
1408  fDatimeC.Set();
1409  fDatimeM.Set();
1410  fNbytesKeys = 0; // updated when the keys are written
1411  fNbytesName = 0; // updated by Init
1412  // Does not change (user customization): fBufferSize;
1413  fSeekDir = 0; // updated by Init
1414  fSeekParent = 0; // updated by Init
1415  fSeekKeys = 0; // updated by Init
1416  // Does not change: fFile
1417  TKey *key = (TKey*)fKeys->FindObject(fName);
1418  TClass *cl = IsA();
1419  if (key) {
1420  cl = TClass::GetClass(key->GetClassName());
1421  }
1422  // NOTE: We should check that the content is really mergeable and in
1423  // the in-mmeory list, before deleting the keys.
1424  if (fKeys) {
1425  fKeys->Delete("slow");
1426  }
1427 
1428  Init(cl);
1429 
1430  // Do the same with the sub-directories.
1431  TIter next(GetList());
1432  TObject *idcur;
1433  while ((idcur = next())) {
1434  if (idcur->IsA() == TDirectoryFile::Class()) {
1435  ((TDirectoryFile*)idcur)->ResetAfterMerge(info);
1436  }
1437  }
1438 
1439 }
1440 
1441 ////////////////////////////////////////////////////////////////////////////////
1442 /// Removes subdirectory from the directory
1443 ///
1444 /// When diredctory is deleted, all keys in all subdirectories will be
1445 /// read first and deleted from file (if exists)
1446 /// Equivalent call is Delete("name;*");
1447 
1448 void TDirectoryFile::rmdir(const char *name)
1450  if ((name==0) || (*name==0)) return;
1451 
1452  TString mask(name);
1453  mask+=";*";
1454  Delete(mask);
1455 }
1456 
1457 ////////////////////////////////////////////////////////////////////////////////
1458 /// Save recursively all directory keys and headers
1459 
1460 void TDirectoryFile::Save()
1462  TDirectory::TContext ctxt(this);
1463 
1464  SaveSelf();
1465 
1466  // recursively save all sub-directories
1467  if (fList) {
1468  TObject *idcur;
1469  TIter next(fList);
1470  while ((idcur = next())) {
1471  if (idcur->InheritsFrom(TDirectoryFile::Class())) {
1472  TDirectoryFile *dir = (TDirectoryFile*)idcur;
1473  dir->Save();
1474  }
1475  }
1476  }
1477 }
1478 
1479 ////////////////////////////////////////////////////////////////////////////////
1480 /// Save object in filename.
1481 ///
1482 /// If filename is 0 or "", a file with "objectname.root" is created.
1483 /// The name of the key is the object name.
1484 /// If the operation is successful, it returns the number of bytes written to the file
1485 /// otherwise it returns 0.
1486 /// By default a message is printed. Use option "q" to not print the message.
1487 /// If filename contains ".json" extension, JSON representation of the object
1488 /// will be created and saved in the text file. Such file can be used in
1489 /// JavaScript ROOT (https://root.cern.ch/js/) to display object in web browser
1490 /// When creating JSON file, option string may contain compression level from 0 to 3 (default 0)
1491 
1492 Int_t TDirectoryFile::SaveObjectAs(const TObject *obj, const char *filename, Option_t *option) const
1494  if (!obj) return 0;
1495  TDirectory *dirsav = gDirectory;
1496  TString fname = filename;
1497  if (!filename || !filename[0]) {
1498  fname.Form("%s.root",obj->GetName());
1499  }
1500  Int_t nbytes = 0;
1501  if (fname.Index(".json") > 0) {
1502  nbytes = TBufferJSON::ExportToFile(fname, obj, option);
1503  } else {
1504  TFile *local = TFile::Open(fname.Data(),"recreate");
1505  if (!local) return 0;
1506  nbytes = obj->Write();
1507  delete local;
1508  if (dirsav) dirsav->cd();
1509  }
1510  TString opt = option;
1511  opt.ToLower();
1512  if (!opt.Contains("q")) {
1513  if (!gSystem->AccessPathName(fname.Data())) obj->Info("SaveAs", "ROOT file %s has been created", fname.Data());
1514  }
1515  return nbytes;
1516 }
1517 
1518 ////////////////////////////////////////////////////////////////////////////////
1519 /// Save Directory keys and header
1520 ///
1521 /// If the directory has been modified (fModified set), write the keys
1522 /// and the directory header. This function assumes the cd is correctly set.
1523 ///
1524 /// It is recommended to use this function in the following situation:
1525 /// Assume a process1 using a directory in Update mode
1526 /// - New objects or modified objects have been written to the directory.
1527 /// - You do not want to close the file.
1528 /// - You want your changes be visible from another process2 already connected
1529 /// to this directory in read mode.
1530 /// - Call this function.
1531 /// - In process2, use TDirectoryFile::ReadKeys to refresh the directory.
1532 
1533 void TDirectoryFile::SaveSelf(Bool_t force)
1535  if (IsWritable() && (fModified || force) && fFile) {
1536  Bool_t dowrite = kTRUE;
1537  if (fFile->GetListOfFree())
1538  dowrite = fFile->GetListOfFree()->First() != 0;
1539  if (dowrite) {
1540  TDirectory *dirsav = gDirectory;
1541  if (dirsav != this) cd();
1542  WriteKeys(); //*-*- Write keys record
1543  WriteDirHeader(); //*-*- Update directory record
1544  if (dirsav && dirsav != this) dirsav->cd();
1545  }
1546  }
1547 }
1548 
1549 ////////////////////////////////////////////////////////////////////////////////
1550 /// Set the default buffer size when creating new TKeys.
1551 ///
1552 /// See also TDirectoryFile::GetBufferSize
1553 
1556  fBufferSize = bufsize;
1557 }
1558 
1559 ////////////////////////////////////////////////////////////////////////////////
1560 /// Find the action to be executed in the dictionary of the parent class
1561 /// and store the corresponding exec number into fBits.
1562 ///
1563 /// This function searches a data member in the class of parent with an
1564 /// offset corresponding to this.
1565 /// If a comment "TEXEC:" is found in the comment field of the data member,
1566 /// the function stores the exec identifier of the exec statement
1567 /// following this keyword.
1568 
1569 void TDirectoryFile::SetTRefAction(TObject *ref, TObject *parent)
1571  Int_t offset = (char*)ref - (char*)parent;
1572  TClass *cl = parent->IsA();
1573  cl->BuildRealData(parent);
1575  TIter next(info->GetElements());
1576  TStreamerElement *element;
1577  while((element = (TStreamerElement*)next())) {
1578  if (element->GetOffset() != offset) continue;
1579  Int_t execid = element->GetExecID();
1580  if (execid > 0) ref->SetBit(execid << 8);
1581  return;
1582  }
1583 }
1584 
1585 ////////////////////////////////////////////////////////////////////////////////
1586 /// Set the new value of fWritable recursively
1587 
1588 void TDirectoryFile::SetWritable(Bool_t writable)
1590  TDirectory::TContext ctxt(this);
1591 
1592  fWritable = writable;
1593 
1594  // recursively set all sub-directories
1595  if (fList) {
1596  TObject *idcur;
1597  TIter next(fList);
1598  while ((idcur = next())) {
1599  if (idcur->InheritsFrom(TDirectoryFile::Class())) {
1600  TDirectoryFile *dir = (TDirectoryFile*)idcur;
1601  dir->SetWritable(writable);
1602  }
1603  }
1604  }
1605 }
1606 
1607 
1608 ////////////////////////////////////////////////////////////////////////////////
1609 /// Return the size in bytes of the directory header
1610 
1613  Int_t nbytes = 22;
1614 
1615  nbytes += fDatimeC.Sizeof();
1616  nbytes += fDatimeM.Sizeof();
1617  nbytes += fUUID.Sizeof();
1618  //assume that the file may be above 2 Gbytes if file version is > 4
1619  if (fFile && fFile->GetVersion() >= 40000) nbytes += 12;
1620  return nbytes;
1621 }
1622 
1623 
1624 ////////////////////////////////////////////////////////////////////////////////
1625 /// Stream a class object
1626 
1627 void TDirectoryFile::Streamer(TBuffer &b)
1628 {
1629  Version_t v,version;
1630  if (b.IsReading()) {
1631  Build((TFile*)b.GetParent(), 0);
1632  if (fFile && fFile->IsWritable()) fWritable = kTRUE;
1633 
1634  if (fFile && !fFile->IsBinary()) {
1635  Version_t R__v = b.ReadVersion(0, 0);
1636 
1637  TClass* dirclass = (R__v < 5) ? TDirectory::Class() : TDirectoryFile::Class();
1638 
1639  b.ClassBegin(dirclass, R__v);
1640 
1641  TString sbuf;
1642 
1643  b.ClassMember("CreateTime","TString");
1644  sbuf.Streamer(b);
1645  TDatime timeC(sbuf.Data());
1646  fDatimeC = timeC;
1647 
1648  b.ClassMember("ModifyTime","TString");
1649  sbuf.Streamer(b);
1650  TDatime timeM(sbuf.Data());
1651  fDatimeM = timeM;
1652 
1653  b.ClassMember("UUID","TString");
1654  sbuf.Streamer(b);
1655  TUUID id(sbuf.Data());
1656  fUUID = id;
1657 
1658  b.ClassEnd(dirclass);
1659 
1660  fSeekKeys = 0; // read keys later in the TKeySQL class
1661  } else {
1662  b >> version;
1663  fDatimeC.Streamer(b);
1664  fDatimeM.Streamer(b);
1665  b >> fNbytesKeys;
1666  b >> fNbytesName;
1667  if (version > 1000) {
1668  SetBit(kIsBigFile);
1669  b >> fSeekDir;
1670  b >> fSeekParent;
1671  b >> fSeekKeys;
1672  } else {
1673  Int_t sdir,sparent,skeys;
1674  b >> sdir; fSeekDir = (Long64_t)sdir;
1675  b >> sparent; fSeekParent = (Long64_t)sparent;
1676  b >> skeys; fSeekKeys = (Long64_t)skeys;
1677  }
1678  v = version%1000;
1679  if (v == 2) {
1680  fUUID.StreamerV1(b);
1681  } else if (v > 2) {
1682  fUUID.Streamer(b);
1683  }
1684  }
1686  gROOT->GetUUIDs()->AddUUID(fUUID,this);
1687  if (fSeekKeys) ReadKeys();
1688  } else {
1689  if (fFile && !fFile->IsBinary()) {
1691 
1692  TString sbuf;
1693 
1695 
1696  b.ClassMember("CreateTime","TString");
1697  sbuf = fDatimeC.AsSQLString();
1698  sbuf.Streamer(b);
1699 
1700  b.ClassMember("ModifyTime","TString");
1701  fDatimeM.Set();
1702  sbuf = fDatimeM.AsSQLString();
1703  sbuf.Streamer(b);
1704 
1705  b.ClassMember("UUID","TString");
1706  sbuf = fUUID.AsString();
1707  sbuf.Streamer(b);
1708 
1710  } else {
1711  version = TDirectoryFile::Class_Version();
1712  if (fFile && fFile->GetEND() > TFile::kStartBigFile) version += 1000;
1713  b << version;
1714  fDatimeC.Streamer(b);
1715  fDatimeM.Streamer(b);
1716  b << fNbytesKeys;
1717  b << fNbytesName;
1718  if (version > 1000) {
1719  b << fSeekDir;
1720  b << fSeekParent;
1721  b << fSeekKeys;
1722  } else {
1723  b << (Int_t)fSeekDir;
1724  b << (Int_t)fSeekParent;
1725  b << (Int_t)fSeekKeys;
1726  }
1727  fUUID.Streamer(b);
1728  if (version <=1000) for (Int_t i=0;i<3;i++) b << Int_t(0);
1729  }
1730  }
1731 }
1732 
1733 ////////////////////////////////////////////////////////////////////////////////
1734 /// Write all objects in memory to disk.
1735 ///
1736 /// Loop on all objects in memory (including subdirectories).
1737 /// A new key is created in the keys linked list for each object.
1738 /// For allowed options see TObject::Write().
1739 /// The directory header info is rewritten on the directory header record.
1740 
1741 Int_t TDirectoryFile::Write(const char *, Int_t opt, Int_t bufsize)
1743  if (!IsWritable()) return 0;
1744  TDirectory::TContext ctxt(this);
1745 
1746  // Loop on all objects (including subdirs)
1747  TIter next(fList);
1748  TObject *obj;
1749  Int_t nbytes = 0;
1750  while ((obj=next())) {
1751  nbytes += obj->Write(0,opt,bufsize);
1752  }
1753  SaveSelf(kTRUE); // force save itself
1754 
1755  return nbytes;
1756 }
1757 
1758 ////////////////////////////////////////////////////////////////////////////////
1759 /// One can not save a const TDirectory object.
1760 
1761 Int_t TDirectoryFile::Write(const char *n, Int_t opt, Int_t bufsize) const
1763  Error("Write const","A const TDirectory object should not be saved. We try to proceed anyway.");
1764  return const_cast<TDirectoryFile*>(this)->Write(n, opt, bufsize);
1765 }
1766 
1767 ////////////////////////////////////////////////////////////////////////////////
1768 /// Write object obj to this directory.
1769 ///
1770 /// The data structure corresponding to this object is serialized.
1771 /// The corresponding buffer is written to this directory
1772 /// with an associated key with name "name".
1773 ///
1774 /// Writing an object to a file involves the following steps:
1775 /// - Creation of a support TKey object in the directory. The TKey object
1776 /// creates a TBuffer object.
1777 /// - The TBuffer object is filled via the class::Streamer function.
1778 /// - If the file is compressed (default) a second buffer is created to hold
1779 /// the compressed buffer.
1780 /// - Reservation of the corresponding space in the file by looking in the
1781 /// TFree list of free blocks of the file.
1782 /// - The buffer is written to the file.
1783 ///
1784 /// By default, the buffersize will be taken from the average buffer size
1785 /// of all objects written to the current file so far.
1786 /// Use TDirectoryFile::SetBufferSize to force a given buffer size.
1787 ///
1788 /// If a name is specified, it will be the name of the key.
1789 /// If name is not given, the name of the key will be the name as returned
1790 /// by obj->GetName().
1791 ///
1792 /// The option can be a combination of:
1793 /// - "SingleKey"
1794 /// - "Overwrite"
1795 /// - "WriteDelete"
1796 /// Using the "Overwrite" option a previous key with the same name is
1797 /// overwritten. The previous key is deleted before writing the new object.
1798 /// Using the "WriteDelete" option a previous key with the same name is
1799 /// deleted only after the new object has been written. This option
1800 /// is safer than kOverwrite but it is slower.
1801 /// The "SingleKey" option is only used by TCollection::Write() to write
1802 /// a container with a single key instead of each object in the container
1803 /// with its own key.
1804 /// An object is read from this directory via TDirectoryFile::Get.
1805 /// The function returns the total number of bytes written to the directory.
1806 /// It returns 0 if the object cannot be written.
1807 ///
1808 /// WARNING: avoid special characters like '^','$','.' in the name as they
1809 /// are used by the regular expression parser (see TRegexp).
1810 
1811 Int_t TDirectoryFile::WriteTObject(const TObject *obj, const char *name, Option_t *option, Int_t bufsize)
1813  TDirectory::TContext ctxt(this);
1814 
1815  if (fFile==0) {
1816  const char *objname = "no name specified";
1817  if (name) objname = name;
1818  else if (obj) objname = obj->GetName();
1819  Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.",GetName(),objname);
1820  return 0;
1821  }
1822 
1823  if (!fFile->IsWritable()) {
1824  if (!fFile->TestBit(TFile::kWriteError)) {
1825  // Do not print the error if the file already had a SysError.
1826  Error("WriteTObject","Directory %s is not writable", fFile->GetName());
1827  }
1828  return 0;
1829  }
1830 
1831  if (!obj) return 0;
1832 
1833  TString opt = option;
1834  opt.ToLower();
1835 
1836  TKey *key=0, *oldkey=0;
1838  if (bufsize > 0) bsize = bufsize;
1839 
1840  const char *oname;
1841  if (name && *name)
1842  oname = name;
1843  else
1844  oname = obj->GetName();
1845 
1846  // Remove trailing blanks in object name
1847  Int_t nch = strlen(oname);
1848  char *newName = 0;
1849  if (nch && oname[nch-1] == ' ') {
1850  newName = new char[nch+1];
1851  strlcpy(newName,oname,nch+1);
1852  for (Int_t i=0;i<nch;i++) {
1853  if (newName[nch-i-1] != ' ') break;
1854  newName[nch-i-1] = 0;
1855  }
1856  oname = newName;
1857  }
1858 
1859  if (opt.Contains("overwrite")) {
1860  //One must use GetKey. FindObject would return the lowest cycle of the key!
1861  //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
1862  key = GetKey(oname);
1863  if (key) {
1864  key->Delete();
1865  delete key;
1866  }
1867  }
1868  if (opt.Contains("writedelete")) {
1869  oldkey = GetKey(oname);
1870  }
1871  key = fFile->CreateKey(this, obj, oname, bsize);
1872  if (newName) delete [] newName;
1873 
1874  if (!key->GetSeekKey()) {
1875  fKeys->Remove(key);
1876  delete key;
1877  if (bufsize) fFile->SetBufferSize(bufsize);
1878  return 0;
1879  }
1880  fFile->SumBuffer(key->GetObjlen());
1881  Int_t nbytes = key->WriteFile(0);
1883  if (bufsize) fFile->SetBufferSize(bufsize);
1884  return 0;
1885  }
1886  if (oldkey) {
1887  oldkey->Delete();
1888  delete oldkey;
1889  }
1890  if (bufsize) fFile->SetBufferSize(bufsize);
1891 
1892  return nbytes;
1893 }
1894 
1895 ////////////////////////////////////////////////////////////////////////////////
1896 /// Write object from pointer of class classname in this directory.
1897 ///
1898 /// obj may not derive from TObject. See TDirectoryFile::WriteTObject for comments
1899 ///
1900 /// ## Very important note
1901 /// The value passed as 'obj' needs to be from a pointer to the type described by classname.
1902 /// For example:
1903 /// ~~~{.cpp}
1904 /// TopClass *top;
1905 /// BottomClass *bottom;
1906 /// top = bottom;
1907 /// ~~~
1908 /// you can do:
1909 /// ~~~{.cpp}
1910 /// directory->WriteObjectAny(top,"top","name of object");
1911 /// directory->WriteObjectAny(bottom,"bottom","name of object");
1912 /// ~~~
1913 /// <b>BUT YOU CAN NOT DO</b> the following since it will fail with multiple inheritance:
1914 /// ~~~{.cpp}
1915 /// directory->WriteObjectAny(top,"bottom","name of object");
1916 /// ~~~
1917 /// We <b>STRONGLY</b> recommend to use
1918 /// ~~~{.cpp}
1919 /// TopClass *top = ....;
1920 /// directory->WriteObject(top,"name of object")
1921 /// ~~~
1922 /// See also remarks in TDirectoryFile::WriteTObject
1923 
1924 Int_t TDirectoryFile::WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option, Int_t bufsize)
1926  TClass *cl = TClass::GetClass(classname);
1927  if (cl == 0) {
1928  TObject *info_obj = *(TObject**)obj;
1929  TVirtualStreamerInfo *info = dynamic_cast<TVirtualStreamerInfo*>(info_obj);
1930  if (info == 0) {
1931  Error("WriteObjectAny","Unknown class: %s",classname);
1932  return 0;
1933  } else {
1934  cl = info->GetClass();
1935  }
1936  }
1937  return WriteObjectAny(obj,cl,name,option,bufsize);
1938 }
1939 
1940 ////////////////////////////////////////////////////////////////////////////////
1941 /// Write object of class with dictionary cl in this directory.
1942 ///
1943 /// obj may not derive from TObject
1944 /// To get the TClass* cl pointer, one can use
1945 ///
1946 /// TClass *cl = TClass::GetClass("classname");
1947 ///
1948 /// An alternative is to call the function WriteObjectAny above.
1949 /// see TDirectoryFile::WriteTObject for comments
1950 
1951 Int_t TDirectoryFile::WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option, Int_t bufsize)
1953  TDirectory::TContext ctxt(this);
1954 
1955  if (fFile==0) return 0;
1956 
1957  if (!cl) {
1958  Error("WriteObject","Unknown type for %s, it can not be written.",name);
1959  return 0;
1960  }
1961 
1962  if (!fFile->IsWritable()) {
1963  if (!fFile->TestBit(TFile::kWriteError)) {
1964  // Do not print the error if the file already had a SysError.
1965  Error("WriteObject","File %s is not writable", fFile->GetName());
1966  }
1967  return 0;
1968  }
1969 
1970  if (!obj) return 0;
1971 
1972  const char *className = cl->GetName();
1973  const char *oname;
1974  if (name && *name)
1975  oname = name;
1976  else
1977  oname = className;
1978 
1979  if (cl && cl->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(cl->GetCollectionProxy())) {
1980  Error("WriteObjectAny",
1981  "The class requested (%s) for the key name \"%s\""
1982  " is an instance of an stl collection and does not have a compiled CollectionProxy."
1983  " Please generate the dictionary for this collection (%s). No data will be written.",
1984  className, oname, className);
1985  return 0;
1986  }
1987 
1988  TKey *key, *oldkey=0;
1990  if (bufsize > 0) bsize = bufsize;
1991 
1992  TString opt = option;
1993  opt.ToLower();
1994 
1995  // Remove trailing blanks in object name
1996  Int_t nch = strlen(oname);
1997  char *newName = 0;
1998  if (nch && oname[nch-1] == ' ') {
1999  newName = new char[nch+1];
2000  strlcpy(newName,oname,nch+1);
2001  for (Int_t i=0;i<nch;i++) {
2002  if (newName[nch-i-1] != ' ') break;
2003  newName[nch-i-1] = 0;
2004  }
2005  oname = newName;
2006  }
2007 
2008  if (opt.Contains("overwrite")) {
2009  //One must use GetKey. FindObject would return the lowest cycle of the key!
2010  //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
2011  key = GetKey(oname);
2012  if (key) {
2013  key->Delete();
2014  delete key;
2015  }
2016  }
2017  if (opt.Contains("writedelete")) {
2018  oldkey = GetKey(oname);
2019  }
2020  key = fFile->CreateKey(this, obj, cl, oname, bsize);
2021  if (newName) delete [] newName;
2022 
2023  if (!key->GetSeekKey()) {
2024  fKeys->Remove(key);
2025  delete key;
2026  return 0;
2027  }
2028  fFile->SumBuffer(key->GetObjlen());
2029  Int_t nbytes = key->WriteFile(0);
2030  if (fFile->TestBit(TFile::kWriteError)) return 0;
2031 
2032  if (oldkey) {
2033  oldkey->Delete();
2034  delete oldkey;
2035  }
2036 
2037  return nbytes;
2038 }
2039 
2040 ////////////////////////////////////////////////////////////////////////////////
2041 /// Overwrite the Directory header record.
2042 
2045  TFile* f = GetFile();
2046  if (f==0) return;
2047 
2048  if (!f->IsBinary()) {
2049  fDatimeM.Set();
2050  f->DirWriteHeader(this);
2051  return;
2052  }
2053 
2054  Int_t nbytes = TDirectoryFile::Sizeof(); //Warning ! TFile has a Sizeof()
2055  char * header = new char[nbytes];
2056  char * buffer = header;
2057  fDatimeM.Set();
2059  Long64_t pointer = fSeekDir + fNbytesName; // do not overwrite the name/title part
2060  fModified = kFALSE;
2061  f->Seek(pointer);
2062  f->WriteBuffer(header, nbytes);
2063  if (f->MustFlush()) f->Flush();
2064  delete [] header;
2065 }
2066 
2067 ////////////////////////////////////////////////////////////////////////////////
2068 /// Write Keys linked list on the file.
2069 ///
2070 /// The linked list of keys (fKeys) is written as a single data record
2071 
2074  TFile* f = GetFile();
2075  if (f==0) return;
2076 
2077  if (!f->IsBinary()) {
2078  f->DirWriteKeys(this);
2079  return;
2080  }
2081 
2082 //*-* Delete the old keys structure if it exists
2083  if (fSeekKeys != 0) {
2085  }
2086 //*-* Write new keys record
2087  TIter next(fKeys);
2088  TKey *key;
2089  Int_t nkeys = fKeys->GetSize();
2090  Int_t nbytes = sizeof nkeys; //*-* Compute size of all keys
2091  if (f->GetEND() > TFile::kStartBigFile) nbytes += 8;
2092  while ((key = (TKey*)next())) {
2093  nbytes += key->Sizeof();
2094  }
2095  TKey *headerkey = new TKey(fName,fTitle,IsA(),nbytes,this);
2096  if (headerkey->GetSeekKey() == 0) {
2097  delete headerkey;
2098  return;
2099  }
2100  char *buffer = headerkey->GetBuffer();
2101  next.Reset();
2102  tobuf(buffer, nkeys);
2103  while ((key = (TKey*)next())) {
2104  key->FillBuffer(buffer);
2105  }
2106 
2107  fSeekKeys = headerkey->GetSeekKey();
2108  fNbytesKeys = headerkey->GetNbytes();
2109  headerkey->WriteFile();
2110  delete headerkey;
2111 }
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:778
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:1272
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:88
Bool_t IsReading() const
Definition: TBuffer.h:81
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:171
static Int_t DecreaseDirLevel()
Decrease the indentation level for ls().
Definition: TROOT.cxx:2569
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:409
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:847
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: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:150
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:89
const Ssiz_t kNPOS
Definition: RtypesCore.h:115
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: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:159
virtual const char * GetClassName() const
Definition: TKey.h:71
#define BIT(n)
Definition: Rtypes.h:75
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:2109
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:4360
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:1606
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: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:375
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:587
Basic string class.
Definition: TString.h:129
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2814
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:156
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:687
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:501
void SumBuffer(Int_t bufsize)
Increment statistics for buffer sizes of objects in this file.
Definition: TFile.cxx:2253
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: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:3909
virtual void ls(Option_t *option="") const
List Key contents.
Definition: TKey.cxx:685
#define gFile
Definition: TFile.h:318
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:499
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:135
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:2379
Int_t bsize[]
Definition: SparseFit4.cxx:31
virtual void Copy(TObject &object) const
Copy this to obj.
Definition: TObject.cxx:60
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
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:147
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
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:145
virtual void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Definition: TObject.cxx:485
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: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:1943
virtual void Delete(Option_t *option="")
Delete this object.
Definition: TObject.cxx:176
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:561
R__EXTERN TSystem * gSystem
Definition: TSystem.h:539
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:679
virtual Bool_t WriteBuffer(const char *buf, Int_t len)
Write a buffer to the file.
Definition: TFile.cxx:2312
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:436
TUUID fUUID
Definition: TDirectory.h:90
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:563
virtual Bool_t MustFlush() const
Definition: TFile.h:239
virtual TObject * Before(const TObject *obj) const
Returns the object before object obj.
Definition: TList.cxx:326
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:2332
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:873
virtual Bool_t ReadFile()
Read the key structure from the file.
Definition: TKey.cxx:1261
virtual Long64_t GetSeekPdir() const
Definition: TKey.h:86
Ssiz_t Length() const
Definition: TString.h:388
virtual void MakeFree(Long64_t first, Long64_t last)
Mark unused bytes on the file.
Definition: TFile.cxx:1398
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: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:271
short Short_t
Definition: RtypesCore.h:35
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition: TROOT.cxx:2632
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:71
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:177
TString fName
Definition: TNamed.h:32
static TFile *& CurrentFile()
Return the current ROOT file if any.
Definition: TFile.cxx:1021
virtual TObjLink * FirstLink() const
Definition: TList.h:97
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:88
virtual TKey * FindKeyAny(const char *) const
Definition: TDirectory.h:130
#define R__LOCKGUARD2(mutex)
virtual void WriteDirHeader()
Overwrite the Directory header record.
const Bool_t kFALSE
Definition: RtypesCore.h:92
virtual Int_t AppendKey(TKey *)
Definition: TDirectory.h:117
void SetMotherDir(TDirectory *dir)
Definition: TKey.h:102
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:336
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: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: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:82
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:572
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:2885
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:80
Bool_t IsNull() const
Definition: TString.h:385
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:2624
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5575
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:85
virtual void Add(TObject *obj)
Definition: TList.h:77
void(* DirAutoAdd_t)(void *, TDirectory *)
Definition: Rtypes.h:107
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: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:61
R__EXTERN Int_t gDebug
Definition: Rtypes.h:83
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:466
#define gDirectory
Definition: TDirectory.h:211
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:49
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:901
virtual void WriteHeader()
Write File Header.
Definition: TFile.cxx:2451
Bool_t IsWritable() const
const Bool_t kIterBackward
Definition: TCollection.h:38
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:364
virtual Int_t GetSize() const
Definition: TCollection.h:89
Abstract Interface class describing Streamer information for one class.
Int_t Sizeof() const
Definition: TDatime.h:81
const Bool_t kTRUE
Definition: RtypesCore.h:91
static char * skip(char **buf, const char *delimiters)
Definition: civetweb.c:2039
const Int_t n
Definition: legend1.C:16
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: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:347
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