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