Logo ROOT   6.21/01
Reference Guide
TKey.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id$
2 // Author: Rene Brun 28/12/94
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, 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 TKey
14 \ingroup IO
15 
16  Book space in a file, create I/O buffers, to fill them, (un)compress them.
17 
18  The TKey class includes functions to book space in a file, to create I/O
19  buffers, to fill these buffers, to compress/uncompress data buffers.
20  Before saving (making persistent) an object in a file, a key must
21  be created. The key structure contains all the information to
22  uniquely identify a persistent object in a file.
23  | Data Member | Explanation |
24  |-------------|-------------|
25  | fNbytes | Number of bytes for the compressed object and key. |
26  | fObjlen | Length of uncompressed object. |
27  | fDatime | Date/Time when the object was written. |
28  | fKeylen | Number of bytes for the key structure. |
29  | fCycle | Cycle number of the object. |
30  | fSeekKey | Address of the object on file (points to fNbytes). This is a redundant information used to cross-check the data base integrity. |
31  | fSeekPdir | Pointer to the directory supporting this object.|
32  | fClassName | Object class name. |
33  | fName | Name of the object. |
34  | fTitle | Title of the object. |
35 
36  In the 16 highest bits of fSeekPdir is encoded a pid offset. This
37  offset is to be added to the pid index stored in the TRef object
38  and the referenced TObject.
39 
40  The TKey class is used by ROOT to:
41  - Write an object in the current directory
42  - Write a new ntuple buffer
43 
44  The structure of a file is shown in TFile::TFile.
45  The structure of a directory is shown in TDirectoryFile::TDirectoryFile.
46  The TKey class is used by the TBasket class.
47  See also TTree.
48 */
49 
50 #include <atomic>
51 
52 #include "Riostream.h"
53 #include "TROOT.h"
54 #include "TClass.h"
55 #include "TDirectoryFile.h"
56 #include "TFile.h"
57 #include "TKey.h"
58 #include "TBufferFile.h"
59 #include "TFree.h"
60 #include "TBrowser.h"
61 #include "Bytes.h"
62 #include "TInterpreter.h"
63 #include "TError.h"
64 #include "TVirtualStreamerInfo.h"
65 #include "TSchemaRuleSet.h"
66 
67 #include "RZip.h"
68 
69 const Int_t kTitleMax = 32000;
70 #if 0
71 const Int_t kMAXFILEBUFFER = 262144;
72 #endif
73 
74 #if !defined(_MSC_VER) || (_MSC_VER>1300)
75 const ULong64_t kPidOffsetMask = 0xffffffffffffULL;
76 #else
77 const ULong64_t kPidOffsetMask = 0xffffffffffffUL;
78 #endif
80 
82  TTHREAD_TLS_DECL_ARG(TString,gTDirectoryString,"TDirectory");
83  return gTDirectoryString;
84 }
85 std::atomic<UInt_t> keyAbsNumber{0};
86 
87 ClassImp(TKey);
88 
89 ////////////////////////////////////////////////////////////////////////////////
90 /// TKey default constructor.
91 
92 TKey::TKey() : TNamed(), fDatime((UInt_t)0)
93 {
94  Build(0, "", 0);
95 
96  fKeylen = Sizeof();
97 
99 }
100 
101 ////////////////////////////////////////////////////////////////////////////////
102 /// TKey default constructor.
103 
104 TKey::TKey(TDirectory* motherDir) : TNamed(), fDatime((UInt_t)0)
105 {
106  Build(motherDir, "", 0);
107 
108  fKeylen = Sizeof();
109 
111 }
112 
113 ////////////////////////////////////////////////////////////////////////////////
114 /// Copy a TKey from its original directory to the new 'motherDir'
115 
116 TKey::TKey(TDirectory* motherDir, const TKey &orig, UShort_t pidOffset) : TNamed(), fDatime((UInt_t)0)
117 {
118  fMotherDir = motherDir;
119 
120  fPidOffset = orig.fPidOffset + pidOffset;
121  fNbytes = orig.fNbytes;
122  fObjlen = orig.fObjlen;
123  fClassName = orig.fClassName;
124  fName = orig.fName;
125  fTitle = orig.fTitle;
126 
127  fCycle = fMotherDir->AppendKey(this);
128  fSeekPdir = 0;
129  fSeekKey = 0;
130  fLeft = 0;
131 
132  fVersion = TKey::Class_Version();
133  Long64_t filepos = GetFile()->GetEND();
134  if (filepos > TFile::kStartBigFile || fPidOffset) fVersion += 1000;
135 
136  fKeylen = Sizeof(); // fVersion must be set.
137 
138  UInt_t bufferDecOffset = 0;
139  UInt_t bufferIncOffset = 0;
140  UInt_t alloc = fNbytes + sizeof(Int_t); // The extra Int_t is for any free space information.
141  if (fKeylen < orig.fKeylen) {
142  bufferDecOffset = orig.fKeylen - fKeylen;
143  fNbytes -= bufferDecOffset;
144  } else if (fKeylen > orig.fKeylen) {
145  bufferIncOffset = fKeylen - orig.fKeylen;
146  alloc += bufferIncOffset;
147  fNbytes += bufferIncOffset;
148  }
149 
150  fBufferRef = new TBufferFile(TBuffer::kWrite, alloc);
152 
153  // Steal the data from the old key.
154 
155  TFile* f = orig.GetFile();
156  if (f) {
157  Int_t nsize = orig.fNbytes;
158  f->Seek(orig.fSeekKey);
159  if( f->ReadBuffer(fBuffer+bufferIncOffset,nsize) )
160  {
161  Error("ReadFile", "Failed to read data.");
162  return;
163  }
164  if (gDebug) {
165  std::cout << "TKey Reading "<<nsize<< " bytes at address "<<fSeekKey<<std::endl;
166  }
167  }
168  fBuffer += bufferDecOffset; // Reset the buffer to be appropriate for this key.
169  Int_t nout = fNbytes - fKeylen;
170  Create(nout);
171  fBufferRef->SetBufferOffset(bufferDecOffset);
172  Streamer(*fBufferRef); //write key itself again
173 }
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 /// Create a TKey object to read keys.
177 /// Constructor called by TDirectoryFile::ReadKeys and by TFile::TFile.
178 /// A TKey object is created to read the keys structure itself.
179 
180 TKey::TKey(Long64_t pointer, Int_t nbytes, TDirectory* motherDir) : TNamed()
181 {
182  Build(motherDir, "", pointer);
183 
184  fSeekKey = pointer;
185  fNbytes = nbytes;
186  fBuffer = new char[nbytes];
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 /// Create a TKey object with the specified name, title for the given class.
192 ///
193 /// WARNING: in name avoid special characters like '^','$','.' that are used
194 /// by the regular expression parser (see TRegexp).
195 
196 TKey::TKey(const char *name, const char *title, const TClass *cl, Int_t nbytes, TDirectory* motherDir)
197  : TNamed(name,title)
198 {
199  Build(motherDir, cl->GetName(), -1);
200 
201  fKeylen = Sizeof();
202  fObjlen = nbytes;
203  Create(nbytes);
204 }
205 
206 ////////////////////////////////////////////////////////////////////////////////
207 /// Create a TKey object with the specified name, title for the given class.
208 ///
209 /// WARNING: in name avoid special characters like '^','$','.' that are used
210 /// by the regular expression parser (see TRegexp).
211 
212 TKey::TKey(const TString &name, const TString &title, const TClass *cl, Int_t nbytes, TDirectory* motherDir)
213  : TNamed(name,title)
214 {
215  Build(motherDir, cl->GetName(), -1);
216 
217  fKeylen = Sizeof();
218  fObjlen = nbytes;
219  Create(nbytes);
220 }
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 /// Create a TKey object for a TObject* and fill output buffer
224 ///
225 /// WARNING: in name avoid special characters like '^','$','.' that are used
226 /// by the regular expression parser (see TRegexp).
227 
228 TKey::TKey(const TObject *obj, const char *name, Int_t bufsize, TDirectory* motherDir)
229  : TNamed(name, obj->GetTitle())
230 {
231  R__ASSERT(obj);
232 
233  if (!obj->IsA()->HasDefaultConstructor()) {
234  Warning("TKey", "since %s has no public constructor\n"
235  "\twhich can be called without argument, objects of this class\n"
236  "\tcan not be read with the current library. You will need to\n"
237  "\tadd a default constructor before attempting to read it.",
238  obj->ClassName());
239  }
240 
241  Build(motherDir, obj->ClassName(), -1);
242 
243  Int_t lbuf, nout, noutot, bufmax, nzip;
244  fBufferRef = new TBufferFile(TBuffer::kWrite, bufsize);
246  fCycle = fMotherDir->AppendKey(this);
247 
248  Streamer(*fBufferRef); //write key itself
250  fBufferRef->MapObject(obj); //register obj in map in case of self reference
251  ((TObject*)obj)->Streamer(*fBufferRef); //write object
252  lbuf = fBufferRef->Length();
253  fObjlen = lbuf - fKeylen;
254 
255  Int_t cxlevel = GetFile() ? GetFile()->GetCompressionLevel() : 0;
257  if (cxlevel > 0 && fObjlen > 256) {
258  Int_t nbuffers = 1 + (fObjlen - 1)/kMAXZIPBUF;
259  Int_t buflen = TMath::Max(512,fKeylen + fObjlen + 9*nbuffers + 28); //add 28 bytes in case object is placed in a deleted gap
260  fBuffer = new char[buflen];
261  char *objbuf = fBufferRef->Buffer() + fKeylen;
262  char *bufcur = &fBuffer[fKeylen];
263  noutot = 0;
264  nzip = 0;
265  for (Int_t i = 0; i < nbuffers; ++i) {
266  if (i == nbuffers - 1) bufmax = fObjlen - nzip;
267  else bufmax = kMAXZIPBUF;
268  R__zipMultipleAlgorithm(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout, cxAlgorithm);
269  if (nout == 0 || nout >= fObjlen) { //this happens when the buffer cannot be compressed
271  Create(fObjlen);
273  Streamer(*fBufferRef); //write key itself again
274  return;
275  }
276  bufcur += nout;
277  noutot += nout;
278  objbuf += kMAXZIPBUF;
279  nzip += kMAXZIPBUF;
280  }
281  Create(noutot);
283  Streamer(*fBufferRef); //write key itself again
284  memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
285  delete fBufferRef; fBufferRef = 0;
286  } else {
288  Create(fObjlen);
290  Streamer(*fBufferRef); //write key itself again
291  }
292 }
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 /// Create a TKey object for any object obj of class cl d and fill
296 /// output buffer.
297 ///
298 /// WARNING: in name avoid special characters like '^','$','.' that are used
299 /// by the regular expression parser (see TRegexp).
300 
301 TKey::TKey(const void *obj, const TClass *cl, const char *name, Int_t bufsize, TDirectory* motherDir)
302  : TNamed(name, "object title")
303 {
304  R__ASSERT(obj && cl);
305 
306  if (!cl->HasDefaultConstructor()) {
307  Warning("TKey", "since %s has no public constructor\n"
308  "\twhich can be called without argument, objects of this class\n"
309  "\tcan not be read with the current library. You will need to\n"
310  "\tadd a default constructor before attempting to read it.",
311  cl->GetName());
312  }
313 
314  TClass *clActual = cl->GetActualClass(obj);
315  const void* actualStart;
316  if (clActual) {
317  const char *temp = (const char*) obj;
318  // clActual->GetStreamerInfo();
319  Int_t offset = (cl != clActual) ?
320  clActual->GetBaseClassOffset(cl) : 0;
321  temp -= offset;
322  actualStart = temp;
323  } else {
324  // We could not determine the real type of this object,
325  // let's assume it is the one given by the caller.
326  clActual = const_cast<TClass*>(cl);
327  actualStart = obj;
328  }
329 
330  Build(motherDir, clActual->GetName(), -1);
331 
332  fBufferRef = new TBufferFile(TBuffer::kWrite, bufsize);
334  fCycle = fMotherDir->AppendKey(this);
335 
336  Streamer(*fBufferRef); //write key itself
338 
339  Int_t lbuf, nout, noutot, bufmax, nzip;
340 
341  fBufferRef->MapObject(actualStart,clActual); //register obj in map in case of self reference
342  clActual->Streamer((void*)actualStart, *fBufferRef); //write object
343  lbuf = fBufferRef->Length();
344  fObjlen = lbuf - fKeylen;
345 
346  Int_t cxlevel = GetFile() ? GetFile()->GetCompressionLevel() : 0;
348  if (cxlevel > 0 && fObjlen > 256) {
349  Int_t nbuffers = 1 + (fObjlen - 1)/kMAXZIPBUF;
350  Int_t buflen = TMath::Max(512,fKeylen + fObjlen + 9*nbuffers + 28); //add 28 bytes in case object is placed in a deleted gap
351  fBuffer = new char[buflen];
352  char *objbuf = fBufferRef->Buffer() + fKeylen;
353  char *bufcur = &fBuffer[fKeylen];
354  noutot = 0;
355  nzip = 0;
356  for (Int_t i = 0; i < nbuffers; ++i) {
357  if (i == nbuffers - 1) bufmax = fObjlen - nzip;
358  else bufmax = kMAXZIPBUF;
359  R__zipMultipleAlgorithm(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout, cxAlgorithm);
360  if (nout == 0 || nout >= fObjlen) { //this happens when the buffer cannot be compressed
362  Create(fObjlen);
364  Streamer(*fBufferRef); //write key itself again
365  return;
366  }
367  bufcur += nout;
368  noutot += nout;
369  objbuf += kMAXZIPBUF;
370  nzip += kMAXZIPBUF;
371  }
372  Create(noutot);
374  Streamer(*fBufferRef); //write key itself again
375  memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
376  delete fBufferRef; fBufferRef = 0;
377  } else {
379  Create(fObjlen);
381  Streamer(*fBufferRef); //write key itself again
382  }
383 }
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 /// Method used in all TKey constructor to initialize basic data fields.
387 ///
388 /// The member filepos is used to calculate correct version number of key
389 /// if filepos==-1, end of file position is used.
390 
391 void TKey::Build(TDirectory* motherDir, const char* classname, Long64_t filepos)
392 {
393  fMotherDir = motherDir;
394 
395  fPidOffset = 0;
396  fNbytes = 0;
397  fBuffer = 0;
398  fKeylen = 0;
399  fObjlen = 0;
400  fBufferRef = 0;
401  fCycle = 0;
402  fSeekPdir = 0;
403  fSeekKey = 0;
404  fLeft = 0;
405 
406  fClassName = classname;
407  //the following test required for forward and backward compatibility
408  if (fClassName == "TDirectoryFile") SetBit(kIsDirectoryFile);
409 
410  fVersion = TKey::Class_Version();
411 
412  if ((filepos==-1) && GetFile()) filepos = GetFile()->GetEND();
413  if (filepos > TFile::kStartBigFile) fVersion += 1000;
414 
416 
419 }
420 
421 ////////////////////////////////////////////////////////////////////////////////
422 /// Read object from disk and call its Browse() method.
423 ///
424 /// If object with same name already exist in memory delete it (like
425 /// TDirectoryFile::Get() is doing), except when the key references a
426 /// folder in which case we don't want to re-read the folder object
427 /// since it might contain new objects not yet saved.
428 
430 {
431  if (fMotherDir==0) return;
432 
434 
435  void* obj = fMotherDir->GetList()->FindObject(GetName());
436  if (obj && objcl->IsTObject()) {
437  TObject *tobj = (TObject*) objcl->DynamicCast(TObject::Class(), obj);
438  if (!tobj->IsFolder()) {
439  if (tobj->InheritsFrom(TCollection::Class()))
440  tobj->Delete(); // delete also collection elements
441  delete tobj;
442  obj = 0;
443  }
444  }
445 
446  if (!obj)
447  obj = ReadObj();
448 
449  if (b && obj) {
450  objcl->Browse(obj,b);
451  b->SetRefreshFlag(kTRUE);
452  }
453 }
454 
455 ////////////////////////////////////////////////////////////////////////////////
456 /// Create a TKey object of specified size.
457 ///
458 /// If externFile!=0, key will be allocated in specified file, otherwise file
459 /// of mother directory will be used.
460 
461 void TKey::Create(Int_t nbytes, TFile* externFile)
462 {
464 
465  TFile *f = externFile;
466  if (!f) f = GetFile();
467  if (!f) {
468  Error("Create","Cannot create key without file");
469  return;
470  }
471 
472  Int_t nsize = nbytes + fKeylen;
473  TList *lfree = f->GetListOfFree();
474  TFree *f1 = (TFree*)lfree->First();
475 //*-*-------------------find free segment
476 //*-* =================
477  TFree *bestfree = f1->GetBestFree(lfree,nsize);
478  if (bestfree == 0) {
479  Error("Create","Cannot allocate %d bytes for ID = %s Title = %s",
480  nsize,GetName(),GetTitle());
481  return;
482  }
483 
484  if (f->TestBit(TFile::kReproducible))
486 
487  fDatime.Set();
488  fSeekKey = bestfree->GetFirst();
489 //*-*----------------- Case Add at the end of the file
490  if (fSeekKey >= f->GetEND()) {
491  f->SetEND(fSeekKey+nsize);
492  bestfree->SetFirst(fSeekKey+nsize);
493  if (f->GetEND() > bestfree->GetLast()) {
494  bestfree->SetLast(bestfree->GetLast() + 1000000000);
495  }
496  fLeft = -1;
497  if (!fBuffer) fBuffer = new char[nsize];
498  } else {
499  fLeft = Int_t(bestfree->GetLast() - fSeekKey - nsize + 1);
500  }
501 //*-*----------------- Case where new object fills exactly a deleted gap
502  fNbytes = nsize;
503  if (fLeft == 0) {
504  if (!fBuffer) {
505  fBuffer = new char[nsize];
506  }
507  lfree->Remove(bestfree);
508  delete bestfree;
509  }
510 //*-*----------------- Case where new object is placed in a deleted gap larger than itself
511  if (fLeft > 0) { // found a bigger segment
512  if (!fBuffer) {
513  fBuffer = new char[nsize+sizeof(Int_t)];
514  }
515  char *buffer = fBuffer+nsize;
516  Int_t nbytesleft = -fLeft; // set header of remaining record
517  tobuf(buffer, nbytesleft);
518  bestfree->SetFirst(fSeekKey+nsize);
519  }
520 
521  fSeekPdir = externFile ? externFile->GetSeekDir() : fMotherDir->GetSeekDir();
522 }
523 
524 ////////////////////////////////////////////////////////////////////////////////
525 /// TKey default destructor.
526 
528 {
529  // delete [] fBuffer; fBuffer = 0;
530  // delete fBufferRef; fBufferRef = 0;
531 
532  DeleteBuffer();
533 }
534 
535 ////////////////////////////////////////////////////////////////////////////////
536 /// Delete an object from the file.
537 ///
538 /// Note: the key is not deleted. You still have to call "delete key".
539 /// This is different from the behaviour of TObject::Delete()!
540 
541 void TKey::Delete(Option_t *option)
542 {
543  if (option && option[0] == 'v') printf("Deleting key: %s at address %lld, nbytes = %d\n",GetName(),fSeekKey,fNbytes);
545  Long64_t last = fSeekKey + fNbytes -1;
546  if (GetFile()) GetFile()->MakeFree(first, last); // release space used by this key
547  fMotherDir->GetListOfKeys()->Remove(this);
548 }
549 
550 ////////////////////////////////////////////////////////////////////////////////
551 /// Delete key buffer(s).
552 
554 {
555  if (fBufferRef) {
556  delete fBufferRef;
557  fBufferRef = 0;
558  } else {
559  // We only need to delete fBuffer if fBufferRef is zero because
560  // if fBufferRef exists, we delegate ownership of fBuffer to fBufferRef.
561  if (fBuffer) {
562  delete [] fBuffer;
563  }
564  }
565  fBuffer = 0;
566 }
567 
568 ////////////////////////////////////////////////////////////////////////////////
569 /// Return cycle number associated to this key.
570 
572 {
573  return ((fCycle >0) ? fCycle : -fCycle);
574 }
575 
576 ////////////////////////////////////////////////////////////////////////////////
577 /// Returns file to which key belong.
578 
580 {
581  return fMotherDir!=0 ? fMotherDir->GetFile() : gFile;
582 }
583 
584 ////////////////////////////////////////////////////////////////////////////////
585 /// Returns the "KEEP" status.
586 
588 {
589  return ((fCycle >0) ? 0 : 1);
590 }
591 
592 ////////////////////////////////////////////////////////////////////////////////
593 /// Encode key header into output buffer.
594 
595 void TKey::FillBuffer(char *&buffer)
596 {
597  tobuf(buffer, fNbytes);
598  Version_t version = fVersion;
599  tobuf(buffer, version);
600 
601  tobuf(buffer, fObjlen);
603  TDatime((UInt_t) 1).FillBuffer(buffer);
604  else
605  fDatime.FillBuffer(buffer);
606  tobuf(buffer, fKeylen);
607  tobuf(buffer, fCycle);
608  if (fVersion > 1000) {
609  tobuf(buffer, fSeekKey);
610 
611  // We currently store in the 16 highest bit of fSeekPdir the value of
612  // fPidOffset. This offset is used when a key (or basket) is transfered from one
613  // file to the other. In this case the TRef and TObject might have stored a
614  // pid index (to retrieve TProcessIDs) which refered to their order on the original
615  // file, the fPidOffset is to be added to those values to correctly find the
616  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
617  // and need to be zero for new key/basket.
619  tobuf(buffer, pdir);
620  } else {
621  tobuf(buffer, (Int_t)fSeekKey);
622  tobuf(buffer, (Int_t)fSeekPdir);
623  }
624  if (TestBit(kIsDirectoryFile)) {
625  // We want to record "TDirectory" instead of TDirectoryFile so that the file can be read by ancient version of ROOT.
626  gTDirectoryString().FillBuffer(buffer);
627  } else {
628  fClassName.FillBuffer(buffer);
629  }
630  fName.FillBuffer(buffer);
631  fTitle.FillBuffer(buffer);
632 }
633 
634 ////////////////////////////////////////////////////////////////////////////////
635 /// Increment fPidOffset by 'offset'.
636 ///
637 /// This offset is used when a key (or basket) is transfered from one file to
638 /// the other. In this case the TRef and TObject might have stored a pid
639 /// index (to retrieve TProcessIDs) which refered to their order on the
640 /// original file, the fPidOffset is to be added to those values to correctly
641 /// find the TProcessID. This fPidOffset needs to be increment if the
642 /// key/basket is copied and need to be zero for new key/basket.
643 
645 {
646  fPidOffset += offset;
647  if (fPidOffset) {
648  // We currently store fPidOffset in the 16 highest bit of fSeekPdir, which
649  // need to be store as a 64 bit integer. So we require this key to be
650  // a 'large file' key.
651  if (fVersion<1000) fVersion += 1000;
652  }
653 }
654 
655 ////////////////////////////////////////////////////////////////////////////////
656 /// Check if object referenced by the key is a folder.
657 
659 {
660  Bool_t ret = kFALSE;
661 
662  TClass *classPtr = TClass::GetClass((const char *) fClassName);
663  if (classPtr && classPtr->GetState() > TClass::kEmulated && classPtr->IsTObject()) {
664  TObject *obj = (TObject *) classPtr->DynamicCast(TObject::Class(), classPtr->New(TClass::kDummyNew));
665  if (obj) {
666  ret = obj->IsFolder();
667  delete obj;
668  }
669  }
670 
671  return ret;
672 }
673 
674 ////////////////////////////////////////////////////////////////////////////////
675 /// Set the "KEEP" status.
676 ///
677 /// When the KEEP flag is set to 1 the object cannot be purged.
678 
680 {
681  if (fCycle >0) fCycle = -fCycle;
682 }
683 
684 ////////////////////////////////////////////////////////////////////////////////
685 /// List Key contents.
686 
687 void TKey::ls(Option_t *) const
688 {
690  std::cout <<"KEY: "<<fClassName<<"\t"<<GetName()<<";"<<GetCycle()<<"\t"<<GetTitle()<<std::endl;
691 }
692 
693 ////////////////////////////////////////////////////////////////////////////////
694 /// Print key contents.
695 
696 void TKey::Print(Option_t *) const
697 {
698  printf("TKey Name = %s, Title = %s, Cycle = %d\n",GetName(),GetTitle(),GetCycle());
699 }
700 
701 ////////////////////////////////////////////////////////////////////////////////
702 /// To read a TObject* from the file.
703 ///
704 /// The object associated to this key is read from the file into memory
705 /// Once the key structure is read (via Streamer) the class identifier
706 /// of the object is known.
707 /// Using the class identifier we find the TClass object for this class.
708 /// A TClass object contains a full description (i.e. dictionary) of the
709 /// associated class. In particular the TClass object can create a new
710 /// object of the class type it describes. This new object now calls its
711 /// Streamer function to rebuilt itself.
712 ///
713 /// Use TKey::ReadObjectAny to read any object non-derived from TObject
714 ///
715 /// ### Note
716 /// A C style cast can only be used in the case where the final class
717 /// of this object derives from TObject as a first inheritance, otherwise
718 /// one must use a dynamic_cast.
719 ///
720 /// #### Example1: simplified case
721 /// class MyClass : public TObject, public AnotherClass
722 /// then on return, one get away with using:
723 /// MyClass *obj = (MyClass*)key->ReadObj();
724 ///
725 /// #### Example2: Usual case (recommended unless performance is critical)
726 /// MyClass *obj = dynamic_cast<MyClass*>(key->ReadObj());
727 /// which support also the more complex inheritance like:
728 /// class MyClass : public AnotherClass, public TObject
729 ///
730 /// Of course, dynamic_cast<> can also be used in the example 1.
731 
733 {
735  if (!cl) {
736  Error("ReadObj", "Unknown class %s", fClassName.Data());
737  return 0;
738  }
739  if (!cl->IsTObject()) {
740  // in principle user should call TKey::ReadObjectAny!
741  return (TObject*)ReadObjectAny(0);
742  }
743 
745  if (!fBufferRef) {
746  Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
747  return 0;
748  }
749  if (GetFile()==0) return 0;
752 
753  if (fObjlen > fNbytes-fKeylen) {
754  fBuffer = new char[fNbytes];
755  if( !ReadFile() ) //Read object structure from file
756  {
757  delete fBufferRef;
758  delete [] fBuffer;
759  fBufferRef = 0;
760  fBuffer = 0;
761  return 0;
762  }
763  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
764  } else {
766  if( !ReadFile() ) { //Read object structure from file
767  delete fBufferRef;
768  fBufferRef = 0;
769  fBuffer = 0;
770  return 0;
771  }
772  }
773 
774  // get version of key
776  Version_t kvers = fBufferRef->ReadVersion();
777 
779  TObject *tobj = 0;
780  // Create an instance of this class
781 
782  char *pobj = (char*)cl->New();
783  if (!pobj) {
784  Error("ReadObj", "Cannot create new object of class %s", fClassName.Data());
785  return 0;
786  }
787  Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
788  if (baseOffset==-1) {
789  // cl does not inherit from TObject.
790  // Since this is not possible yet, the only reason we could reach this code
791  // is because something is screw up in the ROOT code.
792  Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
793  fClassName.Data());
794  }
795  tobj = (TObject*)(pobj+baseOffset);
796  if (kvers > 1)
797  fBufferRef->MapObject(pobj,cl); //register obj in map to handle self reference
798 
799  if (fObjlen > fNbytes-fKeylen) {
800  char *objbuf = fBufferRef->Buffer() + fKeylen;
801  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
802  Int_t nin, nout = 0, nbuf;
803  Int_t noutot = 0;
804  while (1) {
805  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
806  if (hc!=0) break;
807  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
808  if (!nout) break;
809  noutot += nout;
810  if (noutot >= fObjlen) break;
811  bufcur += nin;
812  objbuf += nout;
813  }
814  if (nout) {
815  tobj->Streamer(*fBufferRef); //does not work with example 2 above
816  delete [] fBuffer;
817  } else {
818  delete [] fBuffer;
819  // Even-though we have a TObject, if the class is emulated the virtual
820  // table may not be 'right', so let's go via the TClass.
821  cl->Destructor(pobj);
822  pobj = 0;
823  tobj = 0;
824  goto CLEAR;
825  }
826  } else {
827  tobj->Streamer(*fBufferRef);
828  }
829 
830  if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
831 
832  if (cl->InheritsFrom(TDirectoryFile::Class())) {
833  TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
834  dir->SetName(GetName());
835  dir->SetTitle(GetTitle());
836  dir->SetMother(fMotherDir);
837  fMotherDir->Append(dir);
838  }
839 
840  // Append the object to the directory if requested:
841  {
842  ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
843  if (addfunc) {
844  addfunc(pobj, fMotherDir);
845  }
846  }
847 
848 CLEAR:
849  delete fBufferRef;
850  fBufferRef = 0;
851  fBuffer = 0;
852 
853  return tobj;
854 }
855 
856 ////////////////////////////////////////////////////////////////////////////////
857 /// To read a TObject* from bufferRead.
858 ///
859 /// This function is identical to TKey::ReadObj, but it reads directly from
860 /// bufferRead instead of reading from a file.
861 /// The object associated to this key is read from the buffer into memory
862 /// Using the class identifier we find the TClass object for this class.
863 /// A TClass object contains a full description (i.e. dictionary) of the
864 /// associated class. In particular the TClass object can create a new
865 /// object of the class type it describes. This new object now calls its
866 /// Streamer function to rebuilt itself.
867 ///
868 /// ### Note
869 /// This function is called only internally by ROOT classes.
870 /// Although being public it is not supposed to be used outside ROOT.
871 /// If used, you must make sure that the bufferRead is large enough to
872 /// accomodate the object being read.
873 
875 {
876 
878  if (!cl) {
879  Error("ReadObjWithBuffer", "Unknown class %s", fClassName.Data());
880  return 0;
881  }
882  if (!cl->IsTObject()) {
883  // in principle user should call TKey::ReadObjectAny!
884  return (TObject*)ReadObjectAny(0);
885  }
886 
888  if (!fBufferRef) {
889  Error("ReadObjWithBuffer", "Cannot allocate buffer: fObjlen = %d", fObjlen);
890  return 0;
891  }
892  if (GetFile()==0) return 0;
895 
896  if (fObjlen > fNbytes-fKeylen) {
897  fBuffer = bufferRead;
898  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
899  } else {
901  ReadFile(); //Read object structure from file
902  }
903 
904  // get version of key
906  Version_t kvers = fBufferRef->ReadVersion();
907 
909  TObject *tobj = 0;
910  // Create an instance of this class
911 
912  char *pobj = (char*)cl->New();
913  if (!pobj) {
914  Error("ReadObjWithBuffer", "Cannot create new object of class %s", fClassName.Data());
915  return 0;
916  }
917  Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
918  if (baseOffset==-1) {
919  // cl does not inherit from TObject.
920  // Since this is not possible yet, the only reason we could reach this code
921  // is because something is screw up in the ROOT code.
922  Fatal("ReadObjWithBuffer","Incorrect detection of the inheritance from TObject for class %s.\n",
923  fClassName.Data());
924  }
925  tobj = (TObject*)(pobj+baseOffset);
926 
927  if (kvers > 1)
928  fBufferRef->MapObject(pobj,cl); //register obj in map to handle self reference
929 
930  if (fObjlen > fNbytes-fKeylen) {
931  char *objbuf = fBufferRef->Buffer() + fKeylen;
932  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
933  Int_t nin, nout = 0, nbuf;
934  Int_t noutot = 0;
935  while (1) {
936  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
937  if (hc!=0) break;
938  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
939  if (!nout) break;
940  noutot += nout;
941  if (noutot >= fObjlen) break;
942  bufcur += nin;
943  objbuf += nout;
944  }
945  if (nout) {
946  tobj->Streamer(*fBufferRef); //does not work with example 2 above
947  } else {
948  // Even-though we have a TObject, if the class is emulated the virtual
949  // table may not be 'right', so let's go via the TClass.
950  cl->Destructor(pobj);
951  pobj = 0;
952  tobj = 0;
953  goto CLEAR;
954  }
955  } else {
956  tobj->Streamer(*fBufferRef);
957  }
958 
959  if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
960 
961  if (cl->InheritsFrom(TDirectoryFile::Class())) {
962  TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
963  dir->SetName(GetName());
964  dir->SetTitle(GetTitle());
965  dir->SetMother(fMotherDir);
966  fMotherDir->Append(dir);
967  }
968 
969  // Append the object to the directory if requested:
970  {
971  ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
972  if (addfunc) {
973  addfunc(pobj, fMotherDir);
974  }
975  }
976 
977 CLEAR:
978  delete fBufferRef;
979  fBufferRef = 0;
980  fBuffer = 0;
981 
982  return tobj;
983 }
984 
985 ////////////////////////////////////////////////////////////////////////////////
986 /// To read an object (non deriving from TObject) from the file.
987 ///
988 /// If expectedClass is not null, we checked that that actual class of the
989 /// object stored is suitable to be stored in a pointer pointing to an object
990 /// of class 'expectedClass'. We also adjust the value of the returned address
991 /// so that it is suitable to be cast (C-Style)
992 /// a pointer pointing to an object of class 'expectedClass'.
993 ///
994 /// So for example if the class Bottom inherits from Top and the object
995 /// stored is of type Bottom you can safely do:
996 /// ~~~{.cpp}
997 /// auto TopClass = TClass::GetClass("Top");
998 /// auto ptr = (Top*) key->ReadObjectAny( TopClass );
999 /// if (ptr==0) printError("the object stored in the key is not of the expected type\n");
1000 /// ~~~
1001 /// The object associated to this key is read from the file into memory.
1002 /// Once the key structure is read (via Streamer) the class identifier
1003 /// of the object is known.
1004 /// Using the class identifier we find the TClass object for this class.
1005 /// A TClass object contains a full description (i.e. dictionary) of the
1006 /// associated class. In particular the TClass object can create a new
1007 /// object of the class type it describes. This new object now calls its
1008 /// Streamer function to rebuilt itself.
1009 
1010 void *TKey::ReadObjectAny(const TClass* expectedClass)
1011 {
1013  if (!fBufferRef) {
1014  Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
1015  return 0;
1016  }
1017  if (GetFile()==0) return 0;
1020 
1021  if (fObjlen > fNbytes-fKeylen) {
1022  fBuffer = new char[fNbytes];
1023  ReadFile(); //Read object structure from file
1024  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
1025  } else {
1026  fBuffer = fBufferRef->Buffer();
1027  ReadFile(); //Read object structure from file
1028  }
1029 
1030  // get version of key
1032  Version_t kvers = fBufferRef->ReadVersion();
1033 
1036  TClass *clOnfile = 0;
1037  if (!cl) {
1038  Error("ReadObjectAny", "Unknown class %s", fClassName.Data());
1039  return 0;
1040  }
1041  Int_t baseOffset = 0;
1042  if (expectedClass) {
1043  // baseOffset will be -1 if cl does not inherit from expectedClass
1044  baseOffset = cl->GetBaseClassOffset(expectedClass);
1045  if (baseOffset == -1) {
1046  // The 2 classes are unrelated, maybe there is a converter between the 2.
1047 
1048  if (!expectedClass->GetSchemaRules() ||
1049  !expectedClass->GetSchemaRules()->HasRuleWithSourceClass(cl->GetName()))
1050  {
1051  // There is no converter
1052  return 0;
1053  }
1054  baseOffset = 0; // For now we do not support requesting from a class that is the base of one of the class for which there is transformation to ....
1055  clOnfile = cl;
1056  cl = const_cast<TClass*>(expectedClass);
1057  Info("ReadObjectAny","Using Converter StreamerInfo from %s to %s",clOnfile->GetName(),expectedClass->GetName());
1058  }
1059  if (cl->GetState() > TClass::kEmulated && expectedClass->GetState() <= TClass::kEmulated) {
1060  //we cannot mix a compiled class with an emulated class in the inheritance
1061  Warning("ReadObjectAny",
1062  "Trying to read an emulated class (%s) to store in a compiled pointer (%s)",
1063  cl->GetName(),expectedClass->GetName());
1064  }
1065  }
1066  // Create an instance of this class
1067 
1068  void *pobj = cl->New();
1069  if (!pobj) {
1070  Error("ReadObjectAny", "Cannot create new object of class %s", fClassName.Data());
1071  return 0;
1072  }
1073 
1074  if (kvers > 1)
1075  fBufferRef->MapObject(pobj,cl); //register obj in map to handle self reference
1076 
1077  if (fObjlen > fNbytes-fKeylen) {
1078  char *objbuf = fBufferRef->Buffer() + fKeylen;
1079  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
1080  Int_t nin, nout = 0, nbuf;
1081  Int_t noutot = 0;
1082  while (1) {
1083  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
1084  if (hc!=0) break;
1085  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
1086  if (!nout) break;
1087  noutot += nout;
1088  if (noutot >= fObjlen) break;
1089  bufcur += nin;
1090  objbuf += nout;
1091  }
1092  if (nout) {
1093  cl->Streamer((void*)pobj, *fBufferRef, clOnfile); //read object
1094  delete [] fBuffer;
1095  } else {
1096  delete [] fBuffer;
1097  cl->Destructor(pobj);
1098  pobj = 0;
1099  goto CLEAR;
1100  }
1101  } else {
1102  cl->Streamer((void*)pobj, *fBufferRef, clOnfile); //read object
1103  }
1104 
1105  if (cl->IsTObject()) {
1106  auto tobjBaseOffset = cl->GetBaseClassOffset(TObject::Class());
1107  if (tobjBaseOffset == -1) {
1108  Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
1109  fClassName.Data());
1110  }
1111  TObject *tobj = (TObject*)( ((char*)pobj) + tobjBaseOffset);
1112 
1113  // See similar adjustments in ReadObj
1114  if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
1115 
1116  if (cl->InheritsFrom(TDirectoryFile::Class())) {
1117  TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
1118  dir->SetName(GetName());
1119  dir->SetTitle(GetTitle());
1120  dir->SetMother(fMotherDir);
1121  fMotherDir->Append(dir);
1122  }
1123  }
1124 
1125  {
1126  // Append the object to the directory if requested:
1127  ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
1128  if (addfunc) {
1129  addfunc(pobj, fMotherDir);
1130  }
1131  }
1132 
1133  CLEAR:
1134  delete fBufferRef;
1135  fBufferRef = 0;
1136  fBuffer = 0;
1137 
1138  return ( ((char*)pobj) + baseOffset );
1139 }
1140 
1141 ////////////////////////////////////////////////////////////////////////////////
1142 /// To read an object from the file.
1143 ///
1144 /// The object associated to this key is read from the file into memory.
1145 /// Before invoking this function, obj has been created via the
1146 /// default constructor.
1147 
1149 {
1150  if (!obj || (GetFile()==0)) return 0;
1151 
1155 
1156  if (fVersion > 1)
1157  fBufferRef->MapObject(obj); //register obj in map to handle self reference
1158 
1159  if (fObjlen > fNbytes-fKeylen) {
1160  fBuffer = new char[fNbytes];
1161  ReadFile(); //Read object structure from file
1162  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
1163  } else {
1164  fBuffer = fBufferRef->Buffer();
1165  ReadFile(); //Read object structure from file
1166  }
1168  if (fObjlen > fNbytes-fKeylen) {
1169  char *objbuf = fBufferRef->Buffer() + fKeylen;
1170  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
1171  Int_t nin, nout = 0, nbuf;
1172  Int_t noutot = 0;
1173  while (1) {
1174  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
1175  if (hc!=0) break;
1176  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
1177  if (!nout) break;
1178  noutot += nout;
1179  if (noutot >= fObjlen) break;
1180  bufcur += nin;
1181  objbuf += nout;
1182  }
1183  if (nout) obj->Streamer(*fBufferRef);
1184  delete [] fBuffer;
1185  } else {
1186  obj->Streamer(*fBufferRef);
1187  }
1188 
1189  // Append the object to the directory if requested:
1190  {
1191  ROOT::DirAutoAdd_t addfunc = obj->IsA()->GetDirectoryAutoAdd();
1192  if (addfunc) {
1193  addfunc(obj, fMotherDir);
1194  }
1195  }
1196 
1197  delete fBufferRef;
1198  fBufferRef = 0;
1199  fBuffer = 0;
1200  return fNbytes;
1201 }
1202 
1203 ////////////////////////////////////////////////////////////////////////////////
1204 /// Decode input buffer.
1205 ///
1206 /// In some situation will add key to gDirectory.
1207 
1208 void TKey::ReadBuffer(char *&buffer)
1209 {
1210  ReadKeyBuffer(buffer);
1211 
1212  if (!gROOT->ReadingObject() && gDirectory) {
1213  if (fSeekPdir != gDirectory->GetSeekDir()) gDirectory->AppendKey(this);
1214  }
1215 }
1216 
1217 ////////////////////////////////////////////////////////////////////////////////
1218 /// Decode input buffer.
1219 
1220 void TKey::ReadKeyBuffer(char *&buffer)
1221 {
1222  frombuf(buffer, &fNbytes);
1223  Version_t version;
1224  frombuf(buffer,&version);
1225  fVersion = (Int_t)version;
1226  frombuf(buffer, &fObjlen);
1227  fDatime.ReadBuffer(buffer);
1228  frombuf(buffer, &fKeylen);
1229  frombuf(buffer, &fCycle);
1230  if (fVersion > 1000) {
1231  frombuf(buffer, &fSeekKey);
1232 
1233  // We currently store in the 16 highest bit of fSeekPdir the value of
1234  // fPidOffset. This offset is used when a key (or basket) is transfered from one
1235  // file to the other. In this case the TRef and TObject might have stored a
1236  // pid index (to retrieve TProcessIDs) which refered to their order on the original
1237  // file, the fPidOffset is to be added to those values to correctly find the
1238  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1239  // and need to be zero for new key/basket.
1240  Long64_t pdir;
1241  frombuf(buffer, &pdir);
1242  fPidOffset = pdir >> kPidOffsetShift;
1243  fSeekPdir = pdir & kPidOffsetMask;
1244  } else {
1245  UInt_t seekkey,seekdir;
1246  frombuf(buffer, &seekkey); fSeekKey = (Long64_t)seekkey;
1247  frombuf(buffer, &seekdir); fSeekPdir= (Long64_t)seekdir;
1248  }
1249  fClassName.ReadBuffer(buffer);
1250  //the following test required for forward and backward compatibility
1251  if (fClassName == "TDirectory") {
1252  fClassName = "TDirectoryFile";
1254  }
1255 
1256  fName.ReadBuffer(buffer);
1257  fTitle.ReadBuffer(buffer);
1258 }
1259 
1260 ////////////////////////////////////////////////////////////////////////////////
1261 /// Read the key structure from the file
1262 
1264 {
1265  TFile* f = GetFile();
1266  if (f==0) return kFALSE;
1267 
1268  Int_t nsize = fNbytes;
1269  f->Seek(fSeekKey);
1270 #if 0
1271  for (Int_t i = 0; i < nsize; i += kMAXFILEBUFFER) {
1272  int nb = kMAXFILEBUFFER;
1273  if (i+nb > nsize) nb = nsize - i;
1274  f->ReadBuffer(fBuffer+i,nb);
1275  }
1276 #else
1277  if( f->ReadBuffer(fBuffer,nsize) )
1278  {
1279  Error("ReadFile", "Failed to read data.");
1280  return kFALSE;
1281  }
1282 #endif
1283  if (gDebug) {
1284  std::cout << "TKey Reading "<<nsize<< " bytes at address "<<fSeekKey<<std::endl;
1285  }
1286  return kTRUE;
1287 }
1288 
1289 ////////////////////////////////////////////////////////////////////////////////
1290 /// Set parent in key buffer.
1291 
1292 void TKey::SetParent(const TObject *parent)
1293 {
1294  if (fBufferRef) fBufferRef->SetParent((TObject*)parent);
1295 }
1296 
1297 ////////////////////////////////////////////////////////////////////////////////
1298 /// Reset the key as it had not been 'filled' yet.
1299 
1301 {
1302  fPidOffset = 0;
1303  fNbytes = 0;
1304  fBuffer = 0;
1305  fObjlen = 0;
1306  fCycle = 0;
1307  fSeekPdir = 0;
1308  fSeekKey = 0;
1309  fLeft = 0;
1310  fDatime = (UInt_t)0;
1311 
1312  // fBufferRef and fKeylen intentionally not reset/changed
1313 
1315 }
1316 
1317 ////////////////////////////////////////////////////////////////////////////////
1318 /// Return the size in bytes of the key header structure.
1319 ///
1320 /// An explaination about the nbytes (Int_t nbytes) variable used in the
1321 /// function. The size of fSeekKey and fSeekPdir is 8 instead of 4 if version is
1322 /// greater than 1000.
1323 /// | Component | Sizeof |
1324 /// |-------------------|--------|
1325 /// | fNbytes | 4 |
1326 /// | sizeof(Version_t) | 2 |
1327 /// | fObjlen | 4 |
1328 /// | fKeylen | 2 |
1329 /// | fCycle | 2 |
1330 /// | fSeekKey | 4 or 8 |
1331 /// | fSeekPdir | 4 or 8 |
1332 /// | **TOTAL** | 22 |
1333 
1335 {
1336  Int_t nbytes = 22; if (fVersion > 1000) nbytes += 8;
1337  nbytes += fDatime.Sizeof();
1338  if (TestBit(kIsDirectoryFile)) {
1339  nbytes += 11; // strlen("TDirectory")+1
1340  } else {
1341  nbytes += fClassName.Sizeof();
1342  }
1343  nbytes += fName.Sizeof();
1344  nbytes += fTitle.Sizeof();
1345  return nbytes;
1346 }
1347 
1348 ////////////////////////////////////////////////////////////////////////////////
1349 /// Stream a class object.
1350 
1351 void TKey::Streamer(TBuffer &b)
1352 {
1353  Version_t version;
1354  if (b.IsReading()) {
1355  b >> fNbytes;
1356  b >> version; fVersion = (Int_t)version;
1357  b >> fObjlen;
1358  fDatime.Streamer(b);
1359  b >> fKeylen;
1360  b >> fCycle;
1361  if (fVersion > 1000) {
1362  b >> fSeekKey;
1363 
1364  // We currently store in the 16 highest bit of fSeekPdir the value of
1365  // fPidOffset. This offset is used when a key (or basket) is transfered from one
1366  // file to the other. In this case the TRef and TObject might have stored a
1367  // pid index (to retrieve TProcessIDs) which refered to their order on the original
1368  // file, the fPidOffset is to be added to those values to correctly find the
1369  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1370  // and need to be zero for new key/basket.
1371  Long64_t pdir;
1372  b >> pdir;
1373  fPidOffset = pdir >> kPidOffsetShift;
1374  fSeekPdir = pdir & kPidOffsetMask;
1375  } else {
1376  UInt_t seekkey, seekdir;
1377  b >> seekkey; fSeekKey = (Long64_t)seekkey;
1378  b >> seekdir; fSeekPdir= (Long64_t)seekdir;
1379  }
1380  fClassName.Streamer(b);
1381  //the following test required for forward and backward compatibility
1382  if (fClassName == "TDirectory") {
1383  fClassName = "TDirectoryFile";
1385  }
1386  fName.Streamer(b);
1387  fTitle.Streamer(b);
1388  if (fKeylen < 0) {
1389  Error("Streamer","The value of fKeylen is incorrect (%d) ; trying to recover by setting it to zero",fKeylen);
1390  MakeZombie();
1391  fKeylen = 0;
1392  }
1393  if (fObjlen < 0) {
1394  Error("Streamer","The value of fObjlen is incorrect (%d) ; trying to recover by setting it to zero",fObjlen);
1395  MakeZombie();
1396  fObjlen = 0;
1397  }
1398  if (fNbytes < 0) {
1399  Error("Streamer","The value of fNbytes is incorrect (%d) ; trying to recover by setting it to zero",fNbytes);
1400  MakeZombie();
1401  fNbytes = 0;
1402  }
1403 
1404  } else {
1405  b << fNbytes;
1406  version = (Version_t)fVersion;
1407  b << version;
1408  b << fObjlen;
1409  if (fDatime.Get() == 0) fDatime.Set();
1411  TDatime((UInt_t) 1).Streamer(b);
1412  else
1413  fDatime.Streamer(b);
1414  b << fKeylen;
1415  b << fCycle;
1416  if (fVersion > 1000) {
1417  b << fSeekKey;
1418 
1419  // We currently store in the 16 highest bit of fSeekPdir the value of
1420  // fPidOffset. This offset is used when a key (or basket) is transfered from one
1421  // file to the other. In this case the TRef and TObject might have stored a
1422  // pid index (to retrieve TProcessIDs) which refered to their order on the original
1423  // file, the fPidOffset is to be added to those values to correctly find the
1424  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1425  // and need to be zero for new key/basket.
1427  b << pdir;
1428  } else {
1429  b << (Int_t)fSeekKey;
1430  b << (Int_t)fSeekPdir;
1431  }
1432  if (TestBit(kIsDirectoryFile)) {
1433  // We want to record "TDirectory" instead of TDirectoryFile so that the file can be read by ancient version of ROOT.
1434  gTDirectoryString().Streamer(b);
1435  } else {
1436  fClassName.Streamer(b);
1437  }
1438  fName.Streamer(b);
1439  fTitle.Streamer(b);
1440  }
1441 }
1442 
1443 ////////////////////////////////////////////////////////////////////////////////
1444 /// Write the encoded object supported by this key.
1445 /// The function returns the number of bytes committed to the file.
1446 /// If a write error occurs, the number of bytes returned is -1.
1447 
1449 {
1450  if (!f) f = GetFile();
1451  if (!f) return -1;
1452 
1453  Int_t nsize = fNbytes;
1454  char *buffer = fBuffer;
1455  if (cycle) {
1456  fCycle = cycle;
1457  FillBuffer(buffer);
1458  buffer = fBuffer;
1459  }
1460 
1461  if (fLeft > 0) nsize += sizeof(Int_t);
1462  f->Seek(fSeekKey);
1463 #if 0
1464  for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
1465  Int_t nb = kMAXFILEBUFFER;
1466  if (i+nb > nsize) nb = nsize - i;
1467  f->WriteBuffer(buffer,nb);
1468  buffer += nb;
1469  }
1470 #else
1471  Bool_t result = f->WriteBuffer(buffer,nsize);
1472 #endif
1473  //f->Flush(); Flushing takes too much time.
1474  // Let user flush the file when they want.
1475  if (gDebug) {
1476  std::cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
1477  <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<std::endl;
1478  }
1479 
1480  DeleteBuffer();
1481  return result==kTRUE ? -1 : nsize;
1482 }
1483 
1484 ////////////////////////////////////////////////////////////////////////////////
1485 /// Write the encoded object supported by this key.
1486 /// The function returns the number of bytes committed to the file.
1487 /// If a write error occurs, the number of bytes returned is -1.
1488 
1490 {
1491  if (!f) f = GetFile();
1492  if (!f) return -1;
1493 
1494  Int_t nsize = fNbytes;
1495  char *buffer = fBuffer;
1496 
1497  if (fLeft > 0) nsize += sizeof(Int_t);
1498  f->Seek(fSeekKey);
1499 #if 0
1500  for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
1501  Int_t nb = kMAXFILEBUFFER;
1502  if (i+nb > nsize) nb = nsize - i;
1503  f->WriteBuffer(buffer,nb);
1504  buffer += nb;
1505  }
1506 #else
1507  Bool_t result = f->WriteBuffer(buffer,nsize);
1508 #endif
1509  //f->Flush(); Flushing takes too much time.
1510  // Let user flush the file when they want.
1511  if (gDebug) {
1512  std::cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
1513  <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<std::endl;
1514  }
1515 
1516  return result==kTRUE ? -1 : nsize;
1517 }
1518 
1519 ////////////////////////////////////////////////////////////////////////////////
1520 /// Title can keep 32x32 xpm thumbnail/icon of the parent object.
1521 
1522 const char *TKey::GetIconName() const
1523 {
1524  return (!fTitle.IsNull() && fTitle.BeginsWith("/* ") ? fTitle.Data() : 0);
1525 }
1526 
1527 ////////////////////////////////////////////////////////////////////////////////
1528 /// Returns title (title can contain 32x32 xpm thumbnail/icon).
1529 
1530 const char *TKey::GetTitle() const
1531 {
1532  if (!fTitle.IsNull() && fTitle.BeginsWith("/* ")) { // title contains xpm thumbnail
1533  static TString ret;
1534  int start = fTitle.Index("/*") + 3;
1535  int stop = fTitle.Index("*/") - 1;
1536  ret = fTitle(start, stop - start);
1537  return ret.Data();
1538  }
1539  return fTitle.Data();
1540 }
Int_t fVersion
Key version identifier.
Definition: TKey.h:35
Bool_t HasRuleWithSourceClass(const TString &source) const
Return True if we have any rule whose source class is &#39;source&#39;.
TString fTitle
Definition: TNamed.h:33
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:92
Int_t fLeft
Number of bytes left in current segment.
Definition: TKey.h:44
void frombuf(char *&buf, Bool_t *x)
Definition: Bytes.h:280
virtual const char * GetIconName() const
Title can keep 32x32 xpm thumbnail/icon of the parent object.
Definition: TKey.cxx:1522
virtual TList * GetListOfKeys() const
Definition: TDirectory.h:160
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket...
Definition: TBufferFile.h:46
long long Long64_t
Definition: RtypesCore.h:69
Long64_t GetLast() const
Definition: TFree.h:41
void Set()
Set Date/Time to current time as reported by the system.
Definition: TDatime.cxx:288
short Version_t
Definition: RtypesCore.h:61
const char Option_t
Definition: RtypesCore.h:62
const UChar_t kPidOffsetShift
Definition: TKey.cxx:79
UShort_t fPidOffset
!Offset to be added to the pid index in this key/buffer. This is actually saved in the high bits of f...
Definition: TKey.h:47
unsigned short UShort_t
Definition: RtypesCore.h:36
virtual const char * GetClassName() const
Definition: TKey.h:72
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:48
virtual void * ReadObjectAny(const TClass *expectedClass)
To read an object (non deriving from TObject) from the file.
Definition: TKey.cxx:1010
Buffer base class used for serializing objects.
Definition: TBuffer.h:42
TKey()
TKey default constructor.
Definition: TKey.cxx:92
#define R__ASSERT(e)
Definition: TError.h:96
#define gROOT
Definition: TROOT.h:415
virtual void Browse(TBrowser *b)
Read object from disk and call its Browse() method.
Definition: TKey.cxx:429
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
void Build(TDirectory *motherDir, const char *classname, Long64_t filepos)
Method used in all TKey constructor to initialize basic data fields.
Definition: TKey.cxx:391
Basic string class.
Definition: TString.h:131
#define f(i)
Definition: RSha256.hxx:104
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
void SetParent(TObject *parent)
Set parent owning this buffer.
Definition: TBuffer.cxx:270
virtual void UseCurrentStyle()
Set current style settings in this object This function is called when either TCanvas::UseCurrentStyl...
Definition: TObject.cxx:715
void SetName(const char *newname) override
Set the name for directory If the directory name is changed after the directory was written once...
const Int_t kTitleMax
Definition: TKey.cxx:69
char * fBuffer
Object buffer.
Definition: TKey.h:45
void ReadBuffer(char *&buffer)
Decode Date/Time from output buffer, used by I/O system.
Definition: TDatime.cxx:277
virtual void FillBuffer(char *&buffer)
Encode key header into output buffer.
Definition: TKey.cxx:595
TDirectory * fMotherDir
!pointer to mother directory
Definition: TKey.h:48
void SetLast(Long64_t last)
Definition: TFree.h:45
const ULong64_t kPidOffsetMask
Definition: TKey.cxx:75
virtual Int_t Sizeof() const
Return the size in bytes of the key header structure.
Definition: TKey.cxx:1334
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:575
Int_t Length() const
Definition: TBuffer.h:99
virtual void ls(Option_t *option="") const
List Key contents.
Definition: TKey.cxx:687
#define gFile
Definition: TFile.h:338
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2729
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:128
Service class for TFile.
Definition: TFree.h:27
Long64_t fSeekPdir
Location of parent directory on file.
Definition: TKey.h:42
virtual void ReadBuffer(char *&buffer)
Read string from I/O buffer.
Definition: TString.cxx:1264
virtual void Print(Option_t *option="") const
Print key contents.
Definition: TKey.cxx:696
void Class()
Definition: Class.C:29
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
char * Buffer() const
Definition: TBuffer.h:95
Short_t GetKeep() const
Returns the "KEEP" status.
Definition: TKey.cxx:587
void FillBuffer(char *&buffer)
Encode Date/Time into buffer, used by I/O system.
Definition: TDatime.cxx:228
virtual Int_t WriteFile(Int_t cycle=1, TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1448
EState GetState() const
Definition: TClass.h:453
int R__unzip_header(Int_t *nin, UChar_t *bufin, Int_t *lout)
Short_t fKeylen
Number of bytes for the key itself.
Definition: TKey.h:39
TString fClassName
Object Class name.
Definition: TKey.h:43
virtual ~TKey()
TKey default destructor.
Definition: TKey.cxx:527
virtual void SetPidOffset(UShort_t offset)=0
virtual TList * GetList() const
Definition: TDirectory.h:159
void tobuf(char *&buf, Bool_t x)
Definition: Bytes.h:57
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:24
virtual void Delete(Option_t *option="")
Delete an object from the file.
Definition: TKey.cxx:541
TDatime fDatime
Date/Time of insertion in file.
Definition: TKey.h:38
EValues
Note: this is only temporarily a struct and will become a enum class hence the name.
Definition: Compression.h:83
virtual TFile * GetFile() const
Definition: TDirectory.h:157
virtual Int_t WriteFileKeepBuffer(TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1489
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition: TObject.cxx:705
A doubly linked list.
Definition: TList.h:44
Int_t GetCompressionAlgorithm() const
Definition: TFile.h:382
virtual void Delete(Option_t *option="")
Delete this object.
Definition: TObject.cxx:169
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:37
virtual void IncrementPidOffset(UShort_t offset)
Increment fPidOffset by &#39;offset&#39;.
Definition: TKey.cxx:644
Long64_t GetSeekDir() const override
virtual void Keep()
Set the "KEEP" status.
Definition: TKey.cxx:679
virtual void ReadBuffer(char *&buffer)
Decode input buffer.
Definition: TKey.cxx:1208
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:656
A ROOT file is structured in Directories (like a file system).
TFile * GetFile() const
Returns file to which key belong.
Definition: TKey.cxx:579
TClass * GetActualClass(const void *object) const
Return a pointer the the real class of the object.
Definition: TClass.cxx:2546
Bool_t HasDefaultConstructor() const
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:819
UInt_t Get() const
Return raw date/time as encoded by TDatime.
Definition: TDatime.cxx:239
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:443
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:610
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5214
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual Bool_t ReadFile()
Read the key structure from the file.
Definition: TKey.cxx:1263
ROOT::DirAutoAdd_t GetDirectoryAutoAdd() const
Ssiz_t Length() const
Definition: TString.h:405
virtual void MakeFree(Long64_t first, Long64_t last)
Mark unused bytes on the file.
Definition: TFile.cxx:1379
virtual void Append(TObject *obj, Bool_t replace=kFALSE)
Append object to this directory.
Definition: TDirectory.cxx:190
virtual Long64_t GetSeekDir() const
Definition: TDirectory.h:165
short Short_t
Definition: RtypesCore.h:35
virtual void Browse(TBrowser *b)
This method is called by a browser to get the class information.
Definition: TClass.cxx:1940
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition: TROOT.cxx:2845
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
virtual void Reset()
Reset the key as it had not been &#39;filled&#39; yet.
Definition: TKey.cxx:1300
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4753
virtual TObject * ReadObjWithBuffer(char *bufferRead)
To read a TObject* from bufferRead.
Definition: TKey.cxx:874
TString fName
Definition: TNamed.h:32
Long64_t GetFirst() const
Definition: TFree.h:40
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=0) const
Definition: TClass.h:563
TBuffer * fBufferRef
Pointer to the TBuffer object.
Definition: TKey.h:46
virtual void SetParent(const TObject *parent)
Set parent in key buffer.
Definition: TKey.cxx:1292
const Bool_t kFALSE
Definition: RtypesCore.h:88
Long64_t fSeekKey
Location of object on file.
Definition: TKey.h:41
virtual Int_t AppendKey(TKey *)
Definition: TDirectory.h:124
void SetFirst(Long64_t first)
Definition: TFree.h:44
void ReadKeyBuffer(char *&buffer)
Decode input buffer.
Definition: TKey.cxx:1220
virtual void MapObject(const TObject *obj, UInt_t offset=1)=0
Short_t fCycle
Cycle number.
Definition: TKey.h:40
#define ClassImp(name)
Definition: Rtypes.h:365
Describe directory structure in memory.
Definition: TDirectory.h:34
virtual const char * GetTitle() const
Returns title (title can contain 32x32 xpm thumbnail/icon).
Definition: TKey.cxx:1530
unsigned long long ULong64_t
Definition: RtypesCore.h:70
std::atomic< UInt_t > keyAbsNumber
Definition: TKey.cxx:85
virtual Int_t Sizeof() const
Returns size string will occupy on I/O buffer.
Definition: TString.cxx:1334
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:2906
void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout)
TString & gTDirectoryString()
Definition: TKey.cxx:81
Bool_t IsNull() const
Definition: TString.h:402
Int_t fObjlen
Length of uncompressed object in bytes.
Definition: TKey.h:37
Mother of all ROOT objects.
Definition: TObject.h:37
virtual void Create(Int_t nbytes, TFile *f=0)
Create a TKey object of specified size.
Definition: TKey.cxx:461
virtual Long64_t GetEND() const
Definition: TFile.h:218
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5733
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition: TKey.cxx:732
virtual void DeleteBuffer()
Delete key buffer(s).
Definition: TKey.cxx:553
void(* DirAutoAdd_t)(void *, TDirectory *)
Definition: Rtypes.h:115
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:212
void MakeZombie()
Definition: TObject.h:49
TF1 * f1
Definition: legend1.C:11
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
R__EXTERN Int_t gDebug
Definition: Rtypes.h:91
Int_t fNbytes
Number of bytes for the object on file.
Definition: TKey.h:36
virtual Bool_t IsFolder() const
Returns kTRUE in case object contains browsable objects (like containers or lists of other objects)...
Definition: TObject.cxx:473
#define gDirectory
Definition: TDirectory.h:223
void * DynamicCast(const TClass *base, void *obj, Bool_t up=kTRUE)
Cast obj of this class type up to baseclass cl if up is true.
Definition: TClass.cxx:4794
unsigned char UChar_t
Definition: RtypesCore.h:34
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition: TClass.cxx:1862
virtual void FillBuffer(char *&buffer) const
Copy string into I/O buffer.
Definition: TString.cxx:1243
Definition: first.py:1
virtual Int_t Read(const char *name)
Read contents of object with specified name from the current directory.
Definition: TKey.h:50
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:908
Short_t GetCycle() const
Return cycle number associated to this key.
Definition: TKey.cxx:571
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:164
virtual void SetMother(TObject *mother)
Definition: TDirectory.h:194
Int_t Sizeof() const
Definition: TDatime.h:81
const Bool_t kTRUE
Definition: RtypesCore.h:87
Int_t GetCompressionLevel() const
Definition: TFile.h:388
Bool_t IsFolder() const
Check if object referenced by the key is a folder.
Definition: TKey.cxx:658
char name[80]
Definition: TGX11.cxx:109
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
virtual Version_t ReadVersion(UInt_t *start=0, UInt_t *bcnt=0, const TClass *cl=0)=0
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1095
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:37
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4857
const char * Data() const
Definition: TString.h:364