Logo ROOT   6.08/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 
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 
98  keyAbsNumber++; SetUniqueID(keyAbsNumber);
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;
256  Int_t cxAlgorithm = GetFile() ? GetFile()->GetCompressionAlgorithm() : 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;
347  Int_t cxAlgorithm = GetFile() ? GetFile()->GetCompressionAlgorithm() : 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*)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 /// This Hash function should redefine the default from TNamed.
626 
628 {
629  return TNamed::Hash();
630 }
631 
632 ////////////////////////////////////////////////////////////////////////////////
633 /// Increment fPidOffset by 'offset'.
634 ///
635 /// This offset is used when a key (or basket) is transfered from one file to
636 /// the other. In this case the TRef and TObject might have stored a pid
637 /// index (to retrieve TProcessIDs) which refered to their order on the
638 /// original file, the fPidOffset is to be added to those values to correctly
639 /// find the TProcessID. This fPidOffset needs to be increment if the
640 /// key/basket is copied and need to be zero for new key/basket.
641 
643 {
644  fPidOffset += offset;
645  if (fPidOffset) {
646  // We currently store fPidOffset in the 16 highest bit of fSeekPdir, which
647  // need to be store as a 64 bit integer. So we require this key to be
648  // a 'large file' key.
649  if (fVersion<1000) fVersion += 1000;
650  }
651 }
652 
653 ////////////////////////////////////////////////////////////////////////////////
654 /// Check if object referenced by the key is a folder.
655 
657 {
658  Bool_t ret = kFALSE;
659 
660  TClass *classPtr = TClass::GetClass((const char *) fClassName);
661  if (classPtr && classPtr->GetState() > TClass::kEmulated && classPtr->IsTObject()) {
662  TObject *obj = (TObject *) classPtr->New(TClass::kDummyNew);
663  if (obj) {
664  ret = obj->IsFolder();
665  delete obj;
666  }
667  }
668 
669  return ret;
670 }
671 
672 ////////////////////////////////////////////////////////////////////////////////
673 /// Set the "KEEP" status.
674 ///
675 /// When the KEEP flag is set to 1 the object cannot be purged.
676 
678 {
679  if (fCycle >0) fCycle = -fCycle;
680 }
681 
682 ////////////////////////////////////////////////////////////////////////////////
683 /// List Key contents.
684 
685 void TKey::ls(Option_t *) const
686 {
688  std::cout <<"KEY: "<<fClassName<<"\t"<<GetName()<<";"<<GetCycle()<<"\t"<<GetTitle()<<std::endl;
689 }
690 
691 ////////////////////////////////////////////////////////////////////////////////
692 /// Print key contents.
693 
694 void TKey::Print(Option_t *) const
695 {
696  printf("TKey Name = %s, Title = %s, Cycle = %d\n",GetName(),GetTitle(),GetCycle());
697 }
698 
699 ////////////////////////////////////////////////////////////////////////////////
700 /// To read a TObject* from the file.
701 ///
702 /// The object associated to this key is read from the file into memory
703 /// Once the key structure is read (via Streamer) the class identifier
704 /// of the object is known.
705 /// Using the class identifier we find the TClass object for this class.
706 /// A TClass object contains a full description (i.e. dictionary) of the
707 /// associated class. In particular the TClass object can create a new
708 /// object of the class type it describes. This new object now calls its
709 /// Streamer function to rebuilt itself.
710 ///
711 /// Use TKey::ReadObjectAny to read any object non-derived from TObject
712 ///
713 /// ### Note
714 /// A C style cast can only be used in the case where the final class
715 /// of this object derives from TObject as a first inheritance, otherwise
716 /// one must use a dynamic_cast.
717 ///
718 /// #### Example1: simplified case
719 /// class MyClass : public TObject, public AnotherClass
720 /// then on return, one get away with using:
721 /// MyClass *obj = (MyClass*)key->ReadObj();
722 ///
723 /// #### Example2: Usual case (recommended unless performance is critical)
724 /// MyClass *obj = dynamic_cast<MyClass*>(key->ReadObj());
725 /// which support also the more complex inheritance like:
726 /// class MyClass : public AnotherClass, public TObject
727 ///
728 /// Of course, dynamic_cast<> can also be used in the example 1.
729 
731 {
733  if (!cl) {
734  Error("ReadObj", "Unknown class %s", fClassName.Data());
735  return 0;
736  }
737  if (!cl->IsTObject()) {
738  // in principle user should call TKey::ReadObjectAny!
739  return (TObject*)ReadObjectAny(0);
740  }
741 
743  if (!fBufferRef) {
744  Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
745  return 0;
746  }
747  if (GetFile()==0) return 0;
750 
751  if (fObjlen > fNbytes-fKeylen) {
752  fBuffer = new char[fNbytes];
753  if( !ReadFile() ) //Read object structure from file
754  {
755  delete fBufferRef;
756  delete [] fBuffer;
757  fBufferRef = 0;
758  fBuffer = 0;
759  return 0;
760  }
761  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
762  } else {
764  if( !ReadFile() ) { //Read object structure from file
765  delete fBufferRef;
766  fBufferRef = 0;
767  fBuffer = 0;
768  return 0;
769  }
770  }
771 
772  // get version of key
774  Version_t kvers = fBufferRef->ReadVersion();
775 
777  TObject *tobj = 0;
778  // Create an instance of this class
779 
780  char *pobj = (char*)cl->New();
781  if (!pobj) {
782  Error("ReadObj", "Cannot create new object of class %s", fClassName.Data());
783  return 0;
784  }
785  Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
786  if (baseOffset==-1) {
787  // cl does not inherit from TObject.
788  // Since this is not possible yet, the only reason we could reach this code
789  // is because something is screw up in the ROOT code.
790  Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
791  fClassName.Data());
792  }
793  tobj = (TObject*)(pobj+baseOffset);
794  if (kvers > 1)
795  fBufferRef->MapObject(pobj,cl); //register obj in map to handle self reference
796 
797  if (fObjlen > fNbytes-fKeylen) {
798  char *objbuf = fBufferRef->Buffer() + fKeylen;
799  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
800  Int_t nin, nout = 0, nbuf;
801  Int_t noutot = 0;
802  while (1) {
803  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
804  if (hc!=0) break;
805  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
806  if (!nout) break;
807  noutot += nout;
808  if (noutot >= fObjlen) break;
809  bufcur += nin;
810  objbuf += nout;
811  }
812  if (nout) {
813  tobj->Streamer(*fBufferRef); //does not work with example 2 above
814  delete [] fBuffer;
815  } else {
816  delete [] fBuffer;
817  // Even-though we have a TObject, if the class is emulated the virtual
818  // table may not be 'right', so let's go via the TClass.
819  cl->Destructor(pobj);
820  pobj = 0;
821  tobj = 0;
822  goto CLEAR;
823  }
824  } else {
825  tobj->Streamer(*fBufferRef);
826  }
827 
828  if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
829 
830  if (cl->InheritsFrom(TDirectoryFile::Class())) {
831  TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
832  dir->SetName(GetName());
833  dir->SetTitle(GetTitle());
834  dir->SetMother(fMotherDir);
835  fMotherDir->Append(dir);
836  }
837 
838  // Append the object to the directory if requested:
839  {
840  ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
841  if (addfunc) {
842  addfunc(pobj, fMotherDir);
843  }
844  }
845 
846 CLEAR:
847  delete fBufferRef;
848  fBufferRef = 0;
849  fBuffer = 0;
850 
851  return tobj;
852 }
853 
854 ////////////////////////////////////////////////////////////////////////////////
855 /// To read a TObject* from bufferRead.
856 ///
857 /// This function is identical to TKey::ReadObj, but it reads directly from
858 /// bufferRead instead of reading from a file.
859 /// The object associated to this key is read from the buffer into memory
860 /// Using the class identifier we find the TClass object for this class.
861 /// A TClass object contains a full description (i.e. dictionary) of the
862 /// associated class. In particular the TClass object can create a new
863 /// object of the class type it describes. This new object now calls its
864 /// Streamer function to rebuilt itself.
865 ///
866 /// ### Note
867 /// This function is called only internally by ROOT classes.
868 /// Although being public it is not supposed to be used outside ROOT.
869 /// If used, you must make sure that the bufferRead is large enough to
870 /// accomodate the object being read.
871 
873 {
874 
876  if (!cl) {
877  Error("ReadObjWithBuffer", "Unknown class %s", fClassName.Data());
878  return 0;
879  }
880  if (!cl->IsTObject()) {
881  // in principle user should call TKey::ReadObjectAny!
882  return (TObject*)ReadObjectAny(0);
883  }
884 
886  if (!fBufferRef) {
887  Error("ReadObjWithBuffer", "Cannot allocate buffer: fObjlen = %d", fObjlen);
888  return 0;
889  }
890  if (GetFile()==0) return 0;
893 
894  if (fObjlen > fNbytes-fKeylen) {
895  fBuffer = bufferRead;
896  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
897  } else {
899  ReadFile(); //Read object structure from file
900  }
901 
902  // get version of key
904  Version_t kvers = fBufferRef->ReadVersion();
905 
907  TObject *tobj = 0;
908  // Create an instance of this class
909 
910  char *pobj = (char*)cl->New();
911  if (!pobj) {
912  Error("ReadObjWithBuffer", "Cannot create new object of class %s", fClassName.Data());
913  return 0;
914  }
915  Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
916  if (baseOffset==-1) {
917  // cl does not inherit from TObject.
918  // Since this is not possible yet, the only reason we could reach this code
919  // is because something is screw up in the ROOT code.
920  Fatal("ReadObjWithBuffer","Incorrect detection of the inheritance from TObject for class %s.\n",
921  fClassName.Data());
922  }
923  tobj = (TObject*)(pobj+baseOffset);
924 
925  if (kvers > 1)
926  fBufferRef->MapObject(pobj,cl); //register obj in map to handle self reference
927 
928  if (fObjlen > fNbytes-fKeylen) {
929  char *objbuf = fBufferRef->Buffer() + fKeylen;
930  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
931  Int_t nin, nout = 0, nbuf;
932  Int_t noutot = 0;
933  while (1) {
934  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
935  if (hc!=0) break;
936  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
937  if (!nout) break;
938  noutot += nout;
939  if (noutot >= fObjlen) break;
940  bufcur += nin;
941  objbuf += nout;
942  }
943  if (nout) {
944  tobj->Streamer(*fBufferRef); //does not work with example 2 above
945  } else {
946  // Even-though we have a TObject, if the class is emulated the virtual
947  // table may not be 'right', so let's go via the TClass.
948  cl->Destructor(pobj);
949  pobj = 0;
950  tobj = 0;
951  goto CLEAR;
952  }
953  } else {
954  tobj->Streamer(*fBufferRef);
955  }
956 
957  if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
958 
959  if (cl->InheritsFrom(TDirectoryFile::Class())) {
960  TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
961  dir->SetName(GetName());
962  dir->SetTitle(GetTitle());
963  dir->SetMother(fMotherDir);
964  fMotherDir->Append(dir);
965  }
966 
967  // Append the object to the directory if requested:
968  {
969  ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
970  if (addfunc) {
971  addfunc(pobj, fMotherDir);
972  }
973  }
974 
975 CLEAR:
976  delete fBufferRef;
977  fBufferRef = 0;
978  fBuffer = 0;
979 
980  return tobj;
981 }
982 
983 ////////////////////////////////////////////////////////////////////////////////
984 /// To read an object (non deriving from TObject) from the file.
985 ///
986 /// If expectedClass is not null, we checked that that actual class of the
987 /// object stored is suitable to be stored in a pointer pointing to an object
988 /// of class 'expectedClass'. We also adjust the value of the returned address
989 /// so that it is suitable to be cast (C-Style)
990 /// a pointer pointing to an object of class 'expectedClass'.
991 ///
992 /// So for example if the class Bottom inherits from Top and the object
993 /// stored is of type Bottom you can safely do:
994 /// ~~~{.cpp}
995 /// auto TopClass = TClass::GetClass("Top");
996 /// auto ptr = (Top*) key->ReadObjectAny( TopClass );
997 /// if (ptr==0) printError("the object stored in the key is not of the expected type\n");
998 /// ~~~
999 /// The object associated to this key is read from the file into memory.
1000 /// Once the key structure is read (via Streamer) the class identifier
1001 /// of the object is known.
1002 /// Using the class identifier we find the TClass object for this class.
1003 /// A TClass object contains a full description (i.e. dictionary) of the
1004 /// associated class. In particular the TClass object can create a new
1005 /// object of the class type it describes. This new object now calls its
1006 /// Streamer function to rebuilt itself.
1007 
1008 void *TKey::ReadObjectAny(const TClass* expectedClass)
1009 {
1011  if (!fBufferRef) {
1012  Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
1013  return 0;
1014  }
1015  if (GetFile()==0) return 0;
1018 
1019  if (fObjlen > fNbytes-fKeylen) {
1020  fBuffer = new char[fNbytes];
1021  ReadFile(); //Read object structure from file
1022  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
1023  } else {
1024  fBuffer = fBufferRef->Buffer();
1025  ReadFile(); //Read object structure from file
1026  }
1027 
1028  // get version of key
1030  Version_t kvers = fBufferRef->ReadVersion();
1031 
1034  TClass *clOnfile = 0;
1035  if (!cl) {
1036  Error("ReadObjectAny", "Unknown class %s", fClassName.Data());
1037  return 0;
1038  }
1039  Int_t baseOffset = 0;
1040  if (expectedClass) {
1041  // baseOffset will be -1 if cl does not inherit from expectedClass
1042  baseOffset = cl->GetBaseClassOffset(expectedClass);
1043  if (baseOffset == -1) {
1044  // The 2 classes are unrelated, maybe there is a converter between the 2.
1045 
1046  if (!expectedClass->GetSchemaRules() ||
1047  !expectedClass->GetSchemaRules()->HasRuleWithSourceClass(cl->GetName()))
1048  {
1049  // There is no converter
1050  return 0;
1051  }
1052  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 ....
1053  clOnfile = cl;
1054  cl = const_cast<TClass*>(expectedClass);
1055  Info("ReadObjectAny","Using Converter StreamerInfo from %s to %s",clOnfile->GetName(),expectedClass->GetName());
1056  }
1057  if (cl->GetState() > TClass::kEmulated && expectedClass->GetState() <= TClass::kEmulated) {
1058  //we cannot mix a compiled class with an emulated class in the inheritance
1059  Warning("ReadObjectAny",
1060  "Trying to read an emulated class (%s) to store in a compiled pointer (%s)",
1061  cl->GetName(),expectedClass->GetName());
1062  }
1063  }
1064  // Create an instance of this class
1065 
1066  void *pobj = cl->New();
1067  if (!pobj) {
1068  Error("ReadObjectAny", "Cannot create new object of class %s", fClassName.Data());
1069  return 0;
1070  }
1071 
1072  if (kvers > 1)
1073  fBufferRef->MapObject(pobj,cl); //register obj in map to handle self reference
1074 
1075  if (fObjlen > fNbytes-fKeylen) {
1076  char *objbuf = fBufferRef->Buffer() + fKeylen;
1077  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
1078  Int_t nin, nout = 0, nbuf;
1079  Int_t noutot = 0;
1080  while (1) {
1081  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
1082  if (hc!=0) break;
1083  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
1084  if (!nout) break;
1085  noutot += nout;
1086  if (noutot >= fObjlen) break;
1087  bufcur += nin;
1088  objbuf += nout;
1089  }
1090  if (nout) {
1091  cl->Streamer((void*)pobj, *fBufferRef, clOnfile); //read object
1092  delete [] fBuffer;
1093  } else {
1094  delete [] fBuffer;
1095  cl->Destructor(pobj);
1096  pobj = 0;
1097  goto CLEAR;
1098  }
1099  } else {
1100  cl->Streamer((void*)pobj, *fBufferRef, clOnfile); //read object
1101  }
1102 
1103  if (cl->IsTObject()) {
1104  baseOffset = cl->GetBaseClassOffset(TObject::Class());
1105  if (baseOffset==-1) {
1106  Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
1107  fClassName.Data());
1108  }
1109  TObject *tobj = (TObject*)( ((char*)pobj) +baseOffset);
1110 
1111  // See similar adjustments in ReadObj
1112  if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
1113 
1114  if (cl->InheritsFrom(TDirectoryFile::Class())) {
1115  TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
1116  dir->SetName(GetName());
1117  dir->SetTitle(GetTitle());
1118  dir->SetMother(fMotherDir);
1119  fMotherDir->Append(dir);
1120  }
1121  }
1122 
1123  {
1124  // Append the object to the directory if requested:
1125  ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
1126  if (addfunc) {
1127  addfunc(pobj, fMotherDir);
1128  }
1129  }
1130 
1131  CLEAR:
1132  delete fBufferRef;
1133  fBufferRef = 0;
1134  fBuffer = 0;
1135 
1136  return ( ((char*)pobj) + baseOffset );
1137 }
1138 
1139 ////////////////////////////////////////////////////////////////////////////////
1140 /// To read an object from the file.
1141 ///
1142 /// The object associated to this key is read from the file into memory.
1143 /// Before invoking this function, obj has been created via the
1144 /// default constructor.
1145 
1147 {
1148  if (!obj || (GetFile()==0)) return 0;
1149 
1153 
1154  if (fVersion > 1)
1155  fBufferRef->MapObject(obj); //register obj in map to handle self reference
1156 
1157  if (fObjlen > fNbytes-fKeylen) {
1158  fBuffer = new char[fNbytes];
1159  ReadFile(); //Read object structure from file
1160  memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
1161  } else {
1162  fBuffer = fBufferRef->Buffer();
1163  ReadFile(); //Read object structure from file
1164  }
1166  if (fObjlen > fNbytes-fKeylen) {
1167  char *objbuf = fBufferRef->Buffer() + fKeylen;
1168  UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
1169  Int_t nin, nout = 0, nbuf;
1170  Int_t noutot = 0;
1171  while (1) {
1172  Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
1173  if (hc!=0) break;
1174  R__unzip(&nin, bufcur, &nbuf, (unsigned char*) objbuf, &nout);
1175  if (!nout) break;
1176  noutot += nout;
1177  if (noutot >= fObjlen) break;
1178  bufcur += nin;
1179  objbuf += nout;
1180  }
1181  if (nout) obj->Streamer(*fBufferRef);
1182  delete [] fBuffer;
1183  } else {
1184  obj->Streamer(*fBufferRef);
1185  }
1186 
1187  // Append the object to the directory if requested:
1188  {
1189  ROOT::DirAutoAdd_t addfunc = obj->IsA()->GetDirectoryAutoAdd();
1190  if (addfunc) {
1191  addfunc(obj, fMotherDir);
1192  }
1193  }
1194 
1195  delete fBufferRef;
1196  fBufferRef = 0;
1197  fBuffer = 0;
1198  return fNbytes;
1199 }
1200 
1201 ////////////////////////////////////////////////////////////////////////////////
1202 /// Decode input buffer.
1203 ///
1204 /// In some situation will add key to gDirectory.
1205 
1206 void TKey::ReadBuffer(char *&buffer)
1207 {
1208  ReadKeyBuffer(buffer);
1209 
1210  if (!gROOT->ReadingObject() && gDirectory) {
1211  if (fSeekPdir != gDirectory->GetSeekDir()) gDirectory->AppendKey(this);
1212  }
1213 }
1214 
1215 ////////////////////////////////////////////////////////////////////////////////
1216 /// Decode input buffer.
1217 
1218 void TKey::ReadKeyBuffer(char *&buffer)
1219 {
1220  frombuf(buffer, &fNbytes);
1221  Version_t version;
1222  frombuf(buffer,&version);
1223  fVersion = (Int_t)version;
1224  frombuf(buffer, &fObjlen);
1225  fDatime.ReadBuffer(buffer);
1226  frombuf(buffer, &fKeylen);
1227  frombuf(buffer, &fCycle);
1228  if (fVersion > 1000) {
1229  frombuf(buffer, &fSeekKey);
1230 
1231  // We currently store in the 16 highest bit of fSeekPdir the value of
1232  // fPidOffset. This offset is used when a key (or basket) is transfered from one
1233  // file to the other. In this case the TRef and TObject might have stored a
1234  // pid index (to retrieve TProcessIDs) which refered to their order on the original
1235  // file, the fPidOffset is to be added to those values to correctly find the
1236  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1237  // and need to be zero for new key/basket.
1238  Long64_t pdir;
1239  frombuf(buffer, &pdir);
1240  fPidOffset = pdir >> kPidOffsetShift;
1241  fSeekPdir = pdir & kPidOffsetMask;
1242  } else {
1243  UInt_t seekkey,seekdir;
1244  frombuf(buffer, &seekkey); fSeekKey = (Long64_t)seekkey;
1245  frombuf(buffer, &seekdir); fSeekPdir= (Long64_t)seekdir;
1246  }
1247  fClassName.ReadBuffer(buffer);
1248  //the following test required for forward and backward compatibility
1249  if (fClassName == "TDirectory") {
1250  fClassName = "TDirectoryFile";
1252  }
1253 
1254  fName.ReadBuffer(buffer);
1255  fTitle.ReadBuffer(buffer);
1256 }
1257 
1258 ////////////////////////////////////////////////////////////////////////////////
1259 /// Read the key structure from the file
1260 
1262 {
1263  TFile* f = GetFile();
1264  if (f==0) return kFALSE;
1265 
1266  Int_t nsize = fNbytes;
1267  f->Seek(fSeekKey);
1268 #if 0
1269  for (Int_t i = 0; i < nsize; i += kMAXFILEBUFFER) {
1270  int nb = kMAXFILEBUFFER;
1271  if (i+nb > nsize) nb = nsize - i;
1272  f->ReadBuffer(fBuffer+i,nb);
1273  }
1274 #else
1275  if( f->ReadBuffer(fBuffer,nsize) )
1276  {
1277  Error("ReadFile", "Failed to read data.");
1278  return kFALSE;
1279  }
1280 #endif
1281  if (gDebug) {
1282  std::cout << "TKey Reading "<<nsize<< " bytes at address "<<fSeekKey<<std::endl;
1283  }
1284  return kTRUE;
1285 }
1286 
1287 ////////////////////////////////////////////////////////////////////////////////
1288 /// Set parent in key buffer.
1289 
1290 void TKey::SetParent(const TObject *parent)
1291 {
1292  if (fBufferRef) fBufferRef->SetParent((TObject*)parent);
1293 }
1294 
1295 ////////////////////////////////////////////////////////////////////////////////
1296 /// Reset the key as it had not been 'filled' yet.
1297 
1299 {
1300  fPidOffset = 0;
1301  fNbytes = 0;
1302  fBuffer = 0;
1303  fObjlen = 0;
1304  fCycle = 0;
1305  fSeekPdir = 0;
1306  fSeekKey = 0;
1307  fLeft = 0;
1308  fDatime = (UInt_t)0;
1309 
1310  // fBufferRef and fKeylen intentionally not reset/changed
1311 
1313 }
1314 
1315 ////////////////////////////////////////////////////////////////////////////////
1316 /// Return the size in bytes of the key header structure.
1317 ///
1318 /// An explaination about the nbytes (Int_t nbytes) variable used in the
1319 /// function. The size of fSeekKey and fSeekPdir is 8 instead of 4 if version is
1320 /// greater than 1000.
1321 /// | Component | Sizeof |
1322 /// |-------------------|--------|
1323 /// | fNbytes | 4 |
1324 /// | sizeof(Version_t) | 2 |
1325 /// | fObjlen | 4 |
1326 /// | fKeylen | 2 |
1327 /// | fCycle | 2 |
1328 /// | fSeekKey | 4 or 8 |
1329 /// | fSeekPdir | 4 or 8 |
1330 /// | **TOTAL** | 22 |
1331 
1333 {
1334  Int_t nbytes = 22; if (fVersion > 1000) nbytes += 8;
1335  nbytes += fDatime.Sizeof();
1336  if (TestBit(kIsDirectoryFile)) {
1337  nbytes += 11; // strlen("TDirectory")+1
1338  } else {
1339  nbytes += fClassName.Sizeof();
1340  }
1341  nbytes += fName.Sizeof();
1342  nbytes += fTitle.Sizeof();
1343  return nbytes;
1344 }
1345 
1346 ////////////////////////////////////////////////////////////////////////////////
1347 /// Stream a class object.
1348 
1349 void TKey::Streamer(TBuffer &b)
1350 {
1351  Version_t version;
1352  if (b.IsReading()) {
1353  b >> fNbytes;
1354  b >> version; fVersion = (Int_t)version;
1355  b >> fObjlen;
1356  fDatime.Streamer(b);
1357  b >> fKeylen;
1358  b >> fCycle;
1359  if (fVersion > 1000) {
1360  b >> fSeekKey;
1361 
1362  // We currently store in the 16 highest bit of fSeekPdir the value of
1363  // fPidOffset. This offset is used when a key (or basket) is transfered from one
1364  // file to the other. In this case the TRef and TObject might have stored a
1365  // pid index (to retrieve TProcessIDs) which refered to their order on the original
1366  // file, the fPidOffset is to be added to those values to correctly find the
1367  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1368  // and need to be zero for new key/basket.
1369  Long64_t pdir;
1370  b >> pdir;
1371  fPidOffset = pdir >> kPidOffsetShift;
1372  fSeekPdir = pdir & kPidOffsetMask;
1373  } else {
1374  UInt_t seekkey, seekdir;
1375  b >> seekkey; fSeekKey = (Long64_t)seekkey;
1376  b >> seekdir; fSeekPdir= (Long64_t)seekdir;
1377  }
1378  fClassName.Streamer(b);
1379  //the following test required for forward and backward compatibility
1380  if (fClassName == "TDirectory") {
1381  fClassName = "TDirectoryFile";
1383  }
1384  fName.Streamer(b);
1385  fTitle.Streamer(b);
1386  if (fKeylen < 0) {
1387  Error("Streamer","The value of fKeylen is incorrect (%d) ; trying to recover by setting it to zero",fKeylen);
1388  MakeZombie();
1389  fKeylen = 0;
1390  }
1391  if (fObjlen < 0) {
1392  Error("Streamer","The value of fObjlen is incorrect (%d) ; trying to recover by setting it to zero",fObjlen);
1393  MakeZombie();
1394  fObjlen = 0;
1395  }
1396  if (fNbytes < 0) {
1397  Error("Streamer","The value of fNbytes is incorrect (%d) ; trying to recover by setting it to zero",fNbytes);
1398  MakeZombie();
1399  fNbytes = 0;
1400  }
1401 
1402  } else {
1403  b << fNbytes;
1404  version = (Version_t)fVersion;
1405  b << version;
1406  b << fObjlen;
1407  if (fDatime.Get() == 0) fDatime.Set();
1408  fDatime.Streamer(b);
1409  b << fKeylen;
1410  b << fCycle;
1411  if (fVersion > 1000) {
1412  b << fSeekKey;
1413 
1414  // We currently store in the 16 highest bit of fSeekPdir the value of
1415  // fPidOffset. This offset is used when a key (or basket) is transfered from one
1416  // file to the other. In this case the TRef and TObject might have stored a
1417  // pid index (to retrieve TProcessIDs) which refered to their order on the original
1418  // file, the fPidOffset is to be added to those values to correctly find the
1419  // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1420  // and need to be zero for new key/basket.
1422  b << pdir;
1423  } else {
1424  b << (Int_t)fSeekKey;
1425  b << (Int_t)fSeekPdir;
1426  }
1427  if (TestBit(kIsDirectoryFile)) {
1428  // We want to record "TDirectory" instead of TDirectoryFile so that the file can be read by ancient version of ROOT.
1429  gTDirectoryString().Streamer(b);
1430  } else {
1431  fClassName.Streamer(b);
1432  }
1433  fName.Streamer(b);
1434  fTitle.Streamer(b);
1435  }
1436 }
1437 
1438 ////////////////////////////////////////////////////////////////////////////////
1439 /// Write the encoded object supported by this key.
1440 /// The function returns the number of bytes committed to the file.
1441 /// If a write error occurs, the number of bytes returned is -1.
1442 
1444 {
1445  if (!f) f = GetFile();
1446  if (!f) return -1;
1447 
1448  Int_t nsize = fNbytes;
1449  char *buffer = fBuffer;
1450  if (cycle) {
1451  fCycle = cycle;
1452  FillBuffer(buffer);
1453  buffer = fBuffer;
1454  }
1455 
1456  if (fLeft > 0) nsize += sizeof(Int_t);
1457  f->Seek(fSeekKey);
1458 #if 0
1459  for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
1460  Int_t nb = kMAXFILEBUFFER;
1461  if (i+nb > nsize) nb = nsize - i;
1462  f->WriteBuffer(buffer,nb);
1463  buffer += nb;
1464  }
1465 #else
1466  Bool_t result = f->WriteBuffer(buffer,nsize);
1467 #endif
1468  //f->Flush(); Flushing takes too much time.
1469  // Let user flush the file when they want.
1470  if (gDebug) {
1471  std::cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
1472  <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<std::endl;
1473  }
1474 
1475  DeleteBuffer();
1476  return result==kTRUE ? -1 : nsize;
1477 }
1478 
1479 ////////////////////////////////////////////////////////////////////////////////
1480 /// Write the encoded object supported by this key.
1481 /// The function returns the number of bytes committed to the file.
1482 /// If a write error occurs, the number of bytes returned is -1.
1483 
1485 {
1486  if (!f) f = GetFile();
1487  if (!f) return -1;
1488 
1489  Int_t nsize = fNbytes;
1490  char *buffer = fBuffer;
1491 
1492  if (fLeft > 0) nsize += sizeof(Int_t);
1493  f->Seek(fSeekKey);
1494 #if 0
1495  for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
1496  Int_t nb = kMAXFILEBUFFER;
1497  if (i+nb > nsize) nb = nsize - i;
1498  f->WriteBuffer(buffer,nb);
1499  buffer += nb;
1500  }
1501 #else
1502  Bool_t result = f->WriteBuffer(buffer,nsize);
1503 #endif
1504  //f->Flush(); Flushing takes too much time.
1505  // Let user flush the file when they want.
1506  if (gDebug) {
1507  std::cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
1508  <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<std::endl;
1509  }
1510 
1511  return result==kTRUE ? -1 : nsize;
1512 }
1513 
1514 ////////////////////////////////////////////////////////////////////////////////
1515 /// Title can keep 32x32 xpm thumbnail/icon of the parent object.
1516 
1517 const char *TKey::GetIconName() const
1518 {
1519  return (!fTitle.IsNull() && fTitle.BeginsWith("/* ") ? fTitle.Data() : 0);
1520 }
1521 
1522 ////////////////////////////////////////////////////////////////////////////////
1523 /// Returns title (title can contain 32x32 xpm thumbnail/icon).
1524 
1525 const char *TKey::GetTitle() const
1526 {
1527  if (!fTitle.IsNull() && fTitle.BeginsWith("/* ")) { // title contains xpm thumbnail
1528  static TString ret;
1529  int start = fTitle.Index("/*") + 3;
1530  int stop = fTitle.Index("*/") - 1;
1531  ret = fTitle(start, stop - start);
1532  return ret.Data();
1533  }
1534  return fTitle.Data();
1535 }
Int_t fVersion
Key version identifier.
Definition: TKey.h:40
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:37
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
void SetBufferOffset(Int_t offset=0)
Definition: TBuffer.h:90
Int_t fLeft
Number of bytes left in current segment.
Definition: TKey.h:49
Bool_t IsReading() const
Definition: TBuffer.h:83
void frombuf(char *&buf, Bool_t *x)
Definition: Bytes.h:282
virtual const char * GetIconName() const
Title can keep 32x32 xpm thumbnail/icon of the parent object.
Definition: TKey.cxx:1517
virtual TList * GetListOfKeys() const
Definition: TDirectory.h:158
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:899
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket...
Definition: TBufferFile.h:51
long long Long64_t
Definition: RtypesCore.h:69
Long64_t GetLast() const
Definition: TFree.h:43
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:52
virtual void SetEND(Long64_t last)
Definition: TFile.h:255
unsigned short UShort_t
Definition: RtypesCore.h:36
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:157
virtual const char * GetClassName() const
Definition: TKey.h:77
virtual void Seek(Long64_t offset, ERelativeTo pos=kBeg)
Seek to a specific position in the file. Pos it either kBeg, kCur or kEnd.
Definition: TFile.cxx:2105
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:50
virtual Bool_t ReadBuffer(char *buf, Int_t len)
Read a buffer from the file.
Definition: TFile.cxx:1602
virtual void * ReadObjectAny(const TClass *expectedClass)
To read an object (non deriving from TObject) from the file.
Definition: TKey.cxx:1008
Buffer base class used for serializing objects.
Definition: TBuffer.h:42
TKey()
TKey default constructor.
Definition: TKey.cxx:92
#define R__ASSERT(e)
Definition: TError.h:98
#define gROOT
Definition: TROOT.h:364
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:582
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:137
virtual ULong_t Hash() const
This Hash function should redefine the default from TNamed.
Definition: TKey.cxx:627
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
void SetParent(TObject *parent)
Set parent owning this buffer.
Definition: TBuffer.cxx:239
virtual void UseCurrentStyle()
Set current style settings in this object This function is called when either TCanvas::UseCurrentStyl...
Definition: TObject.cxx:760
const char * Class
Definition: TXMLSetup.cxx:64
const Int_t kTitleMax
Definition: TKey.cxx:69
char * fBuffer
Object buffer.
Definition: TKey.h:50
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:53
void SetLast(Long64_t last)
Definition: TFree.h:47
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:1332
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:739
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:497
Int_t Length() const
Definition: TBuffer.h:96
virtual void ls(Option_t *option="") const
List Key contents.
Definition: TKey.cxx:685
#define gFile
Definition: TFile.h:316
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2717
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:188
Service class for TFile.
Definition: TFree.h:29
Long64_t fSeekPdir
Location of parent directory on file.
Definition: TKey.h:47
virtual void ReadBuffer(char *&buffer)
Read string from I/O buffer.
Definition: TString.cxx:1228
virtual void Print(Option_t *option="") const
Print key contents.
Definition: TKey.cxx:694
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
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:1443
EState GetState() const
Definition: TClass.h:443
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:44
TString fClassName
Object Class name.
Definition: TKey.h:48
virtual ~TKey()
TKey default destructor.
Definition: TKey.cxx:520
virtual void SetPidOffset(UShort_t offset)=0
virtual TList * GetList() const
Definition: TDirectory.h:157
void tobuf(char *&buf, Bool_t x)
Definition: Bytes.h:59
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:30
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:43
virtual TFile * GetFile() const
Definition: TDirectory.h:155
virtual Int_t WriteFileKeepBuffer(TFile *f=0)
Write the encoded object supported by this key.
Definition: TKey.cxx:1484
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition: TObject.cxx:750
A doubly linked list.
Definition: TList.h:47
Int_t GetCompressionAlgorithm() const
Definition: TFile.h:360
virtual void Delete(Option_t *option="")
Delete this object.
Definition: TObject.cxx:229
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:41
virtual void IncrementPidOffset(UShort_t offset)
Increment fPidOffset by &#39;offset&#39;.
Definition: TKey.cxx:642
virtual void Keep()
Set the "KEEP" status.
Definition: TKey.cxx:677
virtual void ReadBuffer(char *&buffer)
Decode input buffer.
Definition: TKey.cxx:1206
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:557
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:2536
Bool_t HasDefaultConstructor() const
virtual TObject * Remove(TObject *obj)
Remove object from the list.
Definition: TList.cxx:675
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:2308
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:488
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:558
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5071
void SetRefreshFlag(Bool_t flag)
Definition: TBrowser.h:101
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
virtual Bool_t ReadFile()
Read the key structure from the file.
Definition: TKey.cxx:1261
ROOT::DirAutoAdd_t GetDirectoryAutoAdd() const
Ssiz_t Length() const
Definition: TString.h:390
virtual void MakeFree(Long64_t first, Long64_t last)
Mark unused bytes on the file.
Definition: TFile.cxx:1394
virtual void Append(TObject *obj, Bool_t replace=kFALSE)
Append object to this directory.
Definition: TDirectory.cxx:153
virtual Long64_t GetSeekDir() const
Definition: TDirectory.h:163
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:1930
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition: TROOT.cxx:2618
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
virtual void Reset()
Reset the key as it had not been &#39;filled&#39; yet.
Definition: TKey.cxx:1298
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4610
virtual TObject * ReadObjWithBuffer(char *bufferRead)
To read a TObject* from bufferRead.
Definition: TKey.cxx:872
TString fName
Definition: TNamed.h:36
Long64_t GetFirst() const
Definition: TFree.h:42
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=0) const
Definition: TClass.h:540
virtual ULong_t Hash() const
Return hash value for this object.
Definition: TNamed.h:53
TBuffer * fBufferRef
Pointer to the TBuffer object.
Definition: TKey.h:51
virtual void SetParent(const TObject *parent)
Set parent in key buffer.
Definition: TKey.cxx:1290
Long64_t fSeekKey
Location of object on file.
Definition: TKey.h:46
virtual Int_t AppendKey(TKey *)
Definition: TDirectory.h:127
void SetFirst(Long64_t first)
Definition: TFree.h:46
void ReadKeyBuffer(char *&buffer)
Decode input buffer.
Definition: TKey.cxx:1218
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:45
#define ClassImp(name)
Definition: Rtypes.h:279
double f(double x)
Describe directory structure in memory.
Definition: TDirectory.h:44
virtual const char * GetTitle() const
Returns title (title can contain 32x32 xpm thumbnail/icon).
Definition: TKey.cxx:1525
unsigned long long ULong64_t
Definition: RtypesCore.h:70
std::atomic< UInt_t > keyAbsNumber
Definition: TKey.cxx:85
unsigned long ULong_t
Definition: RtypesCore.h:51
virtual Int_t Sizeof() const
Returns size string will occupy on I/O buffer.
Definition: TString.cxx:1298
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2893
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:387
Int_t fObjlen
Length of uncompressed object in bytes.
Definition: TKey.h:42
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:200
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:5583
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition: TKey.cxx:730
virtual void DeleteBuffer()
Delete key buffer(s).
Definition: TKey.cxx:546
void(* DirAutoAdd_t)(void *, TDirectory *)
Definition: Rtypes.h:152
TList * GetListOfFree() const
Definition: TFile.h:206
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:202
void MakeZombie()
Definition: TObject.h:47
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:128
Int_t fNbytes
Number of bytes for the object on file.
Definition: TKey.h:41
virtual Bool_t IsFolder() const
Returns kTRUE in case object contains browsable objects (like containers or lists of other objects)...
Definition: TObject.cxx:518
#define gDirectory
Definition: TDirectory.h:221
double result[121]
virtual 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:1852
virtual void FillBuffer(char *&buffer) const
Copy string into I/O buffer.
Definition: TString.cxx:1207
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:55
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:953
Short_t GetCycle() const
Return cycle number associated to this key.
Definition: TKey.cxx:564
const Bool_t kTRUE
Definition: Rtypes.h:91
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:155
virtual void SetMother(TObject *mother)
Definition: TDirectory.h:192
Int_t Sizeof() const
Definition: TDatime.h:83
Int_t GetCompressionLevel() const
Definition: TFile.h:366
Bool_t IsFolder() const
Check if object referenced by the key is a folder.
Definition: TKey.cxx:656
char name[80]
Definition: TGX11.cxx:109
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:911
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:1059
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4714
const char * Data() const
Definition: TString.h:349