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