ROOT logo
// @(#)root/tree:$Id: TBasket.cxx 25980 2008-10-27 18:17:39Z pcanal $
// Author: Rene Brun   19/01/96
/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#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 "TTreeCacheUnzip.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 UInt_t kDisplacementMask = 0xFF000000;  // In the streamer the two highest bytes of
                                              // the fEntryOffset are used to stored displacement.

ClassImp(TBasket)

//_______________________________________________________________________
//
//  Manages buffers for branches of a Tree.
//  See picture in TTree.
//

//_______________________________________________________________________
TBasket::TBasket() 
{
   // Default contructor.

   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)
{
   // Constructor used during reading.

   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())
{
   // Basket normal constructor, used during writing.

   SetName(name);
   SetTitle(title);
   fClassName   = "TBasket";
   fBufferSize  = branch->GetBasketSize();
   fNevBufSize  = branch->GetEntryOffsetLen();
   fNevBuf      = 0;
   fEntryOffset = 0;  //Must be set to 0 before calling Sizeof
   fDisplacement= 0;  //Must be set to 0 before calling Sizeof
   fBuffer      = 0;  //Must be set to 0 before calling Sizeof
   fBufferRef   = new TBufferFile(TBuffer::kWrite, fBufferSize);
   fVersion    += 1000;
   if (branch->GetDirectory()) {
      TFile *file = branch->GetFile();
      fBufferRef->SetParent(file);
   }
   fHeaderOnly  = kTRUE;
   fLast        = 0; // RDK: Must initialize before calling Streamer()
   
   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()
{
   // Basket destructor.

   if (fDisplacement) delete [] fDisplacement;
   if (fEntryOffset)  delete [] fEntryOffset;
   fDisplacement= 0;
   fEntryOffset = 0;
}

//_______________________________________________________________________
void TBasket::AdjustSize(Int_t newsize)
{
   // Increase the size of the current fBuffer up to newsize.

   char *newbuf = TStorage::ReAllocChar(fBuffer,newsize,fBufferSize);
   fBufferSize  = newsize;
   fBuffer      = newbuf;
}

//_______________________________________________________________________
Long64_t TBasket::CopyTo(TFile *to) 
{
   // Copy the basket of this branch onto the file to.

//   Global variables no longer required by key store   
//   TDirectory::TContext c(gDirectory,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 = WriteFile(0, to);

   return nBytes>0 ? nBytes : -1;
}

//_______________________________________________________________________
void TBasket::DeleteEntryOffset()
{
   //  Delete fEntryOffset array.

   if (fEntryOffset) delete [] fEntryOffset;
   fEntryOffset = 0;
   fNevBufSize  = 0;
}


//_______________________________________________________________________
Int_t TBasket::DropBuffers()
{
   // Drop buffers of this basket if it is not the current basket.

   if (!fBuffer && !fBufferRef) return 0;
   //   delete [] fBuffer;
   if (fDisplacement) delete [] fDisplacement;
   if (fEntryOffset)  delete [] fEntryOffset;
   if (fBufferRef)    delete fBufferRef;
   fBufferRef   = 0;
   fBuffer      = 0;
   fDisplacement= 0;
   fEntryOffset = 0;
   fBranch->GetTree()->IncrementTotalBuffers(-fBufferSize);
   return fBufferSize;
}

//_______________________________________________________________________
Int_t TBasket::GetEntryPointer(Int_t entry)
{
   // Get pointer to buffer for internal 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)
{ 
   // Load basket buffers in memory without unziping.
   // This function is called by TTreeCloner.
   // The function returns 0 in case of success, 1 in case of error.

   fBufferRef = new TBufferFile(TBuffer::kRead, len);
   fBufferRef->SetParent(file);
   char *buffer = fBufferRef->Buffer();
   file->Seek(pos);
   if (file->ReadBuffer(buffer,len)) {
      return 1; //error while reading
   }

   fBufferRef->SetReadMode();
   fBufferRef->SetBufferOffset(0);
   Streamer(*fBufferRef);

   return 0;
}

//_______________________________________________________________________
void TBasket::MoveEntries(Int_t dentries)
{
   // Remove the first dentries of this basket, moving entries at
   // dentries to the start of the buffer.
   
   Int_t i;

   if (dentries >= fNevBuf) return;
   Int_t bufbegin;
   Int_t moved;

   if (fEntryOffset) {
      bufbegin = fEntryOffset[dentries];
      moved = bufbegin-GetKeylen();

      // First store the original location in the fDisplacement array
      // and record the new start offset

      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 {
      // If there is no EntryOffset array, this means
      // that each entry has the same size and that 
      // it does not point to other objects (hence there
      // is no need for a displacement array).
      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;
}

//_______________________________________________________________________
Int_t TBasket::ReadBasketBuffers(Long64_t pos, Int_t len, TFile *file)
{
   // Read basket buffers in memory and cleanup.
   //
   // Read a basket buffer. Check if buffers of previous ReadBasket
   // should not be dropped. Remember, we keep buffers in memory up to
   // fMaxVirtualSize.
   // The function returns 0 in case of success, 1 in case of error
   // This function was modified with the addition of the parallel
   // unzipping, it will try to get the unzipped file from the cache
   // receiving only a pointer to that buffer (so we shall not
   // delete that pointer), although we get a new buffer in case
   // it's not found in the cache.
   // There is a lot of code duplication but it was necesary to assure
   // the expected behavior when there is no cache.

   Int_t badread= 0;
   TDirectory *cursav = gDirectory;
   TDirectory *brdir = fBranch->GetDirectory();
   if(!brdir) {
      return -1;
   }
   brdir->cd();

   if (fBranch->GetTree()->MemoryFull(fBufferSize)) fBranch->DropBaskets();

   TFileCacheRead *pf = file->GetCacheRead();
   if (pf && pf->InheritsFrom(TTreeCacheUnzip::Class())) {
      TTreeCacheUnzip *tpfu = (TTreeCacheUnzip*)pf;
      char *buffer = 0;
      Bool_t free = kTRUE; // Must we free this buffer or does it make part of the cache? 
      Int_t res = tpfu->GetUnzipBuffer(&buffer, pos, len, &free);

      // there was some error reading the buffer
	  if (res == -1) {
         badread = 1;
         return badread;
      }

      // We always create the TBuffer for the basket but it will be a shell only,
      // since we pass the pointer to the low level buffer
      fBufferRef = new TBufferFile(TBuffer::kRead, res, buffer, free);
      fBufferRef->SetParent(file);

      Streamer(*fBufferRef);

      Bool_t oldCase = fObjlen==fNbytes-fKeylen
         && GetBranch()->GetCompressionLevel()!=0
         && file->GetVersion()<=30401;
      if (fObjlen > fNbytes-fKeylen || oldCase) {
         if (TestBit(TBufferFile::kNotDecompressed) && (fNevBuf==1)) {
            // By-passing buffer unzipping has been requested and is
            // possible (only 1 entry in this basket).
            fBuffer = fBufferRef->Buffer();

            // Make sure that the buffer is set at the END of the data
            fBufferRef->SetBufferOffset(fNbytes);

            // Indicate that this buffer is weird.
            fBufferRef->SetBit(TBufferFile::kNotDecompressed);

            // Usage of this mode assume the existance of only ONE
            // entry in this basket.
            delete [] fEntryOffset; fEntryOffset = 0;
            delete [] fDisplacement; fDisplacement = 0;

            fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
            return badread;
         }
      }

      fBuffer = fBufferRef->Buffer();
      len = fObjlen+fKeylen;
   }
   else{
      fBufferRef = new TBufferFile(TBuffer::kRead, len);
      fBufferRef->SetParent(file);

      char *buffer = fBufferRef->Buffer();
      file->Seek(pos);
      if (file->ReadBuffer(buffer,len)) {
         badread = 1;
         return badread;
      }

      Streamer(*fBufferRef);

      Bool_t oldCase = fObjlen==fNbytes-fKeylen
         && GetBranch()->GetCompressionLevel()!=0
         && file->GetVersion()<=30401;
      if (fObjlen > fNbytes-fKeylen || oldCase) {
         if (TestBit(TBufferFile::kNotDecompressed) && (fNevBuf==1)) {
            // By-passing buffer unzipping has been requested and is
            // possible (only 1 entry in this basket).
            fBuffer = fBufferRef->Buffer();

            // Make sure that the buffer is set at the END of the data
            fBufferRef->SetBufferOffset(fNbytes);

            // Indicate that this buffer is weird.
            fBufferRef->SetBit(TBufferFile::kNotDecompressed);

            // Usage of this mode assume the existance of only ONE
            // entry in this basket.
            delete [] fEntryOffset; fEntryOffset = 0;
            delete [] fDisplacement; fDisplacement = 0;

            fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
            return badread;
         }
         fBuffer = new char[fObjlen+fKeylen];
         memcpy(fBuffer,buffer,fKeylen);
         char *objbuf = fBuffer + fKeylen;
         UChar_t *bufcur = (UChar_t *)&buffer[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);
            if (oldCase && (nin > fObjlen || nbuf > fObjlen)) {
               //buffer was very likely not compressed in an old version
               delete [] fBuffer;
                fBuffer = fBufferRef->Buffer();
                goto AfterBuffer;
            }
            R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
            if (!nout) break;
            noutot += nout;
            if (noutot >= fObjlen) break;
            bufcur += nin;
            objbuf += nout;
          }
         if (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);
            badread = 1;
         }
         fBufferRef->SetBuffer(fBuffer, fObjlen+fKeylen );
         len = fObjlen+fKeylen;
      } else {
         fBuffer = fBufferRef->Buffer();
      }
   }
 AfterBuffer:
   cursav->cd();

   fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);

   // read offsets table
   if (!fBranch->GetEntryOffsetLen()) {
      return badread;
   }
   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 badread;
   }
   delete [] fDisplacement;
   fDisplacement = 0;
   if (fBufferRef->Length() != len) {
      // There is more data in the buffer!  It is the displacement
      // array.  If len is less than TBuffer::kMinimalSize the actual
      // size of the buffer is too large, so we can not use the
      // fBufferRef->BufferSize()
      fBufferRef->ReadArray(fDisplacement);
   }

   return badread;
}

