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