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