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