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