#include "Riostream.h"
#include "TROOT.h"
#include "TClass.h"
#include "TDirectoryFile.h"
#include "TFile.h"
#include "TKey.h"
#include "TBufferFile.h"
#include "TFree.h"
#include "TBrowser.h"
#include "Bytes.h"
#include "TInterpreter.h"
#include "TError.h"
#include "TVirtualStreamerInfo.h"
#include "TSchemaRuleSet.h"
extern "C" void R__zip (Int_t cxlevel, Int_t *nin, char *bufin, Int_t *lout, char *bufout, Int_t *nout);
extern "C" void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout);
const Int_t kMAXBUF = 0xffffff;
const Int_t kTitleMax = 32000;
#if 0
const Int_t kMAXFILEBUFFER = 262144;
#endif
#if !defined(_MSC_VER) || (_MSC_VER>1300)
const ULong64_t kPidOffsetMask = 0xffffffffffffULL;
#else
const ULong64_t kPidOffsetMask = 0xffffffffffffUL;
#endif
const UChar_t kPidOffsetShift = 48;
UInt_t keyAbsNumber = 0;
ClassImp(TKey)
TKey::TKey() : TNamed(), fDatime((UInt_t)0)
{
Build(0, "", 0);
fKeylen = Sizeof();
keyAbsNumber++; SetUniqueID(keyAbsNumber);
}
TKey::TKey(TDirectory* motherDir) : TNamed(), fDatime((UInt_t)0)
{
Build(motherDir, "", 0);
fKeylen = Sizeof();
keyAbsNumber++; SetUniqueID(keyAbsNumber);
}
TKey::TKey(Long64_t pointer, Int_t nbytes, TDirectory* motherDir) : TNamed()
{
Build(motherDir, "", pointer);
fSeekKey = pointer;
fNbytes = nbytes;
fBuffer = new char[nbytes];
keyAbsNumber++; SetUniqueID(keyAbsNumber);
}
TKey::TKey(const char *name, const char *title, const TClass *cl, Int_t nbytes, TDirectory* motherDir)
: TNamed(name,title)
{
Build(motherDir, cl->GetName(), -1);
fKeylen = Sizeof();
fObjlen = nbytes;
Create(nbytes);
}
TKey::TKey(const TString &name, const TString &title, const TClass *cl, Int_t nbytes, TDirectory* motherDir)
: TNamed(name,title)
{
Build(motherDir, cl->GetName(), -1);
fKeylen = Sizeof();
fObjlen = nbytes;
Create(nbytes);
}
TKey::TKey(const TObject *obj, const char *name, Int_t bufsize, TDirectory* motherDir)
: TNamed(name, obj->GetTitle())
{
R__ASSERT(obj);
if (!obj->IsA()->HasDefaultConstructor()) {
Warning("TKey", "since %s has no public constructor\n"
"\twhich can be called without argument, objects of this class\n"
"\tcan not be read with the current library. You will need to\n"
"\tadd a default constructor before attempting to read it.",
obj->ClassName());
}
Build(motherDir, obj->ClassName(), -1);
Int_t lbuf, nout, noutot, bufmax, nzip;
fBufferRef = new TBufferFile(TBuffer::kWrite, bufsize);
fBufferRef->SetParent(GetFile());
fCycle = fMotherDir->AppendKey(this);
Streamer(*fBufferRef);
fKeylen = fBufferRef->Length();
fBufferRef->MapObject(obj);
((TObject*)obj)->Streamer(*fBufferRef);
lbuf = fBufferRef->Length();
fObjlen = lbuf - fKeylen;
Int_t cxlevel = GetFile() ? GetFile()->GetCompressionLevel() : 0;
if (cxlevel && fObjlen > 256) {
if (cxlevel == 2) cxlevel--;
Int_t nbuffers = fObjlen/kMAXBUF;
Int_t buflen = TMath::Max(512,fKeylen + fObjlen + 9*nbuffers + 28);
fBuffer = new char[buflen];
char *objbuf = fBufferRef->Buffer() + fKeylen;
char *bufcur = &fBuffer[fKeylen];
noutot = 0;
nzip = 0;
for (Int_t i=0;i<=nbuffers;i++) {
if (i == nbuffers) bufmax = fObjlen -nzip;
else bufmax = kMAXBUF;
R__zip(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout);
if (nout == 0 || nout >= fObjlen) {
fBuffer = fBufferRef->Buffer();
Create(fObjlen);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
return;
}
bufcur += nout;
noutot += nout;
objbuf += kMAXBUF;
nzip += kMAXBUF;
}
Create(noutot);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
delete fBufferRef; fBufferRef = 0;
} else {
fBuffer = fBufferRef->Buffer();
Create(fObjlen);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
}
}
TKey::TKey(const void *obj, const TClass *cl, const char *name, Int_t bufsize, TDirectory* motherDir)
: TNamed(name, "object title")
{
R__ASSERT(obj && cl);
if (!cl->HasDefaultConstructor()) {
Warning("TKey", "since %s has no public constructor\n"
"\twhich can be called without argument, objects of this class\n"
"\tcan not be read with the current library. You will need to\n"
"\tadd a default constructor before attempting to read it.",
cl->GetName());
}
TClass *clActual = cl->GetActualClass(obj);
const void* actualStart;
if (clActual) {
const char *temp = (const char*) obj;
Int_t offset = (cl != clActual) ?
clActual->GetBaseClassOffset(cl) : 0;
temp -= offset;
actualStart = temp;
} else {
clActual = const_cast<TClass*>(cl);
actualStart = obj;
}
Build(motherDir, clActual->GetName(), -1);
fBufferRef = new TBufferFile(TBuffer::kWrite, bufsize);
fBufferRef->SetParent(GetFile());
fCycle = fMotherDir->AppendKey(this);
Streamer(*fBufferRef);
fKeylen = fBufferRef->Length();
Int_t lbuf, nout, noutot, bufmax, nzip;
fBufferRef->MapObject(actualStart,clActual);
clActual->Streamer((void*)actualStart, *fBufferRef);
lbuf = fBufferRef->Length();
fObjlen = lbuf - fKeylen;
Int_t cxlevel = GetFile() ? GetFile()->GetCompressionLevel() : 0;
if (cxlevel && fObjlen > 256) {
if (cxlevel == 2) cxlevel--;
Int_t nbuffers = fObjlen/kMAXBUF;
Int_t buflen = TMath::Max(512,fKeylen + fObjlen + 9*nbuffers + 28);
fBuffer = new char[buflen];
char *objbuf = fBufferRef->Buffer() + fKeylen;
char *bufcur = &fBuffer[fKeylen];
noutot = 0;
nzip = 0;
for (Int_t i=0;i<=nbuffers;i++) {
if (i == nbuffers) bufmax = fObjlen -nzip;
else bufmax = kMAXBUF;
R__zip(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout);
if (nout == 0 || nout >= fObjlen) {
fBuffer = fBufferRef->Buffer();
Create(fObjlen);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
return;
}
bufcur += nout;
noutot += nout;
objbuf += kMAXBUF;
nzip += kMAXBUF;
}
Create(noutot);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
delete fBufferRef; fBufferRef = 0;
} else {
fBuffer = fBufferRef->Buffer();
Create(fObjlen);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
}
}
void TKey::Build(TDirectory* motherDir, const char* classname, Long64_t filepos)
{
fMotherDir = motherDir;
fPidOffset = 0;
fNbytes = 0;
fBuffer = 0;
fKeylen = 0;
fObjlen = 0;
fBufferRef = 0;
fCycle = 0;
fSeekPdir = 0;
fSeekKey = 0;
fLeft = 0;
fClassName = classname;
if (fClassName == "TDirectoryFile") fClassName = "TDirectory";
fVersion = TKey::Class_Version();
if ((filepos==-1) && GetFile()) filepos = GetFile()->GetEND();
if (filepos > TFile::kStartBigFile) fVersion += 1000;
if (fTitle.Length() > kTitleMax) fTitle.Resize(kTitleMax);
}
void TKey::Browse(TBrowser *b)
{
if (fMotherDir==0) return;
TClass *objcl = TClass::GetClass(GetClassName());
void* obj = fMotherDir->GetList()->FindObject(GetName());
if (obj && objcl->InheritsFrom(TObject::Class())) {
TObject *tobj = (TObject*)obj;
if (!tobj->IsFolder()) {
if (tobj->InheritsFrom(TCollection::Class()))
tobj->Delete();
delete tobj;
obj = 0;
}
}
if (!obj)
obj = ReadObj();
if (b && obj) {
objcl->Browse(obj,b);
b->SetRefreshFlag(kTRUE);
}
}
void TKey::Create(Int_t nbytes, TFile* externFile)
{
keyAbsNumber++; SetUniqueID(keyAbsNumber);
TFile *f = externFile;
if (!f) f = GetFile();
if (!f) {
Error("Create","Cannot create key without file");
return;
}
Int_t nsize = nbytes + fKeylen;
TList *lfree = f->GetListOfFree();
TFree *f1 = (TFree*)lfree->First();
TFree *bestfree = f1->GetBestFree(lfree,nsize);
if (bestfree == 0) {
Error("Create","Cannot allocate %d bytes for ID = %s Title = %s",
nsize,GetName(),GetTitle());
return;
}
fDatime.Set();
fSeekKey = bestfree->GetFirst();
if (fSeekKey >= f->GetEND()) {
f->SetEND(fSeekKey+nsize);
bestfree->SetFirst(fSeekKey+nsize);
fLeft = -1;
if (!fBuffer) fBuffer = new char[nsize];
} else {
fLeft = Int_t(bestfree->GetLast() - fSeekKey - nsize + 1);
}
fNbytes = nsize;
if (fLeft == 0) {
if (!fBuffer) {
fBuffer = new char[nsize];
}
lfree->Remove(bestfree);
delete bestfree;
}
if (fLeft > 0) {
if (!fBuffer) {
fBuffer = new char[nsize+sizeof(Int_t)];
}
char *buffer = fBuffer+nsize;
Int_t nbytesleft = -fLeft;
tobuf(buffer, nbytesleft);
bestfree->SetFirst(fSeekKey+nsize);
}
fSeekPdir = externFile ? externFile->GetSeekDir() : fMotherDir->GetSeekDir();
}
TKey::~TKey()
{
DeleteBuffer();
}
void TKey::Delete(Option_t *option)
{
if (option && option[0] == 'v') printf("Deleting key: %s at address %lld, nbytes = %d\n",GetName(),fSeekKey,fNbytes);
Long64_t first = fSeekKey;
Long64_t last = fSeekKey + fNbytes -1;
if (GetFile()) GetFile()->MakeFree(first, last);
fMotherDir->GetListOfKeys()->Remove(this);
}
void TKey::DeleteBuffer()
{
if (fBufferRef) {
delete fBufferRef;
fBufferRef = 0;
} else {
if (fBuffer) {
delete [] fBuffer;
}
}
fBuffer = 0;
}
Short_t TKey::GetCycle() const
{
return ((fCycle >0) ? fCycle : -fCycle);
}
TFile *TKey::GetFile() const
{
return fMotherDir!=0 ? fMotherDir->GetFile() : gFile;
}
Short_t TKey::GetKeep() const
{
return ((fCycle >0) ? 0 : 1);
}
void TKey::FillBuffer(char *&buffer)
{
tobuf(buffer, fNbytes);
Version_t version = fVersion;
tobuf(buffer, version);
tobuf(buffer, fObjlen);
fDatime.FillBuffer(buffer);
tobuf(buffer, fKeylen);
tobuf(buffer, fCycle);
if (fVersion > 1000) {
tobuf(buffer, fSeekKey);
Long64_t pdir = (((Long64_t)fPidOffset)<<kPidOffsetShift) | (kPidOffsetMask & fSeekPdir);
tobuf(buffer, pdir);
} else {
tobuf(buffer, (Int_t)fSeekKey);
tobuf(buffer, (Int_t)fSeekPdir);
}
fClassName.FillBuffer(buffer);
fName.FillBuffer(buffer);
fTitle.FillBuffer(buffer);
}
ULong_t TKey::Hash() const
{
return TNamed::Hash();
}
void TKey::IncrementPidOffset(UShort_t offset)
{
fPidOffset += offset;
if (fPidOffset) {
if (fVersion<1000) fVersion += 1000;
}
}
Bool_t TKey::IsFolder() const
{
Bool_t ret = kFALSE;
TClass *classPtr = TClass::GetClass((const char *) fClassName);
if (classPtr && classPtr->GetClassInfo() && classPtr->InheritsFrom(TObject::Class())) {
TObject *obj = (TObject *) classPtr->New(TClass::kDummyNew);
if (obj) {
ret = obj->IsFolder();
delete obj;
}
}
return ret;
}
void TKey::Keep()
{
if (fCycle >0) fCycle = -fCycle;
}
void TKey::ls(Option_t *) const
{
TROOT::IndentLevel();
cout <<"KEY: "<<fClassName<<"\t"<<GetName()<<";"<<GetCycle()<<"\t"<<GetTitle()<<endl;
}
void TKey::Print(Option_t *) const
{
printf("TKey Name = %s, Title = %s, Cycle = %d\n",GetName(),GetTitle(),GetCycle());
}
TObject *TKey::ReadObj()
{
TClass *cl = TClass::GetClass(fClassName.Data());
if (!cl) {
Error("ReadObj", "Unknown class %s", fClassName.Data());
return 0;
}
if (!cl->InheritsFrom(TObject::Class())) {
return (TObject*)ReadObjectAny(0);
}
fBufferRef = new TBufferFile(TBuffer::kRead, fObjlen+fKeylen);
if (!fBufferRef) {
Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
return 0;
}
if (GetFile()==0) return 0;
fBufferRef->SetParent(GetFile());
fBufferRef->SetPidOffset(fPidOffset);
if (fObjlen > fNbytes-fKeylen) {
fBuffer = new char[fNbytes];
ReadFile();
memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
} else {
fBuffer = fBufferRef->Buffer();
ReadFile();
}
fBufferRef->SetBufferOffset(sizeof(fNbytes));
Version_t kvers = fBufferRef->ReadVersion();
fBufferRef->SetBufferOffset(fKeylen);
TObject *tobj = 0;
char *pobj = (char*)cl->New();
Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
if (baseOffset==-1) {
Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
fClassName.Data());
}
tobj = (TObject*)(pobj+baseOffset);
if (!pobj) {
Error("ReadObj", "Cannot create new object of class %s", fClassName.Data());
return 0;
}
if (kvers > 1)
fBufferRef->MapObject(pobj,cl);
if (fObjlen > fNbytes-fKeylen) {
char *objbuf = fBufferRef->Buffer() + fKeylen;
UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
Int_t nin, nout, nbuf;
Int_t noutot = 0;
while (1) {
nin = 9 + ((Int_t)bufcur[3] | ((Int_t)bufcur[4] << 8) | ((Int_t)bufcur[5] << 16));
nbuf = (Int_t)bufcur[6] | ((Int_t)bufcur[7] << 8) | ((Int_t)bufcur[8] << 16);
R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
if (!nout) break;
noutot += nout;
if (noutot >= fObjlen) break;
bufcur += nin;
objbuf += nout;
}
if (nout) {
tobj->Streamer(*fBufferRef);
delete [] fBuffer;
} else {
delete [] fBuffer;
delete pobj;
pobj = 0;
tobj = 0;
goto CLEAR;
}
} else {
tobj->Streamer(*fBufferRef);
}
if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
if (cl->InheritsFrom(TDirectoryFile::Class())) {
TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
dir->SetName(GetName());
dir->SetTitle(GetTitle());
dir->SetMother(fMotherDir);
fMotherDir->Append(dir);
}
{
ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
if (addfunc) {
addfunc(pobj, fMotherDir);
}
}
CLEAR:
delete fBufferRef;
fBufferRef = 0;
fBuffer = 0;
return tobj;
}
TObject *TKey::ReadObjWithBuffer(char *bufferRead)
{
TClass *cl = TClass::GetClass(fClassName.Data());
if (!cl) {
Error("ReadObjWithBuffer", "Unknown class %s", fClassName.Data());
return 0;
}
if (!cl->InheritsFrom(TObject::Class())) {
return (TObject*)ReadObjectAny(0);
}
fBufferRef = new TBufferFile(TBuffer::kRead, fObjlen+fKeylen);
if (!fBufferRef) {
Error("ReadObjWithBuffer", "Cannot allocate buffer: fObjlen = %d", fObjlen);
return 0;
}
if (GetFile()==0) return 0;
fBufferRef->SetParent(GetFile());
fBufferRef->SetPidOffset(fPidOffset);
if (fObjlen > fNbytes-fKeylen) {
fBuffer = bufferRead;
memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
} else {
fBuffer = fBufferRef->Buffer();
ReadFile();
}
fBufferRef->SetBufferOffset(sizeof(fNbytes));
Version_t kvers = fBufferRef->ReadVersion();
fBufferRef->SetBufferOffset(fKeylen);
TObject *tobj = 0;
char *pobj = (char*)cl->New();
Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
if (baseOffset==-1) {
Fatal("ReadObjWithBuffer","Incorrect detection of the inheritance from TObject for class %s.\n",
fClassName.Data());
}
tobj = (TObject*)(pobj+baseOffset);
if (!pobj) {
Error("ReadObjWithBuffer", "Cannot create new object of class %s", fClassName.Data());
return 0;
}
if (kvers > 1)
fBufferRef->MapObject(pobj,cl);
if (fObjlen > fNbytes-fKeylen) {
char *objbuf = fBufferRef->Buffer() + fKeylen;
UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
Int_t nin, nout, nbuf;
Int_t noutot = 0;
while (1) {
nin = 9 + ((Int_t)bufcur[3] | ((Int_t)bufcur[4] << 8) | ((Int_t)bufcur[5] << 16));
nbuf = (Int_t)bufcur[6] | ((Int_t)bufcur[7] << 8) | ((Int_t)bufcur[8] << 16);
R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
if (!nout) break;
noutot += nout;
if (noutot >= fObjlen) break;
bufcur += nin;
objbuf += nout;
}
if (nout) {
tobj->Streamer(*fBufferRef);
} else {
delete pobj;
pobj = 0;
tobj = 0;
goto CLEAR;
}
} else {
tobj->Streamer(*fBufferRef);
}
if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
if (cl->InheritsFrom(TDirectoryFile::Class())) {
TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
dir->SetName(GetName());
dir->SetTitle(GetTitle());
dir->SetMother(fMotherDir);
fMotherDir->Append(dir);
}
{
ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
if (addfunc) {
addfunc(pobj, fMotherDir);
}
}
CLEAR:
delete fBufferRef;
fBufferRef = 0;
fBuffer = 0;
return tobj;
}
void *TKey::ReadObjectAny(const TClass* expectedClass)
{
fBufferRef = new TBufferFile(TBuffer::kRead, fObjlen+fKeylen);
if (!fBufferRef) {
Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
return 0;
}
if (GetFile()==0) return 0;
fBufferRef->SetParent(GetFile());
fBufferRef->SetPidOffset(fPidOffset);
if (fObjlen > fNbytes-fKeylen) {
fBuffer = new char[fNbytes];
ReadFile();
memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
} else {
fBuffer = fBufferRef->Buffer();
ReadFile();
}
fBufferRef->SetBufferOffset(sizeof(fNbytes));
Version_t kvers = fBufferRef->ReadVersion();
fBufferRef->SetBufferOffset(fKeylen);
TClass *cl = TClass::GetClass(fClassName.Data());
TClass *clOnfile = 0;
if (!cl) {
Error("ReadObjectAny", "Unknown class %s", fClassName.Data());
return 0;
}
Int_t baseOffset = 0;
if (expectedClass) {
baseOffset = cl->GetBaseClassOffset(expectedClass);
if (baseOffset == -1) {
if (!expectedClass->GetSchemaRules() ||
!expectedClass->GetSchemaRules()->HasRuleWithSourceClass(cl->GetName()))
{
return 0;
}
baseOffset = 0;
clOnfile = cl;
cl = const_cast<TClass*>(expectedClass);
Info("ReadObjectAny","Using Converter StreamerInfo from %s to %s",clOnfile->GetName(),expectedClass->GetName());
}
if (cl->GetClassInfo() && !expectedClass->GetClassInfo()) {
Warning("ReadObjectAny",
"Trying to read an emulated class (%s) to store in a compiled pointer (%s)",
cl->GetName(),expectedClass->GetName());
}
}
void *pobj = cl->New();
if (!pobj) {
Error("ReadObjectAny", "Cannot create new object of class %s", fClassName.Data());
return 0;
}
if (kvers > 1)
fBufferRef->MapObject(pobj,cl);
if (fObjlen > fNbytes-fKeylen) {
char *objbuf = fBufferRef->Buffer() + fKeylen;
UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
Int_t nin, nout, nbuf;
Int_t noutot = 0;
while (1) {
nin = 9 + ((Int_t)bufcur[3] | ((Int_t)bufcur[4] << 8) | ((Int_t)bufcur[5] << 16));
nbuf = (Int_t)bufcur[6] | ((Int_t)bufcur[7] << 8) | ((Int_t)bufcur[8] << 16);
R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
if (!nout) break;
noutot += nout;
if (noutot >= fObjlen) break;
bufcur += nin;
objbuf += nout;
}
if (nout) {
cl->Streamer((void*)pobj, *fBufferRef, clOnfile);
delete [] fBuffer;
} else {
delete [] fBuffer;
cl->Destructor(pobj);
pobj = 0;
goto CLEAR;
}
} else {
cl->Streamer((void*)pobj, *fBufferRef, clOnfile);
}
if (cl->InheritsFrom(TObject::Class())) {
baseOffset = cl->GetBaseClassOffset(TObject::Class());
if (baseOffset==-1) {
Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
fClassName.Data());
}
TObject *tobj = (TObject*)( ((char*)pobj) +baseOffset);
if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
if (cl->InheritsFrom(TDirectoryFile::Class())) {
TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
dir->SetName(GetName());
dir->SetTitle(GetTitle());
dir->SetMother(fMotherDir);
fMotherDir->Append(dir);
}
}
{
ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
if (addfunc) {
addfunc(pobj, fMotherDir);
}
}
CLEAR:
delete fBufferRef;
fBufferRef = 0;
fBuffer = 0;
return ( ((char*)pobj) + baseOffset );
}
Int_t TKey::Read(TObject *obj)
{
if (!obj || (GetFile()==0)) return 0;
fBufferRef = new TBufferFile(TBuffer::kRead, fObjlen+fKeylen);
fBufferRef->SetParent(GetFile());
fBufferRef->SetPidOffset(fPidOffset);
if (fVersion > 1)
fBufferRef->MapObject(obj);
if (fObjlen > fNbytes-fKeylen) {
fBuffer = new char[fNbytes];
ReadFile();
memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
} else {
fBuffer = fBufferRef->Buffer();
ReadFile();
}
fBufferRef->SetBufferOffset(fKeylen);
if (fObjlen > fNbytes-fKeylen) {
char *objbuf = fBufferRef->Buffer() + fKeylen;
UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
Int_t nin, nout, nbuf;
Int_t noutot = 0;
while (1) {
nin = 9 + ((Int_t)bufcur[3] | ((Int_t)bufcur[4] << 8) | ((Int_t)bufcur[5] << 16));
nbuf = (Int_t)bufcur[6] | ((Int_t)bufcur[7] << 8) | ((Int_t)bufcur[8] << 16);
R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
if (!nout) break;
noutot += nout;
if (noutot >= fObjlen) break;
bufcur += nin;
objbuf += nout;
}
if (nout) obj->Streamer(*fBufferRef);
delete [] fBuffer;
} else {
obj->Streamer(*fBufferRef);
}
delete fBufferRef;
fBufferRef = 0;
fBuffer = 0;
return fNbytes;
}
void TKey::ReadBuffer(char *&buffer)
{
ReadKeyBuffer(buffer);
if (!gROOT->ReadingObject() && gDirectory) {
if (fSeekPdir != gDirectory->GetSeekDir()) gDirectory->AppendKey(this);
}
}
void TKey::ReadKeyBuffer(char *&buffer)
{
frombuf(buffer, &fNbytes);
Version_t version;
frombuf(buffer,&version);
fVersion = (Int_t)version;
frombuf(buffer, &fObjlen);
fDatime.ReadBuffer(buffer);
frombuf(buffer, &fKeylen);
frombuf(buffer, &fCycle);
if (fVersion > 1000) {
frombuf(buffer, &fSeekKey);
Long64_t pdir;
frombuf(buffer, &pdir);
fPidOffset = pdir >> kPidOffsetShift;
fSeekPdir = pdir & kPidOffsetMask;
} else {
Int_t seekkey,seekdir;
frombuf(buffer, &seekkey); fSeekKey = (Long64_t)seekkey;
frombuf(buffer, &seekdir); fSeekPdir= (Long64_t)seekdir;
}
fClassName.ReadBuffer(buffer);
if (fClassName == "TDirectory") fClassName = "TDirectoryFile";
fName.ReadBuffer(buffer);
fTitle.ReadBuffer(buffer);
}
void TKey::ReadFile()
{
TFile* f = GetFile();
if (f==0) return;
Int_t nsize = fNbytes;
f->Seek(fSeekKey);
#if 0
for (Int_t i = 0; i < nsize; i += kMAXFILEBUFFER) {
int nb = kMAXFILEBUFFER;
if (i+nb > nsize) nb = nsize - i;
f->ReadBuffer(fBuffer+i,nb);
}
#else
f->ReadBuffer(fBuffer,nsize);
#endif
if (gDebug) {
cout << "TKey Reading "<<nsize<< " bytes at address "<<fSeekKey<<endl;
}
}
void TKey::SetParent(const TObject *parent)
{
if (fBufferRef) fBufferRef->SetParent((TObject*)parent);
}
void TKey::Reset()
{
fPidOffset = 0;
fNbytes = 0;
fBuffer = 0;
fObjlen = 0;
fCycle = 0;
fSeekPdir = 0;
fSeekKey = 0;
fLeft = 0;
fDatime = (UInt_t)0;
keyAbsNumber++; SetUniqueID(keyAbsNumber);
}
Int_t TKey::Sizeof() const
{
Int_t nbytes = 22; if (fVersion > 1000) nbytes += 8;
nbytes += fDatime.Sizeof();
nbytes += fClassName.Sizeof();
nbytes += fName.Sizeof();
nbytes += fTitle.Sizeof();
return nbytes;
}
void TKey::Streamer(TBuffer &b)
{
Version_t version;
if (b.IsReading()) {
b >> fNbytes;
b >> version; fVersion = (Int_t)version;
b >> fObjlen;
fDatime.Streamer(b);
b >> fKeylen;
b >> fCycle;
if (fVersion > 1000) {
b >> fSeekKey;
Long64_t pdir;
b >> pdir;
fPidOffset = pdir >> kPidOffsetShift;
fSeekPdir = pdir & kPidOffsetMask;
} else {
Int_t seekkey, seekdir;
b >> seekkey; fSeekKey = (Long64_t)seekkey;
b >> seekdir; fSeekPdir= (Long64_t)seekdir;
}
fClassName.Streamer(b);
fName.Streamer(b);
fTitle.Streamer(b);
if (fKeylen < 0) {
Error("Streamer","The value of fKeylen is incorrect (%d) ; trying to recover by setting it to zero",fKeylen);
MakeZombie();
fKeylen = 0;
}
if (fObjlen < 0) {
Error("Streamer","The value of fObjlen is incorrect (%d) ; trying to recover by setting it to zero",fObjlen);
MakeZombie();
fObjlen = 0;
}
if (fNbytes < 0) {
Error("Streamer","The value of fNbytes is incorrect (%d) ; trying to recover by setting it to zero",fNbytes);
MakeZombie();
fNbytes = 0;
}
} else {
b << fNbytes;
version = (Version_t)fVersion;
b << version;
b << fObjlen;
if (fDatime.Get() == 0) fDatime.Set();
fDatime.Streamer(b);
b << fKeylen;
b << fCycle;
if (fVersion > 1000) {
b << fSeekKey;
Long64_t pdir = (((Long64_t)fPidOffset)<<kPidOffsetShift) | (kPidOffsetMask & fSeekPdir);
b << pdir;
} else {
b << (Int_t)fSeekKey;
b << (Int_t)fSeekPdir;
}
fClassName.Streamer(b);
fName.Streamer(b);
fTitle.Streamer(b);
}
}
Int_t TKey::WriteFile(Int_t cycle, TFile* f)
{
if (!f) f = GetFile();
if (!f) return -1;
Int_t nsize = fNbytes;
char *buffer = fBuffer;
if (cycle) {
fCycle = cycle;
FillBuffer(buffer);
buffer = fBuffer;
}
if (fLeft > 0) nsize += sizeof(Int_t);
f->Seek(fSeekKey);
#if 0
for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
Int_t nb = kMAXFILEBUFFER;
if (i+nb > nsize) nb = nsize - i;
f->WriteBuffer(buffer,nb);
buffer += nb;
}
#else
Bool_t result = f->WriteBuffer(buffer,nsize);
#endif
if (gDebug) {
cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
<<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<endl;
}
DeleteBuffer();
return result==kTRUE ? -1 : nsize;
}
Int_t TKey::WriteFileKeepBuffer(TFile *f)
{
if (!f) f = GetFile();
if (!f) return -1;
Int_t nsize = fNbytes;
char *buffer = fBuffer;
if (fLeft > 0) nsize += sizeof(Int_t);
f->Seek(fSeekKey);
#if 0
for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
Int_t nb = kMAXFILEBUFFER;
if (i+nb > nsize) nb = nsize - i;
f->WriteBuffer(buffer,nb);
buffer += nb;
}
#else
Bool_t result = f->WriteBuffer(buffer,nsize);
#endif
if (gDebug) {
cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
<<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<endl;
}
return result==kTRUE ? -1 : nsize;
}
const char *TKey::GetIconName() const
{
return (!fTitle.IsNull() && fTitle.BeginsWith("/* ") ? fTitle.Data() : 0);
}
const char *TKey::GetTitle() const
{
if (!fTitle.IsNull() && fTitle.BeginsWith("/* ")) {
static TString ret;
int start = fTitle.Index("/*") + 3;
int stop = fTitle.Index("*/") - 1;
ret = fTitle(start, stop - start);
return ret.Data();
}
return fTitle.Data();
}