Logo ROOT   6.12/07
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 
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);
333  fBufferRef->SetParent(GetFile());
334  fCycle = fMotherDir->AppendKey(this);
335 
336  Streamer(*fBufferRef); //write key itself
337  fKeylen = fBufferRef->Length();
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
361  fBuffer = fBufferRef->Buffer();
362  Create(fObjlen);
363  fBufferRef->SetBufferOffset(0);
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);
373  fBufferRef->SetBufferOffset(0);
374  Streamer(*fBufferRef); //write key itself again
375  memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
376  delete fBufferRef; fBufferRef = 0;
377  } else {
378  fBuffer = fBufferRef->Buffer();
379  Create(fObjlen);
380  fBufferRef->SetBufferOffset(0);
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 }
417 
418 ////////////////////////////////////////////////////////////////////////////////
419 /// Read object from disk and call its Browse() method.
420 ///
421 /// If object with same name already exist in memory delete it (like
422 /// TDirectoryFile::Get() is doing), except when the key references a
423 /// folder in which case we don't want to re-read the folder object
424 /// since it might contain new objects not yet saved.
425 
427 {
428  if (fMotherDir==0) return;
429 
431 
432  void* obj = fMotherDir->GetList()->FindObject(GetName());
433  if (obj && objcl->IsTObject()) {
434  TObject *tobj = (TObject*) objcl->DynamicCast(TObject::Class(), obj);
435  if (!tobj->IsFolder()) {
436  if (tobj->InheritsFrom(TCollection::Class()))
437  tobj->Delete(); // delete also collection elements
438  delete tobj;
439  obj = 0;
440  }
441  }
442 
443  if (!obj)
444  obj = ReadObj();
445 
446  if (b && obj) {
447  objcl->Browse(obj,b);
448  b->SetRefreshFlag(kTRUE);
449  }
450 }
451 
452 ////////////////////////////////////////////////////////////////////////////////
453 /// Create a TKey object of specified size.
454 ///
455 /// If externFile!=0, key will be allocated in specified file, otherwise file
456 /// of mother directory will be used.
457 
458 void TKey::Create(Int_t nbytes, TFile* externFile)
459 {
461 
462  TFile *f = externFile;
463  if (!f) f = GetFile();
464  if (!f) {
465  Error("Create","Cannot create key without file");
466  return;
467  }
468 
469  Int_t nsize = nbytes + fKeylen;
470  TList *lfree = f->GetListOfFree();
471  TFree *f1 = (TFree*)lfree->First();
472 //*-*-------------------find free segment
473 //*-* =================
474  TFree *bestfree = f1->GetBestFree(lfree,nsize);
475  if (bestfree == 0) {
476  Error("Create","Cannot allocate %d bytes for ID = %s Title = %s",
477  nsize,GetName(),GetTitle());
478  return;
479  }
480  fDatime.Set();
481  fSeekKey = bestfree->GetFirst();
482 //*-*----------------- Case Add at the end of the file
483  if (fSeekKey >= f->GetEND()) {
484  f->SetEND(fSeekKey+nsize);
485  bestfree->SetFirst(fSeekKey+nsize);
486  if (f->GetEND() > bestfree->GetLast()) {
487  bestfree->SetLast(bestfree->GetLast() + 1000000000);
488  }
489  fLeft = -1;
490  if (!fBuffer) fBuffer = new char[nsize];
491  } else {
492  fLeft = Int_t(bestfree->GetLast() - fSeekKey - nsize + 1);
493  }
494 //*-*----------------- Case where new object fills exactly a deleted gap
495  fNbytes = nsize;
496  if (fLeft == 0) {
497  if (!fBuffer) {
498  fBuffer = new char[nsize];
499  }
500  lfree->Remove(bestfree);
501  delete bestfree;
502  }
503 //*-*----------------- Case where new object is placed in a deleted gap larger than itself
504  if (fLeft > 0) { // found a bigger segment
505  if (!fBuffer) {
506  fBuffer = new char[nsize+sizeof(Int_t)];
507  }
508  char *buffer = fBuffer+nsize;
509  Int_t nbytesleft = -fLeft; // set header of remaining record
510  tobuf(buffer, nbytesleft);
511  bestfree->SetFirst(fSeekKey+nsize);
512  }
513 
514  fSeekPdir = externFile ? externFile->GetSeekDir() : fMotherDir->GetSeekDir();
515 }
516 
517 ////////////////////////////////////////////////////////////////////////////////
518 /// TKey default destructor.
519 
521 {
522  // delete [] fBuffer; fBuffer = 0;
523  // delete fBufferRef; fBufferRef = 0;
524 
525  DeleteBuffer();
526 }
527 
528 ////////////////////////////////////////////////////////////////////////////////
529 /// Delete an object from the file.
530 ///
531 /// Note: the key is not deleted. You still have to call "delete key".
532 /// This is different from the behaviour of TObject::Delete()!
533 
534 void TKey::Delete(Option_t *option)
535 {
536  if (option && option[0] == 'v') printf("Deleting key: %s at address %lld, nbytes = %d\n",GetName(),fSeekKey,fNbytes);
538  Long64_t last = fSeekKey + fNbytes -1;
539  if (GetFile()) GetFile()->MakeFree(first, last); // release space used by this key
540  fMotherDir->GetListOfKeys()->Remove(this);
541 }
542 
543 ////////////////////////////////////////////////////////////////////////////////
544 /// Delete key buffer(s).
545 
547 {
548  if (fBufferRef) {
549  delete fBufferRef;
550  fBufferRef = 0;
551  } else {
552  // We only need to delete fBuffer if fBufferRef is zero because
553  // if fBufferRef exists, we delegate ownership of fBuffer to fBufferRef.
554  if (fBuffer) {
555  delete [] fBuffer;
556  }
557  }
558  fBuffer = 0;
559 }
560 
561 ////////////////////////////////////////////////////////////////////////////////
562 /// Return cycle number associated to this key.
563 
565 {
566  return ((fCycle >0) ? fCycle : -fCycle);
567 }
568 
569 ////////////////////////////////////////////////////////////////////////////////
570 /// Returns file to which key belong.
571 
573 {
574  return fMotherDir!=0 ? fMotherDir->GetFile() : gFile;
575 }
576 
577 ////////////////////////////////////////////////////////////////////////////////
578 /// Returns the "KEEP" status.
579 
581 {
582  return ((fCycle >0) ? 0 : 1);
583 }
584 
585 ////////////////////////////////////////////////////////////////////////////////
586 /// Encode key header into output buffer.
587 
588 void TKey::FillBuffer(char *&buffer)
589 {
590  tobuf(buffer, fNbytes);
591  Version_t version = fVersion;
592  tobuf(buffer, version);
593 
594  tobuf(buffer, fObjlen);
595  fDatime.FillBuffer(buffer);
596  tobuf(buffer, fKeylen);
597  tobuf(buffer, fCycle);
598  if (fVersion > 1000) {
599  tobuf(buffer, fSeekKey);
600 
601  // We currently store in the 16 highest bit of fSeekPdir the value of
602  // fPidOffset. This offset is used when a key (or basket) is transfered from one
603  // file to the other. In this case the TRef and TObject might have stored a
604  // pid index (to retrieve TProcessIDs) which refered to their order on the original
605  // file, the fPidOffset is to be added to those values to correctly find the
606  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
607  // and need to be zero for new key/basket.
609  tobuf(buffer, pdir);
610  } else {
611  tobuf(buffer, (Int_t)fSeekKey);
612  tobuf(buffer, (Int_t)fSeekPdir);
613  }
614  if (TestBit(kIsDirectoryFile)) {
615  // We want to record "TDirectory" instead of TDirectoryFile so that the file can be read by ancient version of ROOT.
616  gTDirectoryString().FillBuffer(buffer);
617  } else {
618  fClassName.FillBuffer(buffer);
619  }
620  fName.FillBuffer(buffer);
621  fTitle.FillBuffer(buffer);
622 }
623 
624 ////////////////////////////////////////////////////////////////////////////////
625 /// Increment fPidOffset by 'offset'.
626 ///
627 /// This offset is used when a key (or basket) is transfered from one file to
628 /// the other. In this case the TRef and TObject might have stored a pid
629 /// index (to retrieve TProcessIDs) which refered to their order on the
630 /// original file, the fPidOffset is to be added to those values to correctly
631 /// find the TProcessID. This fPidOffset needs to be increment if the
632 /// key/basket is copied and need to be zero for new key/basket.
633 
635 {
636  fPidOffset += offset;
637  if (fPidOffset) {
638  // We currently store fPidOffset in the 16 highest bit of fSeekPdir, which
639  // need to be store as a 64 bit integer. So we require this key to be
640  // a 'large file' key.
641  if (fVersion<1000) fVersion += 1000;
642  }
643 }
644 
645 ////////////////////////////////////////////////////////////////////////////////
646 /// Check if object referenced by the key is a folder.
647 
649 {
650  Bool_t ret = kFALSE;
651 
652  TClass *classPtr = TClass::GetClass((const char *) fClassName);
653  if (classPtr && classPtr->GetState() > TClass::kEmulated && classPtr->IsTObject()) {
654  TObject *obj = (TObject *) classPtr->DynamicCast(TObject::Class(), classPtr->New(TClass::kDummyNew));
655  if (obj) {
656  ret = obj->IsFolder();
657  delete obj;
658  }
659  }
660 
661  return ret;
662 }
663 
664 ////////////////////////////////////////////////////////////////////////////////
665 /// Set the "KEEP" status.
666 ///
667 /// When the KEEP flag is set to 1 the object cannot be purged.
668 
670 {
671  if (fCycle >0) fCycle = -fCycle;
672 }
673 
674 ////////////////////////////////////////////////////////////////////////////////
675 /// List Key contents.
676 
677 void TKey::ls(Option_t *) const
678 {
680  std::cout <<"KEY: "<<fClassName<<"\t"<<GetName()<<";"<<GetCycle()<<"\t"<<GetTitle()<<std::endl;
681 }
682 
683 ////////////////////////////////////////////////////////////////////////////////
684 /// Print key contents.
685 
686 void TKey::Print(Option_t *) const
687 {
688  printf("TKey Name = %s, Title = %s, Cycle = %d\n",GetName(),GetTitle(),GetCycle());
689 }
690 
691 ////////////////////////////////////////////////////////////////////////////////
692 /// To read a TObject* from the file.
693 ///
694 /// The object associated to this key is read from the file into memory
695 /// Once the key structure is read (via Streamer) the class identifier
696 /// of the object is known.
697 /// Using the class identifier we find the TClass object for this class.
698 /// A TClass object contains a full description (i.e. dictionary) of the
699 /// associated class. In particular the TClass object can create a new
700 /// object of the class type it describes. This new object now calls its
701 /// Streamer function to rebuilt itself.
702 ///
703 /// Use TKey::ReadObjectAny to read any object non-derived from TObject
704 ///
705 /// ### Note
706 /// A C style cast can only be used in the case where the final class
707 /// of this object derives from TObject as a first inheritance, otherwise
708 /// one must use a dynamic_cast.
709 ///
710 /// #### Example1: simplified case
711 /// class MyClass : public TObject, public AnotherClass
712 /// then on return, one get away with using:
713 /// MyClass *obj = (MyClass*)key->ReadObj();
714 ///
715 /// #### Example2: Usual case (recommended unless performance is critical)
716 /// MyClass *obj = dynamic_cast<MyClass*>(key->ReadObj());
717 /// which support also the more complex inheritance like:
718 /// class MyClass : public AnotherClass, public TObject
719 ///
720 /// Of course, dynamic_cast<> can also be used in the example 1.
721 
723 {
725  if (!cl) {
726  Error("ReadObj", "Unknown class %s", fClassName.Data());
727  return 0;
728  }
729  if (!cl->IsTObject()) {
730  // in principle user should call TKey::ReadObjectAny!
731  return (TObject*)ReadObjectAny(0);
732  }
733 
735  if (!fBufferRef) {
736  Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
737  return 0;
738  }
739  if (GetFile()==0) return 0;
742 
743  if (fObjlen > fNbytes-fKeylen) {
744  fBuffer = new char[fNbytes];
745  if( !ReadFile() ) //Read object structure from file
746  {
747  delete fBufferRef;
748  delete [] fBuffer;
749  fBufferRef = 0;
750  fBuffer = 0;
751  return 0;
752  }
753  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
754  } else {
756  if( !ReadFile() ) { //Read object structure from file
757  delete fBufferRef;
758  fBufferRef = 0;
759  fBuffer = 0;
760  return 0;
761  }
762  }
763 
764  // get version of key
766  Version_t kvers = fBufferRef->ReadVersion();
767 
769  TObject *tobj = 0;
770  // Create an instance of this class
771 
772  char *pobj = (char*)cl->New();
773  if (!pobj) {
774  Error("ReadObj", "Cannot create new object of class %s", fClassName.Data());
775  return 0;
776  }
777  Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
778  if (baseOffset==-1) {
779  // cl does not inherit from TObject.
780  // Since this is not possible yet, the only reason we could reach this code
781  // is because something is screw up in the ROOT code.
782  Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
783  fClassName.Data());
784  }
785  tobj = (TObject*)(pobj+baseOffset);
786  if (kvers > 1)
787  fBufferRef->MapObject(pobj,cl); //register obj in map to handle self reference
788 
789  if (fObjlen > fNbytes-fKeylen) {
790  char *objbuf = fBufferRef->Buffer() + fKeylen;
791  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
792  Int_t nin, nout = 0, nbuf;
793  Int_t noutot = 0;
794  while (1) {
795  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
796  if (hc!=0) break;
797  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
798  if (!nout) break;
799  noutot += nout;
800  if (noutot >= fObjlen) break;
801  bufcur += nin;
802  objbuf += nout;
803  }
804  if (nout) {
805  tobj->Streamer(*fBufferRef); //does not work with example 2 above
806  delete [] fBuffer;
807  } else {
808  delete [] fBuffer;
809  // Even-though we have a TObject, if the class is emulated the virtual
810  // table may not be 'right', so let's go via the TClass.
811  cl->Destructor(pobj);
812  pobj = 0;
813  tobj = 0;
814  goto CLEAR;
815  }
816  } else {
817  tobj->Streamer(*fBufferRef);
818  }
819 
820  if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
821 
822  if (cl->InheritsFrom(TDirectoryFile::Class())) {
823  TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
824  dir->SetName(GetName());
825  dir->SetTitle(GetTitle());
826  dir->SetMother(fMotherDir);
827  fMotherDir->Append(dir);
828  }
829 
830  // Append the object to the directory if requested:
831  {
832  ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
833  if (addfunc) {
834  addfunc(pobj, fMotherDir);
835  }
836  }
837 
838 CLEAR:
839  delete fBufferRef;
840  fBufferRef = 0;
841  fBuffer = 0;
842 
843  return tobj;
844 }
845 
846 ////////////////////////////////////////////////////////////////////////////////
847 /// To read a TObject* from bufferRead.
848 ///
849 /// This function is identical to TKey::ReadObj, but it reads directly from
850 /// bufferRead instead of reading from a file.
851 /// The object associated to this key is read from the buffer into memory
852 /// Using the class identifier we find the TClass object for this class.
853 /// A TClass object contains a full description (i.e. dictionary) of the
854 /// associated class. In particular the TClass object can create a new
855 /// object of the class type it describes. This new object now calls its
856 /// Streamer function to rebuilt itself.
857 ///
858 /// ### Note
859 /// This function is called only internally by ROOT classes.
860 /// Although being public it is not supposed to be used outside ROOT.
861 /// If used, you must make sure that the bufferRead is large enough to
862 /// accomodate the object being read.
863 
865 {
866 
868  if (!cl) {
869  Error("ReadObjWithBuffer", "Unknown class %s", fClassName.Data());
870  return 0;
871  }
872  if (!cl->IsTObject()) {
873  // in principle user should call TKey::ReadObjectAny!
874  return (TObject*)ReadObjectAny(0);
875  }
876 
878  if (!fBufferRef) {
879  Error("ReadObjWithBuffer", "Cannot allocate buffer: fObjlen = %d", fObjlen);
880  return 0;
881  }
882  if (GetFile()==0) return 0;
885 
886  if (fObjlen > fNbytes-fKeylen) {
887  fBuffer = bufferRead;
888  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
889  } else {
891  ReadFile(); //Read object structure from file
892  }
893 
894  // get version of key
896  Version_t kvers = fBufferRef->ReadVersion();
897 
899  TObject *tobj = 0;
900  // Create an instance of this class
901 
902  char *pobj = (char*)cl->New();
903  if (!pobj) {
904  Error("ReadObjWithBuffer", "Cannot create new object of class %s", fClassName.Data());
905  return 0;
906  }
907  Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
908  if (baseOffset==-1) {
909  // cl does not inherit from TObject.
910  // Since this is not possible yet, the only reason we could reach this code
911  // is because something is screw up in the ROOT code.
912  Fatal("ReadObjWithBuffer","Incorrect detection of the inheritance from TObject for class %s.\n",
913  fClassName.Data());
914  }
915  tobj = (TObject*)(pobj+baseOffset);
916 
917  if (kvers > 1)
918  fBufferRef->MapObject(pobj,cl); //register obj in map to handle self reference
919 
920  if (fObjlen > fNbytes-fKeylen) {
921  char *objbuf = fBufferRef->Buffer() + fKeylen;
922  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
923  Int_t nin, nout = 0, nbuf;
924  Int_t noutot = 0;
925  while (1) {
926  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
927  if (hc!=0) break;
928  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
929  if (!nout) break;
930  noutot += nout;
931  if (noutot >= fObjlen) break;
932  bufcur += nin;
933  objbuf += nout;
934  }
935  if (nout) {
936  tobj->Streamer(*fBufferRef); //does not work with example 2 above
937  } else {
938  // Even-though we have a TObject, if the class is emulated the virtual
939  // table may not be 'right', so let's go via the TClass.
940  cl->Destructor(pobj);
941  pobj = 0;
942  tobj = 0;
943  goto CLEAR;
944  }
945  } else {
946  tobj->Streamer(*fBufferRef);
947  }
948 
949  if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
950 
951  if (cl->InheritsFrom(TDirectoryFile::Class())) {
952  TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
953  dir->SetName(GetName());
954  dir->SetTitle(GetTitle());
955  dir->SetMother(fMotherDir);
956  fMotherDir->Append(dir);
957  }
958 
959  // Append the object to the directory if requested:
960  {
961  ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
962  if (addfunc) {
963  addfunc(pobj, fMotherDir);
964  }
965  }
966 
967 CLEAR:
968  delete fBufferRef;
969  fBufferRef = 0;
970  fBuffer = 0;
971 
972  return tobj;
973 }
974 
975 ////////////////////////////////////////////////////////////////////////////////
976 /// To read an object (non deriving from TObject) from the file.
977 ///
978 /// If expectedClass is not null, we checked that that actual class of the
979 /// object stored is suitable to be stored in a pointer pointing to an object
980 /// of class 'expectedClass'. We also adjust the value of the returned address
981 /// so that it is suitable to be cast (C-Style)
982 /// a pointer pointing to an object of class 'expectedClass'.
983 ///
984 /// So for example if the class Bottom inherits from Top and the object
985 /// stored is of type Bottom you can safely do:
986 /// ~~~{.cpp}
987 /// auto TopClass = TClass::GetClass("Top");
988 /// auto ptr = (Top*) key->ReadObjectAny( TopClass );
989 /// if (ptr==0) printError("the object stored in the key is not of the expected type\n");
990 /// ~~~
991 /// The object associated to this key is read from the file into memory.
992 /// Once the key structure is read (via Streamer) the class identifier
993 /// of the object is known.
994 /// Using the class identifier we find the TClass object for this class.
995 /// A TClass object contains a full description (i.e. dictionary) of the
996 /// associated class. In particular the TClass object can create a new
997 /// object of the class type it describes. This new object now calls its
998 /// Streamer function to rebuilt itself.
999 
1000 void *TKey::ReadObjectAny(const TClass* expectedClass)
1001 {
1003  if (!fBufferRef) {
1004  Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
1005  return 0;
1006  }
1007  if (GetFile()==0) return 0;
1010 
1011  if (fObjlen > fNbytes-fKeylen) {
1012  fBuffer = new char[fNbytes];
1013  ReadFile(); //Read object structure from file
1014  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
1015  } else {
1016  fBuffer = fBufferRef->Buffer();
1017  ReadFile(); //Read object structure from file
1018  }
1019 
1020  // get version of key
1022  Version_t kvers = fBufferRef->ReadVersion();
1023 
1026  TClass *clOnfile = 0;
1027  if (!cl) {
1028  Error("ReadObjectAny", "Unknown class %s", fClassName.Data());
1029  return 0;
1030  }
1031  Int_t baseOffset = 0;
1032  if (expectedClass) {
1033  // baseOffset will be -1 if cl does not inherit from expectedClass
1034  baseOffset = cl->GetBaseClassOffset(expectedClass);
1035  if (baseOffset == -1) {
1036  // The 2 classes are unrelated, maybe there is a converter between the 2.
1037 
1038  if (!expectedClass->GetSchemaRules() ||
1039  !expectedClass->GetSchemaRules()->HasRuleWithSourceClass(cl->GetName()))
1040  {
1041  // There is no converter
1042  return 0;
1043  }
1044  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 ....
1045  clOnfile = cl;
1046  cl = const_cast<TClass*>(expectedClass);
1047  Info("ReadObjectAny","Using Converter StreamerInfo from %s to %s",clOnfile->GetName(),expectedClass->GetName());
1048  }
1049  if (cl->GetState() > TClass::kEmulated && expectedClass->GetState() <= TClass::kEmulated) {
1050  //we cannot mix a compiled class with an emulated class in the inheritance
1051  Warning("ReadObjectAny",
1052  "Trying to read an emulated class (%s) to store in a compiled pointer (%s)",
1053  cl->GetName(),expectedClass->GetName());
1054  }
1055  }
1056  // Create an instance of this class
1057 
1058  void *pobj = cl->New();
1059  if (!pobj) {
1060  Error("ReadObjectAny", "Cannot create new object of class %s", fClassName.Data());
1061  return 0;
1062  }
1063 
1064  if (kvers > 1)
1065  fBufferRef->MapObject(pobj,cl); //register obj in map to handle self reference
1066 
1067  if (fObjlen > fNbytes-fKeylen) {
1068  char *objbuf = fBufferRef->Buffer() + fKeylen;
1069  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
1070  Int_t nin, nout = 0, nbuf;
1071  Int_t noutot = 0;
1072  while (1) {
1073  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
1074  if (hc!=0) break;
1075  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
1076  if (!nout) break;
1077  noutot += nout;
1078  if (noutot >= fObjlen) break;
1079  bufcur += nin;
1080  objbuf += nout;
1081  }
1082  if (nout) {
1083  cl->Streamer((void*)pobj, *fBufferRef, clOnfile); //read object
1084  delete [] fBuffer;
1085  } else {
1086  delete [] fBuffer;
1087  cl->Destructor(pobj);
1088  pobj = 0;
1089  goto CLEAR;
1090  }
1091  } else {
1092  cl->Streamer((void*)pobj, *fBufferRef, clOnfile); //read object
1093  }
1094 
1095  if (cl->IsTObject()) {
1096  auto tobjBaseOffset = cl->GetBaseClassOffset(TObject::Class());
1097  if (tobjBaseOffset == -1) {
1098  Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
1099  fClassName.Data());
1100  }
1101  TObject *tobj = (TObject*)( ((char*)pobj) + tobjBaseOffset);
1102 
1103  // See similar adjustments in ReadObj
1104  if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
1105 
1106  if (cl->InheritsFrom(TDirectoryFile::Class())) {
1107  TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
1108  dir->SetName(GetName());
1109  dir->SetTitle(GetTitle());
1110  dir->SetMother(fMotherDir);
1111  fMotherDir->Append(dir);
1112  }
1113  }
1114 
1115  {
1116  // Append the object to the directory if requested:
1117  ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
1118  if (addfunc) {
1119  addfunc(pobj, fMotherDir);
1120  }
1121  }
1122 
1123  CLEAR:
1124  delete fBufferRef;
1125  fBufferRef = 0;
1126  fBuffer = 0;
1127 
1128  return ( ((char*)pobj) + baseOffset );
1129 }
1130 
1131 ////////////////////////////////////////////////////////////////////////////////
1132 /// To read an object from the file.
1133 ///
1134 /// The object associated to this key is read from the file into memory.
1135 /// Before invoking this function, obj has been created via the
1136 /// default constructor.
1137 
1139 {
1140  if (!obj || (GetFile()==0)) return 0;
1141 
1145 
1146  if (fVersion > 1)
1147  fBufferRef->MapObject(obj); //register obj in map to handle self reference
1148 
1149  if (fObjlen > fNbytes-fKeylen) {
1150  fBuffer = new char[fNbytes];
1151  ReadFile(); //Read object structure from file
1152  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
1153  } else {
1154  fBuffer = fBufferRef->Buffer();
1155  ReadFile(); //Read object structure from file
1156  }
1158  if (fObjlen > fNbytes-fKeylen) {
1159  char *objbuf = fBufferRef->Buffer() + fKeylen;
1160  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
1161  Int_t nin, nout = 0, nbuf;
1162  Int_t noutot = 0;
1163  while (1) {
1164  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
1165  if (hc!=0) break;
1166  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
1167  if (!nout) break;
1168  noutot += nout;
1169  if (noutot >= fObjlen) break;
1170  bufcur += nin;
1171  objbuf += nout;
1172  }
1173  if (nout) obj->Streamer(*fBufferRef);
1174  delete [] fBuffer;
1175  } else {
1176  obj->Streamer(*fBufferRef);
1177  }
1178 
1179  // Append the object to the directory if requested:
1180  {
1181  ROOT::DirAutoAdd_t addfunc = obj->IsA()->GetDirectoryAutoAdd();
1182  if (addfunc) {
1183  addfunc(obj, fMotherDir);
1184  }
1185  }
1186 
1187  delete fBufferRef;
1188  fBufferRef = 0;
1189  fBuffer = 0;
1190  return fNbytes;
1191 }
1192 
1193 ////////////////////////////////////////////////////////////////////////////////
1194 /// Decode input buffer.
1195 ///
1196 /// In some situation will add key to gDirectory.
1197 
1198 void TKey::ReadBuffer(char *&buffer)
1199 {
1200  ReadKeyBuffer(buffer);
1201 
1202  if (!gROOT->ReadingObject() && gDirectory) {
1203  if (fSeekPdir != gDirectory->GetSeekDir()) gDirectory->AppendKey(this);
1204  }
1205 }
1206 
1207 ////////////////////////////////////////////////////////////////////////////////
1208 /// Decode input buffer.
1209 
1210 void TKey::ReadKeyBuffer(char *&buffer)
1211 {
1212  frombuf(buffer, &fNbytes);
1213  Version_t version;
1214  frombuf(buffer,&version);
1215  fVersion = (Int_t)version;
1216  frombuf(buffer, &fObjlen);
1217  fDatime.ReadBuffer(buffer);
1218  frombuf(buffer, &fKeylen);
1219  frombuf(buffer, &fCycle);
1220  if (fVersion > 1000) {
1221  frombuf(buffer, &fSeekKey);
1222 
1223  // We currently store in the 16 highest bit of fSeekPdir the value of
1224  // fPidOffset. This offset is used when a key (or basket) is transfered from one
1225  // file to the other. In this case the TRef and TObject might have stored a
1226  // pid index (to retrieve TProcessIDs) which refered to their order on the original
1227  // file, the fPidOffset is to be added to those values to correctly find the
1228  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1229  // and need to be zero for new key/basket.
1230  Long64_t pdir;
1231  frombuf(buffer, &pdir);
1232  fPidOffset = pdir >> kPidOffsetShift;
1233  fSeekPdir = pdir & kPidOffsetMask;
1234  } else {
1235  UInt_t seekkey,seekdir;
1236  frombuf(buffer, &seekkey); fSeekKey = (Long64_t)seekkey;
1237  frombuf(buffer, &seekdir); fSeekPdir= (Long64_t)seekdir;
1238  }
1239  fClassName.ReadBuffer(buffer);
1240  //the following test required for forward and backward compatibility
1241  if (fClassName == "TDirectory") {
1242  fClassName = "TDirectoryFile";
1244  }
1245 
1246  fName.ReadBuffer(buffer);
1247  fTitle.ReadBuffer(buffer);
1248 }
1249 
1250 ////////////////////////////////////////////////////////////////////////////////
1251 /// Read the key structure from the file
1252 
1254 {
1255  TFile* f = GetFile();
1256  if (f==0) return kFALSE;
1257 
1258  Int_t nsize = fNbytes;
1259  f->Seek(fSeekKey);
1260 #if 0
1261  for (Int_t i = 0; i < nsize; i += kMAXFILEBUFFER) {
1262  int nb = kMAXFILEBUFFER;
1263  if (i+nb > nsize) nb = nsize - i;
1264  f->ReadBuffer(fBuffer+i,nb);
1265  }
1266 #else
1267  if( f->ReadBuffer(fBuffer,nsize) )
1268  {
1269  Error("ReadFile", "Failed to read data.");
1270  return kFALSE;
1271  }
1272 #endif
1273  if (gDebug) {
1274  std::cout << "TKey Reading "<<nsize<< " bytes at address "<<fSeekKey<<std::endl;
1275  }
1276  return kTRUE;
1277 }
1278 
1279 ////////////////////////////////////////////////////////////////////////////////
1280 /// Set parent in key buffer.
1281 
1282 void TKey::SetParent(const TObject *parent)
1283 {
1284  if (fBufferRef) fBufferRef->SetParent((TObject*)parent);
1285 }
1286 
1287 ////////////////////////////////////////////////////////////////////////////////
1288 /// Reset the key as it had not been 'filled' yet.
1289 
1291 {
1292  fPidOffset = 0;
1293  fNbytes = 0;
1294  fBuffer = 0;
1295  fObjlen = 0;
1296  fCycle = 0;
1297  fSeekPdir = 0;
1298  fSeekKey = 0;
1299  fLeft = 0;
1300  fDatime = (UInt_t)0;
1301 
1302  // fBufferRef and fKeylen intentionally not reset/changed
1303 
1305 }
1306 
1307 ////////////////////////////////////////////////////////////////////////////////
1308 /// Return the size in bytes of the key header structure.
1309 ///
1310 /// An explaination about the nbytes (Int_t nbytes) variable used in the
1311 /// function. The size of fSeekKey and fSeekPdir is 8 instead of 4 if version is
1312 /// greater than 1000.
1313 /// | Component | Sizeof |
1314 /// |-------------------|--------|
1315 /// | fNbytes | 4 |
1316 /// | sizeof(Version_t) | 2 |
1317 /// | fObjlen | 4 |
1318 /// | fKeylen | 2 |
1319 /// | fCycle | 2 |
1320 /// | fSeekKey | 4 or 8 |
1321 /// | fSeekPdir | 4 or 8 |
1322 /// | **TOTAL** | 22 |
1323 
1325 {
1326  Int_t nbytes = 22; if (fVersion > 1000) nbytes += 8;
1327  nbytes += fDatime.Sizeof();
1328  if (TestBit(kIsDirectoryFile)) {
1329  nbytes += 11; // strlen("TDirectory")+1
1330  } else {
1331  nbytes += fClassName.Sizeof();
1332  }
1333  nbytes += fName.Sizeof();
1334  nbytes += fTitle.Sizeof();
1335  return nbytes;
1336 }
1337 
1338 ////////////////////////////////////////////////////////////////////////////////
1339 /// Stream a class object.
1340 
1341 void TKey::Streamer(TBuffer &b)
1342 {
1343  Version_t version;
1344  if (b.IsReading()) {
1345  b >> fNbytes;
1346  b >> version; fVersion = (Int_t)version;
1347  b >> fObjlen;
1348  fDatime.Streamer(b);
1349  b >> fKeylen;
1350  b >> fCycle;
1351  if (fVersion > 1000) {
1352  b >> fSeekKey;
1353 
1354  // We currently store in the 16 highest bit of fSeekPdir the value of
1355  // fPidOffset. This offset is used when a key (or basket) is transfered from one
1356  // file to the other. In this case the TRef and TObject might have stored a
1357  // pid index (to retrieve TProcessIDs) which refered to their order on the original
1358  // file, the fPidOffset is to be added to those values to correctly find the
1359  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1360  // and need to be zero for new key/basket.
1361  Long64_t pdir;
1362  b >> pdir;
1363  fPidOffset = pdir >> kPidOffsetShift;
1364  fSeekPdir = pdir & kPidOffsetMask;
1365  } else {
1366  UInt_t seekkey, seekdir;
1367  b >> seekkey; fSeekKey = (Long64_t)seekkey;
1368  b >> seekdir; fSeekPdir= (Long64_t)seekdir;
1369  }
1370  fClassName.Streamer(b);
1371  //the following test required for forward and backward compatibility
1372  if (fClassName == "TDirectory") {
1373  fClassName = "TDirectoryFile";
1375  }
1376  fName.Streamer(b);
1377  fTitle.Streamer(b);
1378  if (fKeylen < 0) {
1379  Error("Streamer","The value of fKeylen is incorrect (%d) ; trying to recover by setting it to zero",fKeylen);
1380  MakeZombie();
1381  fKeylen = 0;
1382  }
1383  if (fObjlen < 0) {
1384  Error("Streamer","The value of fObjlen is incorrect (%d) ; trying to recover by setting it to zero",fObjlen);
1385  MakeZombie();
1386  fObjlen = 0;
1387  }
1388  if (fNbytes < 0) {
1389  Error("Streamer","The value of fNbytes is incorrect (%d) ; trying to recover by setting it to zero",fNbytes);
1390  MakeZombie();
1391  fNbytes = 0;
1392  }
1393 
1394  } else {
1395  b << fNbytes;
1396  version = (Version_t)fVersion;
1397  b << version;
1398  b << fObjlen;
1399  if (fDatime.Get() == 0) fDatime.Set();
1400  fDatime.Streamer(b);
1401  b << fKeylen;
1402  b << fCycle;
1403  if (fVersion > 1000) {
1404  b << fSeekKey;
1405 
1406  // We currently store in the 16 highest bit of fSeekPdir the value of
1407  // fPidOffset. This offset is used when a key (or basket) is transfered from one
1408  // file to the other. In this case the TRef and TObject might have stored a
1409  // pid index (to retrieve TProcessIDs) which refered to their order on the original
1410  // file, the fPidOffset is to be added to those values to correctly find the
1411  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1412  // and need to be zero for new key/basket.
1414  b << pdir;
1415  } else {
1416  b << (Int_t)fSeekKey;
1417  b << (Int_t)fSeekPdir;
1418  }
1419  if (TestBit(kIsDirectoryFile)) {
1420  // We want to record "TDirectory" instead of TDirectoryFile so that the file can be read by ancient version of ROOT.
1421  gTDirectoryString().Streamer(b);
1422  } else {
1423  fClassName.Streamer(b);
1424  }
1425  fName.Streamer(b);
1426  fTitle.Streamer(b);
1427  }
1428 }
1429 
1430 ////////////////////////////////////////////////////////////////////////////////
1431 /// Write the encoded object supported by this key.
1432 /// The function returns the number of bytes committed to the file.
1433 /// If a write error occurs, the number of bytes returned is -1.
1434 
1436 {
1437  if (!f) f = GetFile();
1438  if (!f) return -1;
1439 
1440  Int_t nsize = fNbytes;
1441  char *buffer = fBuffer;
1442  if (cycle) {
1443  fCycle = cycle;
1444  FillBuffer(buffer);
1445  buffer = fBuffer;
1446  }
1447 
1448  if (fLeft > 0) nsize += sizeof(Int_t);
1449  f->Seek(fSeekKey);
1450 #if 0
1451  for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
1452  Int_t nb = kMAXFILEBUFFER;
1453  if (i+nb > nsize) nb = nsize - i;
1454  f->WriteBuffer(buffer,nb);
1455  buffer += nb;
1456  }
1457 #else
1458  Bool_t result = f->WriteBuffer(buffer,nsize);
1459 #endif
1460  //f->Flush(); Flushing takes too much time.
1461  // Let user flush the file when they want.
1462  if (gDebug) {
1463  std::cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
1464  <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<std::endl;
1465  }
1466 
1467  DeleteBuffer();
1468  return result==kTRUE ? -1 : nsize;
1469 }
1470 
1471 ////////////////////////////////////////////////////////////////////////////////
1472 /// Write the encoded object supported by this key.
1473 /// The function returns the number of bytes committed to the file.
1474 /// If a write error occurs, the number of bytes returned is -1.
1475 
1477 {
1478  if (!f) f = GetFile();
1479  if (!f) return -1;
1480 
1481  Int_t nsize = fNbytes;
1482  char *buffer = fBuffer;
1483 
1484  if (fLeft > 0) nsize += sizeof(Int_t);
1485  f->Seek(fSeekKey);
1486 #if 0
1487  for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
1488  Int_t nb = kMAXFILEBUFFER;
1489  if (i+nb > nsize) nb = nsize - i;
1490  f->WriteBuffer(buffer,nb);
1491  buffer += nb;
1492  }
1493 #else
1494  Bool_t result = f->WriteBuffer(buffer,nsize);
1495 #endif
1496  //f->Flush(); Flushing takes too much time.
1497  // Let user flush the file when they want.
1498  if (gDebug) {
1499  std::cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
1500  <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<std::endl;
1501  }
1502 
1503  return result==kTRUE ? -1 : nsize;
1504 }
1505 
1506 ////////////////////////////////////////////////////////////////////////////////
1507 /// Title can keep 32x32 xpm thumbnail/icon of the parent object.
1508 
1509 const char *TKey::GetIconName() const
1510 {
1511  return (!fTitle.IsNull() && fTitle.BeginsWith("/* ") ? fTitle.Data() : 0);
1512 }
1513 
1514 ////////////////////////////////////////////////////////////////////////////////
1515 /// Returns title (title can contain 32x32 xpm thumbnail/icon).
1516 
1517 const char *TKey::GetTitle() const
1518 {
1519  if (!fTitle.IsNull() && fTitle.BeginsWith("/* ")) { // title contains xpm thumbnail
1520  static TString ret;
1521  int start = fTitle.Index("/*") + 3;
1522  int stop = fTitle.Index("*/") - 1;
1523  ret = fTitle(start, stop - start);
1524  return ret.Data();
1525  }
1526  return fTitle.Data();
1527 }
Int_t fVersion
Key version identifier.
Definition: TKey.h:34
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:90
Int_t fLeft
Number of bytes left in current segment.
Definition: TKey.h:43
Bool_t IsReading() const
Definition: TBuffer.h:83
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:1509
virtual TList * GetListOfKeys() const
Definition: TDirectory.h:150
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:47
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:46
virtual void SetEND(Long64_t last)
Definition: TFile.h:258
unsigned short UShort_t
Definition: RtypesCore.h:36
virtual const char * GetClassName() const
Definition: TKey.h:71
virtual void Seek(Long64_t offset, ERelativeTo pos=kBeg)
Seek to a specific position in the file. Pos it either kBeg, kCur or kEnd.
Definition: TFile.cxx:2150
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:46
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition: TFile.cxx:1647
virtual void * ReadObjectAny(const TClass *expectedClass)
To read an object (non deriving from TObject) from the file.
Definition: TKey.cxx:1000
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
TKey()
TKey default constructor.
Definition: TKey.cxx:92
#define R__ASSERT(e)
Definition: TError.h:96
#define gROOT
Definition: TROOT.h:402
virtual void Browse(TBrowser *b)
Read object from disk and call its Browse() method.
Definition: TKey.cxx:426
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:585
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
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:125
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:249
virtual void UseCurrentStyle()
Set current style settings in this object This function is called when either TCanvas::UseCurrentStyl...
Definition: TObject.cxx:715
const Int_t kTitleMax
Definition: TKey.cxx:69
char * fBuffer
Object buffer.
Definition: TKey.h:44
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:588
TDirectory * fMotherDir
!pointer to mother directory
Definition: TKey.h:47
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:1324
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
virtual TObject * FindObject(const char *name) const
Delete a TObjLink object.
Definition: TList.cxx:574
Int_t Length() const
Definition: TBuffer.h:96
virtual void ls(Option_t *option="") const
List Key contents.
Definition: TKey.cxx:677
#define gFile
Definition: TFile.h:322
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2710
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:41
virtual void ReadBuffer(char *&buffer)
Read string from I/O buffer.
Definition: TString.cxx:1238
virtual void Print(Option_t *option="") const
Print key contents.
Definition: TKey.cxx:686
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:93
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 Int_t WriteFile(Int_t cycle=1, TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1435
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:38
TString fClassName
Object Class name.
Definition: TKey.h:42
virtual ~TKey()
TKey default destructor.
Definition: TKey.cxx:520
virtual void SetPidOffset(UShort_t offset)=0
virtual TList * GetList() const
Definition: TDirectory.h:149
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:534
TDatime fDatime
Date/Time of insertion in file.
Definition: TKey.h:37
virtual TFile * GetFile() const
Definition: TDirectory.h:147
virtual Int_t WriteFileKeepBuffer(TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1476
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition: TObject.cxx:705
ECompressionAlgorithm
The global settings depend on a global variable named R__ZipMode which can be modified by a global fu...
Definition: Compression.h:34
A doubly linked list.
Definition: TList.h:44
Int_t GetCompressionAlgorithm() const
Definition: TFile.h:366
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:634
virtual void Keep()
Set the "KEEP" status.
Definition: TKey.cxx:669
virtual void ReadBuffer(char *&buffer)
Decode input buffer.
Definition: TKey.cxx:1198
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:655
A ROOT file is structured in Directories (like a file system).
TFile * GetFile() const
Returns file to which key belong.
Definition: TKey.cxx:572
TClass * GetActualClass(const void *object) const
Return a pointer the the real class of the object.
Definition: TClass.cxx:2527
Bool_t HasDefaultConstructor() const
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:818
UInt_t Get() const
Return raw date/time as encoded by TDatime.
Definition: TDatime.cxx:239
virtual Bool_t WriteBuffer(const char *buf, Int_t len)
Write a buffer to the file.
Definition: TFile.cxx:2353
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:443
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:561
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5149
void SetRefreshFlag(Bool_t flag)
Definition: TBrowser.h:97
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual Bool_t ReadFile()
Read the key structure from the file.
Definition: TKey.cxx:1253
ROOT::DirAutoAdd_t GetDirectoryAutoAdd() const
Ssiz_t Length() const
Definition: TString.h:386
virtual void MakeFree(Long64_t first, Long64_t last)
Mark unused bytes on the file.
Definition: TFile.cxx:1410
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:155
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:1921
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition: TROOT.cxx:2746
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
virtual void Reset()
Reset the key as it had not been &#39;filled&#39; yet.
Definition: TKey.cxx:1290
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4688
virtual TObject * ReadObjWithBuffer(char *bufferRead)
To read a TObject* from bufferRead.
Definition: TKey.cxx:864
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:561
TBuffer * fBufferRef
Pointer to the TBuffer object.
Definition: TKey.h:45
virtual void SetParent(const TObject *parent)
Set parent in key buffer.
Definition: TKey.cxx:1282
const Bool_t kFALSE
Definition: RtypesCore.h:88
Long64_t fSeekKey
Location of object on file.
Definition: TKey.h:40
virtual Int_t AppendKey(TKey *)
Definition: TDirectory.h:119
void SetFirst(Long64_t first)
Definition: TFree.h:44
void ReadKeyBuffer(char *&buffer)
Decode input buffer.
Definition: TKey.cxx:1210
virtual void MapObject(const TObject *obj, UInt_t offset=1)=0
virtual void SetName(const char *newname)
Set the name for directory If the directory name is changed after the directory was written once...
Short_t fCycle
Cycle number.
Definition: TKey.h:39
#define ClassImp(name)
Definition: Rtypes.h:359
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:1517
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:1308
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2887
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:383
Int_t fObjlen
Length of uncompressed object in bytes.
Definition: TKey.h:36
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:458
virtual Long64_t GetEND() const
Definition: TFile.h:202
TFree * GetBestFree(TList *lfree, Int_t nbytes)
Return the best free segment where to store nbytes.
Definition: TFree.cxx:127
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5668
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition: TKey.cxx:722
virtual void DeleteBuffer()
Delete key buffer(s).
Definition: TKey.cxx:546
void(* DirAutoAdd_t)(void *, TDirectory *)
Definition: Rtypes.h:110
TList * GetListOfFree() const
Definition: TFile.h:208
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
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:86
Int_t fNbytes
Number of bytes for the object on file.
Definition: TKey.h:35
virtual Bool_t IsFolder() const
Returns kTRUE in case object contains browsable objects (like containers or lists of other objects)...
Definition: TObject.cxx:473
#define gDirectory
Definition: TDirectory.h:213
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:4729
virtual Long64_t GetSeekDir() const
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:1843
virtual void FillBuffer(char *&buffer) const
Copy string into I/O buffer.
Definition: TString.cxx:1217
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:49
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:564
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:164
virtual void SetMother(TObject *mother)
Definition: TDirectory.h:184
Int_t Sizeof() const
Definition: TDatime.h:81
const Bool_t kTRUE
Definition: RtypesCore.h:87
Int_t GetCompressionLevel() const
Definition: TFile.h:372
Bool_t IsFolder() const
Check if object referenced by the key is a folder.
Definition: TKey.cxx:648
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:1069
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4792
const char * Data() const
Definition: TString.h:345