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