#include "TBasket.h"
#include "TBufferFile.h"
#include "TTree.h"
#include "TBranch.h"
#include "TFile.h"
#include "TBufferFile.h"
#include "TMath.h"
#include "TTreeCache.h"
#include "TVirtualPerfStats.h"
#include "TTimeStamp.h"
#include "RZip.h"
#if (__GNUC__ >= 3) || defined(__INTEL_COMPILER)
#if !defined(R__unlikely)
#define R__unlikely(expr) __builtin_expect(!!(expr), 0)
#endif
#if !defined(R__likely)
#define R__likely(expr) __builtin_expect(!!(expr), 1)
#endif
#else
#define R__unlikely(expr) expr
#define R__likely(expr) expr
#endif
const UInt_t kDisplacementMask = 0xFF000000;
ClassImp(TBasket)
TBasket::TBasket() : fCompressedBufferRef(0), fOwnsCompressedBuffer(kFALSE), fLastWriteBufferSize(0)
{
fDisplacement = 0;
fEntryOffset = 0;
fBufferRef = 0;
fBuffer = 0;
fHeaderOnly = kFALSE;
fBufferSize = 0;
fNevBufSize = 0;
fNevBuf = 0;
fLast = 0;
fBranch = 0;
}
TBasket::TBasket(TDirectory *motherDir) : TKey(motherDir),fCompressedBufferRef(0), fOwnsCompressedBuffer(kFALSE), fLastWriteBufferSize(0)
{
fDisplacement = 0;
fEntryOffset = 0;
fBufferRef = 0;
fBuffer = 0;
fHeaderOnly = kFALSE;
fBufferSize = 0;
fNevBufSize = 0;
fNevBuf = 0;
fLast = 0;
fBranch = 0;
}
TBasket::TBasket(const char *name, const char *title, TBranch *branch) :
TKey(branch->GetDirectory()),fCompressedBufferRef(0), fOwnsCompressedBuffer(kFALSE), fLastWriteBufferSize(0)
{
SetName(name);
SetTitle(title);
fClassName = "TBasket";
fBufferSize = branch->GetBasketSize();
fNevBufSize = branch->GetEntryOffsetLen();
fNevBuf = 0;
fEntryOffset = 0;
fDisplacement= 0;
fBuffer = 0;
fBufferRef = new TBufferFile(TBuffer::kWrite, fBufferSize);
fVersion += 1000;
if (branch->GetDirectory()) {
TFile *file = branch->GetFile();
fBufferRef->SetParent(file);
}
fHeaderOnly = kTRUE;
fLast = 0;
if (branch->GetTree()) {
fCompressedBufferRef = branch->GetTree()->GetTransientBuffer(fBufferSize);
fOwnsCompressedBuffer = kFALSE;
if (!fCompressedBufferRef) {
fCompressedBufferRef = new TBufferFile(TBuffer::kRead, fBufferSize);
fOwnsCompressedBuffer = kTRUE;
}
}
Streamer(*fBufferRef);
fKeylen = fBufferRef->Length();
fObjlen = fBufferSize - fKeylen;
fLast = fKeylen;
fBuffer = 0;
fBranch = branch;
fHeaderOnly = kFALSE;
if (fNevBufSize) {
fEntryOffset = new Int_t[fNevBufSize];
for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
}
branch->GetTree()->IncrementTotalBuffers(fBufferSize);
}
TBasket::~TBasket()
{
if (fDisplacement) delete [] fDisplacement;
if (fEntryOffset) delete [] fEntryOffset;
if (fBufferRef) delete fBufferRef;
fBufferRef = 0;
fBuffer = 0;
fDisplacement= 0;
fEntryOffset = 0;
if (fCompressedBufferRef && fOwnsCompressedBuffer) {
delete fCompressedBufferRef;
fCompressedBufferRef = 0;
}
}
void TBasket::AdjustSize(Int_t newsize)
{
if (fBuffer == fBufferRef->Buffer()) {
fBufferRef->Expand(newsize);
fBuffer = fBufferRef->Buffer();
} else {
fBufferRef->Expand(newsize);
}
fBranch->GetTree()->IncrementTotalBuffers(newsize-fBufferSize);
fBufferSize = newsize;
}
Long64_t TBasket::CopyTo(TFile *to)
{
fBufferRef->SetWriteMode();
Int_t nout = fNbytes - fKeylen;
fBuffer = fBufferRef->Buffer();
Create(nout, to);
fBufferRef->SetBufferOffset(0);
fHeaderOnly = kTRUE;
Streamer(*fBufferRef);
fHeaderOnly = kFALSE;
Int_t nBytes = WriteFileKeepBuffer(to);
return nBytes>0 ? nBytes : -1;
}
void TBasket::DeleteEntryOffset()
{
if (fEntryOffset) delete [] fEntryOffset;
fEntryOffset = 0;
fNevBufSize = 0;
}
Int_t TBasket::DropBuffers()
{
if (!fBuffer && !fBufferRef) return 0;
if (fDisplacement) delete [] fDisplacement;
if (fEntryOffset) delete [] fEntryOffset;
if (fBufferRef) delete fBufferRef;
if (fCompressedBufferRef && fOwnsCompressedBuffer) delete fCompressedBufferRef;
fBufferRef = 0;
fCompressedBufferRef = 0;
fBuffer = 0;
fDisplacement= 0;
fEntryOffset = 0;
fBranch->GetTree()->IncrementTotalBuffers(-fBufferSize);
return fBufferSize;
}
Int_t TBasket::GetEntryPointer(Int_t entry)
{
Int_t offset;
if (fEntryOffset) offset = fEntryOffset[entry];
else offset = fKeylen + entry*fNevBufSize;
fBufferRef->SetBufferOffset(offset);
return offset;
}
Int_t TBasket::LoadBasketBuffers(Long64_t pos, Int_t len, TFile *file, TTree *tree)
{
if (fBufferRef) {
fBufferRef->Reset();
fBufferRef->SetWriteMode();
if (fBufferRef->BufferSize() < len) {
fBufferRef->Expand(len);
}
fBufferRef->SetReadMode();
} else {
fBufferRef = new TBufferFile(TBuffer::kRead, len);
}
fBufferRef->SetParent(file);
char *buffer = fBufferRef->Buffer();
file->Seek(pos);
TFileCacheRead *pf = file->GetCacheRead(tree);
if (pf) {
TVirtualPerfStats* temp = gPerfStats;
if (tree->GetPerfStats()) gPerfStats = tree->GetPerfStats();
Int_t st = pf->ReadBuffer(buffer,pos,len);
if (st < 0) {
return 1;
} else if (st == 0) {
file->Seek(pos);
TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
if (fc) fc->Disable();
Int_t ret = file->ReadBuffer(buffer,len);
if (fc) fc->Enable();
pf->AddNoCacheBytesRead(len);
pf->AddNoCacheReadCalls(1);
if (ret) {
return 1;
}
}
gPerfStats = temp;
file->SetOffset(pos + len);
} else {
TVirtualPerfStats* temp = gPerfStats;
if (tree->GetPerfStats() != 0) gPerfStats = tree->GetPerfStats();
if (file->ReadBuffer(buffer,len)) {
gPerfStats = temp;
return 1;
}
else gPerfStats = temp;
}
fBufferRef->SetReadMode();
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
return 0;
}
void TBasket::MoveEntries(Int_t dentries)
{
Int_t i;
if (dentries >= fNevBuf) return;
Int_t bufbegin;
Int_t moved;
if (fEntryOffset) {
bufbegin = fEntryOffset[dentries];
moved = bufbegin-GetKeylen();
if (!fDisplacement) {
fDisplacement = new Int_t[fNevBufSize];
}
for (i = 0; i<(fNevBufSize-dentries); ++i) {
fDisplacement[i] = fEntryOffset[i+dentries];
fEntryOffset[i] = fEntryOffset[i+dentries] - moved;
}
for (i = fNevBufSize-dentries; i<fNevBufSize; ++i) {
fDisplacement[i] = 0;
fEntryOffset[i] = 0;
}
} else {
bufbegin = GetKeylen() + dentries*fNevBufSize;
moved = bufbegin-GetKeylen();
}
TBuffer *buf = GetBufferRef();
char *buffer = buf->Buffer();
memmove(buffer+GetKeylen(),buffer+bufbegin,buf->Length()-bufbegin);
buf->SetBufferOffset(buf->Length()-moved);
fNevBuf -= dentries;
}
#define OLD_CASE_EXPRESSION fObjlen==fNbytes-fKeylen && GetBranch()->GetCompressionLevel()!=0 && file->GetVersion()<=30401
Int_t TBasket::ReadBasketBuffersUncompressedCase()
{
fBuffer = fBufferRef->Buffer();
fBufferRef->SetBufferOffset(fNbytes);
fBufferRef->SetBit(TBufferFile::kNotDecompressed);
delete [] fEntryOffset; fEntryOffset = 0;
delete [] fDisplacement; fDisplacement = 0;
fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
return 0;
}
Int_t TBasket::ReadBasketBuffersUnzip(char* buffer, Int_t size, Bool_t mustFree, TFile* file)
{
if (fBufferRef) {
fBufferRef->SetBuffer(buffer, size, mustFree);
fBufferRef->SetReadMode();
fBufferRef->Reset();
} else {
fBufferRef = new TBufferFile(TBuffer::kRead, size, buffer, mustFree);
}
fBufferRef->SetParent(file);
Streamer(*fBufferRef);
if (IsZombie()) {
return -1;
}
Bool_t oldCase = OLD_CASE_EXPRESSION;
if ((fObjlen > fNbytes-fKeylen || oldCase) && TestBit(TBufferFile::kNotDecompressed) && (fNevBuf==1)) {
return TBasket::ReadBasketBuffersUncompressedCase();
}
fBuffer = fBufferRef->Buffer();
return fObjlen+fKeylen;
}
static inline TBuffer* R__InitializeReadBasketBuffer(TBuffer* bufferRef, Int_t len, TFile* file)
{
TBuffer* result;
if (R__likely(bufferRef)) {
bufferRef->SetReadMode();
Int_t curBufferSize = bufferRef->BufferSize();
if (curBufferSize < len) {
bufferRef->Expand(Int_t(len*1.05));
}
bufferRef->Reset();
result = bufferRef;
} else {
result = new TBufferFile(TBuffer::kRead, len);
}
result->SetParent(file);
return result;
}
void inline TBasket::InitializeCompressedBuffer(Int_t len, TFile* file)
{
Bool_t compressedBufferExists = fCompressedBufferRef != NULL;
fCompressedBufferRef = R__InitializeReadBasketBuffer(fCompressedBufferRef, len, file);
if (R__unlikely(!compressedBufferExists)) {
fOwnsCompressedBuffer = kTRUE;
}
}
Int_t TBasket::ReadBasketBuffers(Long64_t pos, Int_t len, TFile *file)
{
if(!fBranch->GetDirectory()) {
return -1;
}
Bool_t oldCase;
char *rawUncompressedBuffer, *rawCompressedBuffer;
Int_t uncompressedBufferLen;
TFileCacheRead *pf = file->GetCacheRead(fBranch->GetTree());
if (pf) {
Int_t res = -1;
Bool_t free = kTRUE;
char *buffer;
res = pf->GetUnzipBuffer(&buffer, pos, len, &free);
if (R__unlikely(res >= 0)) {
len = ReadBasketBuffersUnzip(buffer, res, free, file);
if (len <= 0) return -len;
goto AfterBuffer;
}
}
TBuffer* readBufferRef;
if (R__unlikely(fBranch->GetCompressionLevel()==0)) {
readBufferRef = fBufferRef;
} else {
readBufferRef = fCompressedBufferRef;
}
fBranch->GetTree()->IncrementTotalBuffers(-fBufferSize);
readBufferRef = R__InitializeReadBasketBuffer(readBufferRef, len, file);
if (!readBufferRef) {
Error("ReadBasketBuffers", "Unable to allocate buffer.");
return 1;
}
if (pf) {
TVirtualPerfStats* temp = gPerfStats;
if (fBranch->GetTree()->GetPerfStats() != 0) gPerfStats = fBranch->GetTree()->GetPerfStats();
Int_t st = pf->ReadBuffer(readBufferRef->Buffer(),pos,len);
if (st < 0) {
return 1;
} else if (st == 0) {
TTreeCache *fc = dynamic_cast<TTreeCache*>(file->GetCacheRead());
if (fc) fc->Disable();
Int_t ret = file->ReadBuffer(readBufferRef->Buffer(),pos,len);
if (fc) fc->Enable();
pf->AddNoCacheBytesRead(len);
pf->AddNoCacheReadCalls(1);
if (ret) {
return 1;
}
}
gPerfStats = temp;
} else {
TVirtualPerfStats* temp = gPerfStats;
if (fBranch->GetTree()->GetPerfStats() != 0) gPerfStats = fBranch->GetTree()->GetPerfStats();
if (file->ReadBuffer(readBufferRef->Buffer(),pos,len)) {
gPerfStats = temp;
return 1;
}
else gPerfStats = temp;
}
Streamer(*readBufferRef);
if (IsZombie()) {
return 1;
}
rawCompressedBuffer = readBufferRef->Buffer();
if (R__unlikely(readBufferRef == fBufferRef))
{
if (R__likely(fObjlen+fKeylen == fNbytes)) {
goto AfterBuffer;
} else {
InitializeCompressedBuffer(len, file);
if (!fCompressedBufferRef) {
Error("ReadBasketBuffers", "Unable to allocate buffer.");
return 1;
}
fBufferRef->Reset();
rawCompressedBuffer = fCompressedBufferRef->Buffer();
memcpy(rawCompressedBuffer, fBufferRef->Buffer(), len);
}
}
uncompressedBufferLen = len > fObjlen+fKeylen ? len : fObjlen+fKeylen;
fBufferRef = R__InitializeReadBasketBuffer(fBufferRef, uncompressedBufferLen, file);
rawUncompressedBuffer = fBufferRef->Buffer();
fBuffer = rawUncompressedBuffer;
oldCase = OLD_CASE_EXPRESSION;
if (fObjlen > fNbytes-fKeylen || oldCase) {
if (R__unlikely(TestBit(TBufferFile::kNotDecompressed) && (fNevBuf==1))) {
return ReadBasketBuffersUncompressedCase();
}
Double_t start = 0;
if (R__unlikely(gPerfStats)) {
start = TTimeStamp();
}
memcpy(rawUncompressedBuffer, rawCompressedBuffer, fKeylen);
char *rawUncompressedObjectBuffer = rawUncompressedBuffer+fKeylen;
UChar_t *rawCompressedObjectBuffer = (UChar_t*)rawCompressedBuffer+fKeylen;
Int_t nin, nbuf;
Int_t nout = 0, noutot = 0, nintot = 0;
while (1) {
if (R__unlikely(R__unzip_header(&nin, rawCompressedObjectBuffer, &nbuf) != 0)) {
Error("ReadBasketBuffers", "Inconsistency found in header (nin=%d, nbuf=%d)", nin, nbuf);
break;
}
if (R__unlikely(oldCase && (nin > fObjlen || nbuf > fObjlen))) {
memcpy(rawUncompressedBuffer+fKeylen, rawCompressedObjectBuffer+fKeylen, fObjlen);
goto AfterBuffer;
}
R__unzip(&nin, rawCompressedObjectBuffer, &nbuf, (unsigned char*) rawUncompressedObjectBuffer, &nout);
if (!nout) break;
noutot += nout;
nintot += nin;
if (noutot >= fObjlen) break;
rawCompressedObjectBuffer += nin;
rawUncompressedObjectBuffer += nout;
}
if (R__unlikely(noutot != fObjlen)) {
Error("ReadBasketBuffers", "fNbytes = %d, fKeylen = %d, fObjlen = %d, noutot = %d, nout=%d, nin=%d, nbuf=%d", fNbytes,fKeylen,fObjlen, noutot,nout,nin,nbuf);
fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
return 1;
}
len = fObjlen+fKeylen;
TVirtualPerfStats* temp = gPerfStats;
if (fBranch->GetTree()->GetPerfStats() != 0) gPerfStats = fBranch->GetTree()->GetPerfStats();
if (R__unlikely(gPerfStats)) {
gPerfStats->UnzipEvent(fBranch->GetTree(),pos,start,nintot,fObjlen);
}
gPerfStats = temp;
} else {
memcpy(rawUncompressedBuffer, rawCompressedBuffer, len);
}
AfterBuffer:
fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
if (!fBranch->GetEntryOffsetLen()) {
return 0;
}
delete [] fEntryOffset;
fEntryOffset = 0;
fBufferRef->SetBufferOffset(fLast);
fBufferRef->ReadArray(fEntryOffset);
if (!fEntryOffset) {
fEntryOffset = new Int_t[fNevBuf+1];
fEntryOffset[0] = fKeylen;
Warning("ReadBasketBuffers","basket:%s has fNevBuf=%d but fEntryOffset=0, pos=%lld, len=%d, fNbytes=%d, fObjlen=%d, trying to repair",GetName(),fNevBuf,pos,len,fNbytes,fObjlen);
return 0;
}
delete [] fDisplacement;
fDisplacement = 0;
if (fBufferRef->Length() != len) {
fBufferRef->ReadArray(fDisplacement);
}
return 0;
}
Int_t TBasket::ReadBasketBytes(Long64_t pos, TFile *file)
{
const Int_t len = 128;
char buffer[len];
Int_t keylen;
file->GetRecordHeader(buffer, pos,len, fNbytes, fObjlen, keylen);
fKeylen = keylen;
return fNbytes;
}
void TBasket::Reset()
{
Int_t curSize = fBufferRef->BufferSize();
Int_t curLen = (GetObjlen() + GetKeylen());
Long_t newSize = -1;
if (curSize > 2*curLen)
{
Long_t curBsize = fBranch->GetBasketSize();
if (curSize > 2*curBsize ) {
Long_t avgSize = (Long_t)(fBranch->GetTotBytes() / (1+fBranch->GetWriteBasket()));
if (curSize > 2*avgSize) {
newSize = curBsize;
if (curLen > newSize) {
newSize = curLen;
}
if (avgSize > newSize) {
newSize = avgSize;
}
newSize = newSize + 512 - newSize%512;
}
}
}
if (newSize != -1) {
fBufferRef->Expand(newSize,kFALSE);
}
TKey::Reset();
Int_t newNevBufSize = fBranch->GetEntryOffsetLen();
if (newNevBufSize==0) {
delete [] fEntryOffset;
fEntryOffset = 0;
} else if (newNevBufSize != fNevBufSize) {
delete [] fEntryOffset;
fEntryOffset = new Int_t[newNevBufSize];
} else if (!fEntryOffset) {
fEntryOffset = new Int_t[newNevBufSize];
}
fNevBufSize = newNevBufSize;
fNevBuf = 0;
Int_t *storeEntryOffset = fEntryOffset;
fEntryOffset = 0;
Int_t *storeDisplacement = fDisplacement;
fDisplacement= 0;
fBuffer = 0;
fBufferRef->Reset();
fBufferRef->SetWriteMode();
fHeaderOnly = kTRUE;
fLast = 0;
Streamer(*fBufferRef);
fKeylen = fBufferRef->Length();
fObjlen = fBufferSize - fKeylen;
fLast = fKeylen;
fBuffer = 0;
fHeaderOnly = kFALSE;
fDisplacement= storeDisplacement;
fEntryOffset = storeEntryOffset;
if (fNevBufSize) {
for (Int_t i=0;i<fNevBufSize;i++) fEntryOffset[i] = 0;
}
}
void TBasket::SetReadMode()
{
fLast = fBufferRef->Length();
fBufferRef->SetReadMode();
}
void TBasket::SetWriteMode()
{
fBufferRef->SetWriteMode();
fBufferRef->SetBufferOffset(fLast);
}
void TBasket::Streamer(TBuffer &b)
{
char flag;
if (b.IsReading()) {
TKey::Streamer(b);
Version_t v = b.ReadVersion();
b >> fBufferSize;
b >> fNevBufSize;
if (fNevBufSize < 0) {
Error("Streamer","The value of fNevBufSize is incorrect (%d) ; trying to recover by setting it to zero",fNevBufSize);
MakeZombie();
fNevBufSize = 0;
}
b >> fNevBuf;
b >> fLast;
b >> flag;
if (fLast > fBufferSize) fBufferSize = fLast;
if (!flag) {
return;
}
if (flag%10 != 2) {
delete [] fEntryOffset;
fEntryOffset = new Int_t[fNevBufSize];
if (fNevBuf) b.ReadArray(fEntryOffset);
if (20<flag && flag<40) {
for(int i=0; i<fNevBuf; i++){
fEntryOffset[i] &= ~kDisplacementMask;
}
}
if (flag>40) {
fDisplacement = new Int_t[fNevBufSize];
b.ReadArray(fDisplacement);
}
}
if (flag == 1 || flag > 10) {
fBufferRef = new TBufferFile(TBuffer::kRead,fBufferSize);
fBufferRef->SetParent(b.GetParent());
char *buf = fBufferRef->Buffer();
if (v > 1) b.ReadFastArray(buf,fLast);
else b.ReadArray(buf);
fBufferRef->SetBufferOffset(fLast);
}
} else {
TKey::Streamer(b);
b.WriteVersion(TBasket::IsA());
if (fBufferRef) {
Int_t curLast = fBufferRef->Length();
if (!fHeaderOnly && !fSeekKey && curLast > fLast) fLast = curLast;
}
if (fLast > fBufferSize) fBufferSize = fLast;
b << fBufferSize;
b << fNevBufSize;
b << fNevBuf;
b << fLast;
if (fHeaderOnly) {
flag = 0;
b << flag;
} else {
flag = 1;
if (!fEntryOffset) flag = 2;
if (fBufferRef) flag += 10;
if (fDisplacement) flag += 40;
b << flag;
if (fEntryOffset && fNevBuf) {
b.WriteArray(fEntryOffset, fNevBuf);
if (fDisplacement) b.WriteArray(fDisplacement, fNevBuf);
}
if (fBufferRef) {
char *buf = fBufferRef->Buffer();
b.WriteFastArray(buf, fLast);
}
}
}
}
void TBasket::Update(Int_t offset, Int_t skipped)
{
if (fEntryOffset) {
if (fNevBuf+1 >= fNevBufSize) {
Int_t newsize = TMath::Max(10,2*fNevBufSize);
Int_t *newoff = TStorage::ReAllocInt(fEntryOffset, newsize,
fNevBufSize);
if (fDisplacement) {
Int_t *newdisp = TStorage::ReAllocInt(fDisplacement, newsize,
fNevBufSize);
fDisplacement = newdisp;
}
fEntryOffset = newoff;
fNevBufSize = newsize;
if (fBranch->GetWriteBasket() < 10) {
fBranch->SetEntryOffsetLen(newsize);
}
}
fEntryOffset[fNevBuf] = offset;
if (skipped!=offset && !fDisplacement){
fDisplacement = new Int_t[fNevBufSize];
for (Int_t i = 0; i<fNevBufSize; i++) fDisplacement[i] = fEntryOffset[i];
}
if (fDisplacement) {
fDisplacement[fNevBuf] = skipped;
fBufferRef->SetBufferDisplacement(skipped);
}
}
fNevBuf++;
}
Int_t TBasket::WriteBuffer()
{
const Int_t kWrite = 1;
TFile *file = fBranch->GetFile(kWrite);
if (!file) return 0;
if (!file->IsWritable()) {
return -1;
}
fMotherDir = file;
if (R__unlikely(fBufferRef->TestBit(TBufferFile::kNotDecompressed))) {
Bool_t writing = fBufferRef->IsWriting();
fBufferRef->SetReadMode();
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
if (writing) fBufferRef->SetWriteMode();
Int_t nout = fNbytes - fKeylen;
fBuffer = fBufferRef->Buffer();
Create(nout,file);
fBufferRef->SetBufferOffset(0);
fHeaderOnly = kTRUE;
Streamer(*fBufferRef);
int nBytes = WriteFileKeepBuffer();
fHeaderOnly = kFALSE;
return nBytes>0 ? fKeylen+nout : -1;
}
fLast = fBufferRef->Length();
if (fEntryOffset) {
fBufferRef->WriteArray(fEntryOffset,fNevBuf+1);
if (fDisplacement) {
fBufferRef->WriteArray(fDisplacement,fNevBuf+1);
delete [] fDisplacement; fDisplacement = 0;
}
}
Int_t lbuf, nout, noutot, bufmax, nzip;
lbuf = fBufferRef->Length();
fObjlen = lbuf - fKeylen;
fHeaderOnly = kTRUE;
fCycle = fBranch->GetWriteBasket();
Int_t cxlevel = fBranch->GetCompressionLevel();
Int_t cxAlgorithm = fBranch->GetCompressionAlgorithm();
if (cxlevel > 0) {
Int_t nbuffers = 1 + (fObjlen - 1) / kMAXZIPBUF;
Int_t buflen = fKeylen + fObjlen + 9 * nbuffers + 28;
InitializeCompressedBuffer(buflen, file);
if (!fCompressedBufferRef) {
Warning("WriteBuffer", "Unable to allocate the compressed buffer");
return -1;
}
fCompressedBufferRef->SetWriteMode();
fBuffer = fCompressedBufferRef->Buffer();
char *objbuf = fBufferRef->Buffer() + fKeylen;
char *bufcur = &fBuffer[fKeylen];
noutot = 0;
nzip = 0;
for (Int_t i = 0; i < nbuffers; ++i) {
if (i == nbuffers - 1) bufmax = fObjlen - nzip;
else bufmax = kMAXZIPBUF;
R__zipMultipleAlgorithm(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout, cxAlgorithm);
if (nout == 0 || nout >= fObjlen) {
nout = fObjlen;
fBuffer = fBufferRef->Buffer();
Create(fObjlen,file);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
if ((nout+fKeylen)>buflen) {
Warning("WriteBuffer","Possible memory corruption due to compression algorithm, wrote %d bytes past the end of a block of %d bytes. fNbytes=%d, fObjLen=%d, fKeylen=%d",
(nout+fKeylen-buflen),buflen,fNbytes,fObjlen,fKeylen);
}
goto WriteFile;
}
bufcur += nout;
noutot += nout;
objbuf += kMAXZIPBUF;
nzip += kMAXZIPBUF;
}
nout = noutot;
Create(noutot,file);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
} else {
fBuffer = fBufferRef->Buffer();
Create(fObjlen,file);
fBufferRef->SetBufferOffset(0);
Streamer(*fBufferRef);
nout = fObjlen;
}
WriteFile:
Int_t nBytes = WriteFileKeepBuffer();
fHeaderOnly = kFALSE;
return nBytes>0 ? fKeylen+nout : -1;
}