//_______________________________________________________________________
Int_t TBasket::ReadBasketBytes(Long64_t pos, TFile *file)
{
   // Read basket buffers in memory and cleanup
   //
   // Read first bytes of a logical record starting at position pos
   // return record length (first 4 bytes of record).

   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::SetReadMode()
{
   // Set read mode of basket.

   fLast = fBufferRef->Length();
   fBufferRef->SetReadMode();
}

//_______________________________________________________________________
void TBasket::SetWriteMode()
{
   // Set write mode of basket.

   fBufferRef->SetWriteMode();
   fBufferRef->SetBufferOffset(fLast);
}

//_______________________________________________________________________
void TBasket::Streamer(TBuffer &b)
{
   // Stream a class object.

   char flag;
   if (b.IsReading()) {
      TKey::Streamer(b); //this must be first
      Version_t v = b.ReadVersion();
      b >> fBufferSize;
      b >> fNevBufSize;
      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);
         // This is now done in the TBranch streamer since fBranch might not
         // yet be set correctly.
         //   fBranch->GetTree()->IncrementTotalBuffers(fBufferSize);
      }
   } else {
      TKey::Streamer(b);   //this must be first
      b.WriteVersion(TBasket::IsA());
      Int_t curLast = fBufferRef->Length();
      if (fBufferRef && !fHeaderOnly && !fSeekKey && curLast > fLast) fLast = curLast;
      if (fLast > fBufferSize) fBufferSize = fLast;

//   static TStopwatch timer;
//   timer.Start(kFALSE);

//       //  Check may be fEntryOffset is equidistant
//       //  This attempts by Victor fails :(
//       int equidist = 0;
//       if (1 && fEntryOffset && fNevBuf>=3) {
//          equidist = 1;
//          int dist = fEntryOffset[1]-fEntryOffset[0];
//          int curr = fEntryOffset[1];
//          for (int i=1;i<fNevBuf;i++,curr+=dist) {
//             if (fEntryOffset[i]==curr) continue;
//             equidist = 0;
//             break;
//          }
//          if (equidist) {
//             fNevBufSize=dist;
//             delete [] fEntryOffset; fEntryOffset = 0;
//          }
//           if (equidist) {
//              fprintf(stderr,"detected an equidistant case fNbytes==%d fLast==%d\n",fNbytes,fLast);
//           }
//       }
//  also he add (a little further
//       if (!fEntryOffset || equidist)  flag  = 2;
    
//   timer.Stop();
//   Double_t rt1 = timer.RealTime();
//   Double_t cp1 = timer.CpuTime();
//   fprintf(stderr,"equidist cost :  RT=%6.2f s  Cpu=%6.2f s\n",rt1,cp1);

      b << fBufferSize;
      b << fNevBufSize;
      b << fNevBuf;
      b << fLast;
      flag = 1;
      if (!fEntryOffset)  flag  = 2;
      if (fBufferRef)     flag += 10;
      if (fDisplacement)  flag += 40;
      if (fHeaderOnly)    flag  = 0;
      b << flag;
      if (fHeaderOnly) return;
      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)
{
   // Update basket header and EntryOffset table.

   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;
         //Update branch only for the first 10 baskets
         if (fBranch->GetWriteBasket() < 10) fBranch->SetEntryOffsetLen(newsize);
//          fprintf(stderr,"fNevBuf+1==%d fNevBufSize==%d\n",fNevBuf+1,fNevBufSize);
      }
      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()
{
   // Write buffer of this basket on the current file.
   //
   // The function returns the number of bytes committed to the memory.
   // If a write error occurs, the number of bytes returned is -1.
   // If no data are written, the number of bytes returned is 0.
   //

   const Int_t kWrite = 1;
   TDirectory::TContext ctxt(0);
   TFile *file = fBranch->GetFile(kWrite);
   if (!file) return 0;
   if (!file->IsWritable()) { 
      return -1;
   }
   fMotherDir = file; // fBranch->GetDirectory();
   
   if (fBufferRef->TestBit(TBufferFile::kNotDecompressed)) {
      // Read the basket information that was saved inside the buffer.
      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);         //write key itself again
      int nBytes = WriteFile(0);
      fHeaderOnly = kFALSE;
      return nBytes>0 ? fKeylen+nout : -1;
   }

