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