//*-*- Transfer fEntryOffset table at the end of fBuffer. Offsets to fBuffer
//     are transformed in entry length to optimize compression algorithm.
   fLast      = fBufferRef->Length();
   if (fEntryOffset) {
      fBufferRef->WriteArray(fEntryOffset,fNevBuf+1);
      delete [] fEntryOffset; fEntryOffset = 0;
      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();
   if (cxlevel > 0) {
      //if (cxlevel == 2) cxlevel--; RB: I cannot remember why we had this!
      Int_t nbuffers = fObjlen/kMAXBUF;
      Int_t buflen = fKeylen + fObjlen + 28; //add 28 bytes in case object is placed in a deleted gap
      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;
         //compress the buffer
         R__zip(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout);
         
         // test if buffer has really been compressed. In case of small buffers 
         // when the buffer contains random data, it may happen that the compressed
         // buffer is larger than the input. In this case, we write the original uncompressed buffer
         if (nout == 0 || nout >= fObjlen) {
            nout = fObjlen;
            delete [] fBuffer;
            fBuffer = fBufferRef->Buffer();
            Create(fObjlen,file);
            fBufferRef->SetBufferOffset(0);

            Streamer(*fBufferRef);         //write key itself again
            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 += kMAXBUF;
         nzip   += kMAXBUF;
      }
      nout = noutot;
      Create(noutot,file);
      fBufferRef->SetBufferOffset(0);

      Streamer(*fBufferRef);         //write key itself again
      memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
      delete fBufferRef; fBufferRef = 0;
   } else {
      fBuffer = fBufferRef->Buffer();
      Create(fObjlen,file);
      fBufferRef->SetBufferOffset(0);

      Streamer(*fBufferRef);         //write key itself again
      nout = fObjlen;
   }

WriteFile:
   Int_t nBytes = WriteFile(0);
   fHeaderOnly = kFALSE;
   return nBytes>0 ? fKeylen+nout : -1;
}

 TBasket.cxx:1
 TBasket.cxx:2
 TBasket.cxx:3
 TBasket.cxx:4
 TBasket.cxx:5
 TBasket.cxx:6
 TBasket.cxx:7
 TBasket.cxx:8
 TBasket.cxx:9
 TBasket.cxx:10
 TBasket.cxx:11
 TBasket.cxx:12
 TBasket.cxx:13
 TBasket.cxx:14
 TBasket.cxx:15
 TBasket.cxx:16
 TBasket.cxx:17
 TBasket.cxx:18
 TBasket.cxx:19
 TBasket.cxx:20
 TBasket.cxx:21
 TBasket.cxx:22
 TBasket.cxx:23
 TBasket.cxx:24
 TBasket.cxx:25
 TBasket.cxx:26
 TBasket.cxx:27
 TBasket.cxx:28
 TBasket.cxx:29
 TBasket.cxx:30
 TBasket.cxx:31
 TBasket.cxx:32
 TBasket.cxx:33
 TBasket.cxx:34
 TBasket.cxx:35
 TBasket.cxx:36
 TBasket.cxx:37
 TBasket.cxx:38
 TBasket.cxx:39
 TBasket.cxx:40
 TBasket.cxx:41
 TBasket.cxx:42
 TBasket.cxx:43
 TBasket.cxx:44
 TBasket.cxx:45
 TBasket.cxx:46
 TBasket.cxx:47
 TBasket.cxx:48
 TBasket.cxx:49
 TBasket.cxx:50
 TBasket.cxx:51
 TBasket.cxx:52
 TBasket.cxx:53
 TBasket.cxx:54
 TBasket.cxx:55
 TBasket.cxx:56
 TBasket.cxx:57
 TBasket.cxx:58
 TBasket.cxx:59
 TBasket.cxx:60
 TBasket.cxx:61
 TBasket.cxx:62
 TBasket.cxx:63
 TBasket.cxx:64
 TBasket.cxx:65
 TBasket.cxx:66
 TBasket.cxx:67
 TBasket.cxx:68
 TBasket.cxx:69
 TBasket.cxx:70
 TBasket.cxx:71
 TBasket.cxx:72
 TBasket.cxx:73
 TBasket.cxx:74
 TBasket.cxx:75
 TBasket.cxx:76
 TBasket.cxx:77
 TBasket.cxx:78
 TBasket.cxx:79
 TBasket.cxx:80
 TBasket.cxx:81
 TBasket.cxx:82
 TBasket.cxx:83
 TBasket.cxx:84
 TBasket.cxx:85
 TBasket.cxx:86
 TBasket.cxx:87
 TBasket.cxx:88
 TBasket.cxx:89
 TBasket.cxx:90
 TBasket.cxx:91
 TBasket.cxx:92
 TBasket.cxx:93
 TBasket.cxx:94
 TBasket.cxx:95
 TBasket.cxx:96
 TBasket.cxx:97
 TBasket.cxx:98
 TBasket.cxx:99
 TBasket.cxx:100
 TBasket.cxx:101
 TBasket.cxx:102
 TBasket.cxx:103
 TBasket.cxx:104
 TBasket.cxx:105
 TBasket.cxx:106
 TBasket.cxx:107
 TBasket.cxx:108
 TBasket.cxx:109
 TBasket.cxx:110
 TBasket.cxx:111
 TBasket.cxx:112
 TBasket.cxx:113
 TBasket.cxx:114
 TBasket.cxx:115
 TBasket.cxx:116
 TBasket.cxx:117
 TBasket.cxx:118
 TBasket.cxx:119
 TBasket.cxx:120
 TBasket.cxx:121
 TBasket.cxx:122
 TBasket.cxx:123
 TBasket.cxx:124
 TBasket.cxx:125
 TBasket.cxx:126
 TBasket.cxx:127
 TBasket.cxx:128
 TBasket.cxx:129
 TBasket.cxx:130
 TBasket.cxx:131
 TBasket.cxx:132
 TBasket.cxx:133
 TBasket.cxx:134
 TBasket.cxx:135
 TBasket.cxx:136
 TBasket.cxx:137
 TBasket.cxx:138
 TBasket.cxx:139
 TBasket.cxx:140
 TBasket.cxx:141
 TBasket.cxx:142
 TBasket.cxx:143
 TBasket.cxx:144
 TBasket.cxx:145
 TBasket.cxx:146
 TBasket.cxx:147
 TBasket.cxx:148
 TBasket.cxx:149
 TBasket.cxx:150
 TBasket.cxx:151
 TBasket.cxx:152
 TBasket.cxx:153
 TBasket.cxx:154
 TBasket.cxx:155
 TBasket.cxx:156
 TBasket.cxx:157
 TBasket.cxx:158
 TBasket.cxx:159
 TBasket.cxx:160
 TBasket.cxx:161
 TBasket.cxx:162
 TBasket.cxx:163
 TBasket.cxx:164
 TBasket.cxx:165
 TBasket.cxx:166
 TBasket.cxx:167
 TBasket.cxx:168
 TBasket.cxx:169
 TBasket.cxx:170
 TBasket.cxx:171
 TBasket.cxx:172
 TBasket.cxx:173
 TBasket.cxx:174
 TBasket.cxx:175
 TBasket.cxx:176
 TBasket.cxx:177
 TBasket.cxx:178
 TBasket.cxx:179
 TBasket.cxx:180
 TBasket.cxx:181
 TBasket.cxx:182
 TBasket.cxx:183
 TBasket.cxx:184
 TBasket.cxx:185
 TBasket.cxx:186
 TBasket.cxx:187
 TBasket.cxx:188
 TBasket.cxx:189
 TBasket.cxx:190
 TBasket.cxx:191
 TBasket.cxx:192
 TBasket.cxx:193
 TBasket.cxx:194
 TBasket.cxx:195
 TBasket.cxx:196
 TBasket.cxx:197
 TBasket.cxx:198
 TBasket.cxx:199
 TBasket.cxx:200
 TBasket.cxx:201
 TBasket.cxx:202
 TBasket.cxx:203
 TBasket.cxx:204
 TBasket.cxx:205
 TBasket.cxx:206
 TBasket.cxx:207
 TBasket.cxx:208
 TBasket.cxx:209
 TBasket.cxx:210
 TBasket.cxx:211
 TBasket.cxx:212
 TBasket.cxx:213
 TBasket.cxx:214
 TBasket.cxx:215
 TBasket.cxx:216
 TBasket.cxx:217
 TBasket.cxx:218
 TBasket.cxx:219
 TBasket.cxx:220
 TBasket.cxx:221
 TBasket.cxx:222
 TBasket.cxx:223
 TBasket.cxx:224
 TBasket.cxx:225
 TBasket.cxx:226
 TBasket.cxx:227
 TBasket.cxx:228
 TBasket.cxx:229
 TBasket.cxx:230
 TBasket.cxx:231
 TBasket.cxx:232
 TBasket.cxx:233
 TBasket.cxx:234
 TBasket.cxx:235
 TBasket.cxx:236
 TBasket.cxx:237
 TBasket.cxx:238
 TBasket.cxx:239
 TBasket.cxx:240
 TBasket.cxx:241
 TBasket.cxx:242
 TBasket.cxx:243
 TBasket.cxx:244
 TBasket.cxx:245
 TBasket.cxx:246
 TBasket.cxx:247
 TBasket.cxx:248
 TBasket.cxx:249
 TBasket.cxx:250
 TBasket.cxx:251
 TBasket.cxx:252
 TBasket.cxx:253
 TBasket.cxx:254
 TBasket.cxx:255
 TBasket.cxx:256
 TBasket.cxx:257
 TBasket.cxx:258
 TBasket.cxx:259
 TBasket.cxx:260
 TBasket.cxx:261
 TBasket.cxx:262
 TBasket.cxx:263
 TBasket.cxx:264
 TBasket.cxx:265
 TBasket.cxx:266
 TBasket.cxx:267
 TBasket.cxx:268
 TBasket.cxx:269
 TBasket.cxx:270
 TBasket.cxx:271
 TBasket.cxx:272
 TBasket.cxx:273
 TBasket.cxx:274
 TBasket.cxx:275
 TBasket.cxx:276
 TBasket.cxx:277
 TBasket.cxx:278
 TBasket.cxx:279
 TBasket.cxx:280
 TBasket.cxx:281
 TBasket.cxx:282
 TBasket.cxx:283
 TBasket.cxx:284
 TBasket.cxx:285
 TBasket.cxx:286
 TBasket.cxx:287
 TBasket.cxx:288
 TBasket.cxx:289
 TBasket.cxx:290
 TBasket.cxx:291
 TBasket.cxx:292
 TBasket.cxx:293
 TBasket.cxx:294
 TBasket.cxx:295
 TBasket.cxx:296
 TBasket.cxx:297
 TBasket.cxx:298
 TBasket.cxx:299
 TBasket.cxx:300
 TBasket.cxx:301
 TBasket.cxx:302
 TBasket.cxx:303
 TBasket.cxx:304
 TBasket.cxx:305
 TBasket.cxx:306
 TBasket.cxx:307
 TBasket.cxx:308
 TBasket.cxx:309
 TBasket.cxx:310
 TBasket.cxx:311
 TBasket.cxx:312
 TBasket.cxx:313
 TBasket.cxx:314
 TBasket.cxx:315
 TBasket.cxx:316
 TBasket.cxx:317
 TBasket.cxx:318
 TBasket.cxx:319
 TBasket.cxx:320
 TBasket.cxx:321
 TBasket.cxx:322
 TBasket.cxx:323
 TBasket.cxx:324
 TBasket.cxx:325
 TBasket.cxx:326
 TBasket.cxx:327
 TBasket.cxx:328
 TBasket.cxx:329
 TBasket.cxx:330
 TBasket.cxx:331
 TBasket.cxx:332
 TBasket.cxx:333
 TBasket.cxx:334
 TBasket.cxx:335
 TBasket.cxx:336
 TBasket.cxx:337
 TBasket.cxx:338
 TBasket.cxx:339
 TBasket.cxx:340
 TBasket.cxx:341
 TBasket.cxx:342
 TBasket.cxx:343
 TBasket.cxx:344
 TBasket.cxx:345
 TBasket.cxx:346
 TBasket.cxx:347
 TBasket.cxx:348
 TBasket.cxx:349
 TBasket.cxx:350
 TBasket.cxx:351
 TBasket.cxx:352
 TBasket.cxx:353
 TBasket.cxx:354
 TBasket.cxx:355
 TBasket.cxx:356
 TBasket.cxx:357
 TBasket.cxx:358
 TBasket.cxx:359
 TBasket.cxx:360
 TBasket.cxx:361
 TBasket.cxx:362
 TBasket.cxx:363
 TBasket.cxx:364
 TBasket.cxx:365
 TBasket.cxx:366
 TBasket.cxx:367
 TBasket.cxx:368
 TBasket.cxx:369
 TBasket.cxx:370
 TBasket.cxx:371
 TBasket.cxx:372
 TBasket.cxx:373
 TBasket.cxx:374
 TBasket.cxx:375
 TBasket.cxx:376
 TBasket.cxx:377
 TBasket.cxx:378
 TBasket.cxx:379
 TBasket.cxx:380
 TBasket.cxx:381
 TBasket.cxx:382
 TBasket.cxx:383
 TBasket.cxx:384
 TBasket.cxx:385
 TBasket.cxx:386
 TBasket.cxx:387
 TBasket.cxx:388
 TBasket.cxx:389
 TBasket.cxx:390
 TBasket.cxx:391
 TBasket.cxx:392
 TBasket.cxx:393
 TBasket.cxx:394
 TBasket.cxx:395
 TBasket.cxx:396
 TBasket.cxx:397
 TBasket.cxx:398
 TBasket.cxx:399
 TBasket.cxx:400
 TBasket.cxx:401
 TBasket.cxx:402
 TBasket.cxx:403
 TBasket.cxx:404
 TBasket.cxx:405
 TBasket.cxx:406
 TBasket.cxx:407
 TBasket.cxx:408
 TBasket.cxx:409
 TBasket.cxx:410
 TBasket.cxx:411
 TBasket.cxx:412
 TBasket.cxx:413
 TBasket.cxx:414
 TBasket.cxx:415
 TBasket.cxx:416
 TBasket.cxx:417
 TBasket.cxx:418
 TBasket.cxx:419
 TBasket.cxx:420
 TBasket.cxx:421
 TBasket.cxx:422
 TBasket.cxx:423
 TBasket.cxx:424
 TBasket.cxx:425
 TBasket.cxx:426
 TBasket.cxx:427
 TBasket.cxx:428
 TBasket.cxx:429
 TBasket.cxx:430
 TBasket.cxx:431
 TBasket.cxx:432
 TBasket.cxx:433
 TBasket.cxx:434
 TBasket.cxx:435
 TBasket.cxx:436
 TBasket.cxx:437
 TBasket.cxx:438
 TBasket.cxx:439
 TBasket.cxx:440
 TBasket.cxx:441
 TBasket.cxx:442
 TBasket.cxx:443
 TBasket.cxx:444
 TBasket.cxx:445
 TBasket.cxx:446
 TBasket.cxx:447
 TBasket.cxx:448
 TBasket.cxx:449
 TBasket.cxx:450
 TBasket.cxx:451
 TBasket.cxx:452
 TBasket.cxx:453
 TBasket.cxx:454
 TBasket.cxx:455
 TBasket.cxx:456
 TBasket.cxx:457
 TBasket.cxx:458
 TBasket.cxx:459
 TBasket.cxx:460
 TBasket.cxx:461
 TBasket.cxx:462
 TBasket.cxx:463
 TBasket.cxx:464
 TBasket.cxx:465
 TBasket.cxx:466
 TBasket.cxx:467
 TBasket.cxx:468
 TBasket.cxx:469
 TBasket.cxx:470
 TBasket.cxx:471
 TBasket.cxx:472
 TBasket.cxx:473
 TBasket.cxx:474
 TBasket.cxx:475
 TBasket.cxx:476
 TBasket.cxx:477
 TBasket.cxx:478
 TBasket.cxx:479
 TBasket.cxx:480
 TBasket.cxx:481
 TBasket.cxx:482
 TBasket.cxx:483
 TBasket.cxx:484
 TBasket.cxx:485
 TBasket.cxx:486
 TBasket.cxx:487
 TBasket.cxx:488
 TBasket.cxx:489
 TBasket.cxx:490
 TBasket.cxx:491
 TBasket.cxx:492
 TBasket.cxx:493
 TBasket.cxx:494
 TBasket.cxx:495
 TBasket.cxx:496
 TBasket.cxx:497
 TBasket.cxx:498
 TBasket.cxx:499
 TBasket.cxx:500
 TBasket.cxx:501
 TBasket.cxx:502
 TBasket.cxx:503
 TBasket.cxx:504
 TBasket.cxx:505
 TBasket.cxx:506
 TBasket.cxx:507
 TBasket.cxx:508
 TBasket.cxx:509
 TBasket.cxx:510
 TBasket.cxx:511
 TBasket.cxx:512
 TBasket.cxx:513
 TBasket.cxx:514
 TBasket.cxx:515
 TBasket.cxx:516
 TBasket.cxx:517
 TBasket.cxx:518
 TBasket.cxx:519
 TBasket.cxx:520
 TBasket.cxx:521
 TBasket.cxx:522
 TBasket.cxx:523
 TBasket.cxx:524
 TBasket.cxx:525
 TBasket.cxx:526
 TBasket.cxx:527
 TBasket.cxx:528
 TBasket.cxx:529
 TBasket.cxx:530
 TBasket.cxx:531
 TBasket.cxx:532
 TBasket.cxx:533
 TBasket.cxx:534
 TBasket.cxx:535
 TBasket.cxx:536
 TBasket.cxx:537
 TBasket.cxx:538
 TBasket.cxx:539
 TBasket.cxx:540
 TBasket.cxx:541
 TBasket.cxx:542
 TBasket.cxx:543
 TBasket.cxx:544
 TBasket.cxx:545
 TBasket.cxx:546
 TBasket.cxx:547
 TBasket.cxx:548
 TBasket.cxx:549
 TBasket.cxx:550
 TBasket.cxx:551
 TBasket.cxx:552
 TBasket.cxx:553
 TBasket.cxx:554
 TBasket.cxx:555
 TBasket.cxx:556
 TBasket.cxx:557
 TBasket.cxx:558
 TBasket.cxx:559
 TBasket.cxx:560
 TBasket.cxx:561
 TBasket.cxx:562
 TBasket.cxx:563
 TBasket.cxx:564
 TBasket.cxx:565
 TBasket.cxx:566
 TBasket.cxx:567
 TBasket.cxx:568
 TBasket.cxx:569
 TBasket.cxx:570
 TBasket.cxx:571
 TBasket.cxx:572
 TBasket.cxx:573
 TBasket.cxx:574
 TBasket.cxx:575
 TBasket.cxx:576
 TBasket.cxx:577
 TBasket.cxx:578
 TBasket.cxx:579
 TBasket.cxx:580
 TBasket.cxx:581
 TBasket.cxx:582
 TBasket.cxx:583
 TBasket.cxx:584
 TBasket.cxx:585
 TBasket.cxx:586
 TBasket.cxx:587
 TBasket.cxx:588
 TBasket.cxx:589
 TBasket.cxx:590
 TBasket.cxx:591
 TBasket.cxx:592
 TBasket.cxx:593
 TBasket.cxx:594
 TBasket.cxx:595
 TBasket.cxx:596
 TBasket.cxx:597
 TBasket.cxx:598
 TBasket.cxx:599
 TBasket.cxx:600
 TBasket.cxx:601
 TBasket.cxx:602
 TBasket.cxx:603
 TBasket.cxx:604
 TBasket.cxx:605
 TBasket.cxx:606
 TBasket.cxx:607
 TBasket.cxx:608
 TBasket.cxx:609
 TBasket.cxx:610
 TBasket.cxx:611
 TBasket.cxx:612
 TBasket.cxx:613
 TBasket.cxx:614
 TBasket.cxx:615
 TBasket.cxx:616
 TBasket.cxx:617
 TBasket.cxx:618
 TBasket.cxx:619
 TBasket.cxx:620
 TBasket.cxx:621
 TBasket.cxx:622
 TBasket.cxx:623
 TBasket.cxx:624
 TBasket.cxx:625
 TBasket.cxx:626
 TBasket.cxx:627
 TBasket.cxx:628
 TBasket.cxx:629
 TBasket.cxx:630
 TBasket.cxx:631
 TBasket.cxx:632
 TBasket.cxx:633
 TBasket.cxx:634
 TBasket.cxx:635
 TBasket.cxx:636
 TBasket.cxx:637
 TBasket.cxx:638
 TBasket.cxx:639
 TBasket.cxx:640
 TBasket.cxx:641
 TBasket.cxx:642
 TBasket.cxx:643
 TBasket.cxx:644
 TBasket.cxx:645
 TBasket.cxx:646
 TBasket.cxx:647
 TBasket.cxx:648
 TBasket.cxx:649
 TBasket.cxx:650
 TBasket.cxx:651
 TBasket.cxx:652
 TBasket.cxx:653
 TBasket.cxx:654
 TBasket.cxx:655
 TBasket.cxx:656
 TBasket.cxx:657
 TBasket.cxx:658
 TBasket.cxx:659
 TBasket.cxx:660
 TBasket.cxx:661
 TBasket.cxx:662
 TBasket.cxx:663
 TBasket.cxx:664
 TBasket.cxx:665
 TBasket.cxx:666
 TBasket.cxx:667
 TBasket.cxx:668
 TBasket.cxx:669
 TBasket.cxx:670
 TBasket.cxx:671
 TBasket.cxx:672
 TBasket.cxx:673
 TBasket.cxx:674
 TBasket.cxx:675
 TBasket.cxx:676
 TBasket.cxx:677
 TBasket.cxx:678
 TBasket.cxx:679
 TBasket.cxx:680
 TBasket.cxx:681
 TBasket.cxx:682
 TBasket.cxx:683
 TBasket.cxx:684
 TBasket.cxx:685
 TBasket.cxx:686
 TBasket.cxx:687
 TBasket.cxx:688
 TBasket.cxx:689
 TBasket.cxx:690
 TBasket.cxx:691
 TBasket.cxx:692
 TBasket.cxx:693
 TBasket.cxx:694
 TBasket.cxx:695
 TBasket.cxx:696
 TBasket.cxx:697
 TBasket.cxx:698
 TBasket.cxx:699
 TBasket.cxx:700
 TBasket.cxx:701
 TBasket.cxx:702
 TBasket.cxx:703
 TBasket.cxx:704
 TBasket.cxx:705
 TBasket.cxx:706
 TBasket.cxx:707
 TBasket.cxx:708
 TBasket.cxx:709
 TBasket.cxx:710
 TBasket.cxx:711
 TBasket.cxx:712
 TBasket.cxx:713
 TBasket.cxx:714
 TBasket.cxx:715
 TBasket.cxx:716
 TBasket.cxx:717
 TBasket.cxx:718
 TBasket.cxx:719
 TBasket.cxx:720
 TBasket.cxx:721
 TBasket.cxx:722
 TBasket.cxx:723