TKey.cxx

Go to the documentation of this file.
00001 // @(#)root/io:$Id: TKey.cxx 37986 2011-02-04 21:42:15Z pcanal $
00002 // Author: Rene Brun   28/12/94
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 //  The TKey class includes functions to book space in a file,          //
00015 //   to create I/O buffers, to fill these buffers,                      //
00016 //   to compress/uncompress data buffers.                               //
00017 //                                                                      //
00018 //  Before saving (making persistent) an object in a file, a key must   //
00019 //  be created. The key structure contains all the information to       //
00020 //  uniquely identify a persistent object in a file.                    //
00021 //     fNbytes    = Number of bytes for the compressed object+key       //
00022 //     fObjlen    = Length of uncompressed object                       //
00023 //     fDatime    = Date/Time when the object was written               //
00024 //     fKeylen    = Number of bytes for the key structure               //
00025 //     fCycle     = Cycle number of the object                          //
00026 //     fSeekKey   = Address of the object on file (points to fNbytes)   //
00027 //                  This is a redundant information used to cross-check //
00028 //                  the data base integrity.                            //
00029 //     fSeekPdir  = Pointer to the directory supporting this object     //
00030 //     fClassName = Object class name                                   //
00031 //     fName      = Name of the object                                  //
00032 //     fTitle     = Title of the object                                 //
00033 //                                                                      //
00034 //  In the 16 highest bits of fSeekPdir is encoded a pid offset.  This  //
00035 //  offset is to be added to the pid index stored in the TRef object    //
00036 //  and the referenced TObject.                                         //
00037 //                                                                      //
00038 //  The TKey class is used by ROOT to:                                  //
00039 //    - to write an object in the current directory                     //
00040 //    - to write a new ntuple buffer                                    //
00041 //                                                                      //
00042 //  The structure of a file is shown in TFile::TFile.                   //
00043 //  The structure of a directory is shown in TDirectoryFile ctor.       //
00044 //  The TKey class is used by the TBasket class.                        //
00045 //  See also TTree.                                                     //
00046 //                                                                      //
00047 //////////////////////////////////////////////////////////////////////////
00048 
00049 #include "Riostream.h"
00050 #include "TROOT.h"
00051 #include "TClass.h"
00052 #include "TDirectoryFile.h"
00053 #include "TFile.h"
00054 #include "TKey.h"
00055 #include "TBufferFile.h"
00056 #include "TFree.h"
00057 #include "TBrowser.h"
00058 #include "Bytes.h"
00059 #include "TInterpreter.h"
00060 #include "TError.h"
00061 #include "TVirtualStreamerInfo.h"
00062 #include "TSchemaRuleSet.h"
00063 
00064 extern "C" void R__zip (Int_t cxlevel, Int_t *nin, char *bufin, Int_t *lout, char *bufout, Int_t *nout);
00065 extern "C" void R__unzip(Int_t *nin, UChar_t *bufin, Int_t *lout, char *bufout, Int_t *nout);
00066 extern "C" int R__unzip_header(Int_t *nin, UChar_t *bufin, Int_t *lout);
00067 const Int_t kMAXBUF = 0xffffff;
00068 const Int_t kTitleMax = 32000;
00069 #if 0
00070 const Int_t kMAXFILEBUFFER = 262144;
00071 #endif
00072 
00073 #if !defined(_MSC_VER) || (_MSC_VER>1300)
00074 const ULong64_t kPidOffsetMask = 0xffffffffffffULL;
00075 #else
00076 const ULong64_t kPidOffsetMask = 0xffffffffffffUL;
00077 #endif
00078 const UChar_t kPidOffsetShift = 48;
00079 
00080 UInt_t keyAbsNumber = 0;
00081 
00082 ClassImp(TKey)
00083 
00084 //______________________________________________________________________________
00085 TKey::TKey() : TNamed(), fDatime((UInt_t)0)
00086 {
00087    // TKey default constructor.
00088 
00089    Build(0, "", 0);
00090 
00091    fKeylen     = Sizeof();
00092 
00093    keyAbsNumber++; SetUniqueID(keyAbsNumber);
00094 }
00095 
00096 //______________________________________________________________________________
00097 TKey::TKey(TDirectory* motherDir) : TNamed(), fDatime((UInt_t)0)
00098 {
00099    // TKey default constructor.
00100 
00101    Build(motherDir, "", 0);
00102 
00103    fKeylen     = Sizeof();
00104 
00105    keyAbsNumber++; SetUniqueID(keyAbsNumber);
00106 }
00107 
00108 //______________________________________________________________________________
00109 TKey::TKey(Long64_t pointer, Int_t nbytes, TDirectory* motherDir) : TNamed()
00110 {
00111    // Create a TKey object to read keys.
00112    // Constructor called by TDirectoryFile::ReadKeys and by TFile::TFile.
00113    // A TKey object is created to read the keys structure itself.
00114 
00115    Build(motherDir, "", pointer);
00116 
00117    fSeekKey    = pointer;
00118    fNbytes     = nbytes;
00119    fBuffer     = new char[nbytes];
00120    keyAbsNumber++; SetUniqueID(keyAbsNumber);
00121 }
00122 
00123 //______________________________________________________________________________
00124 TKey::TKey(const char *name, const char *title, const TClass *cl, Int_t nbytes, TDirectory* motherDir)
00125       : TNamed(name,title)
00126 {
00127    // Create a TKey object with the specified name, title for the given class.
00128    //
00129    //  WARNING: in name avoid special characters like '^','$','.' that are used 
00130    //  by the regular expression parser (see TRegexp).
00131 
00132    Build(motherDir, cl->GetName(), -1);
00133 
00134    fKeylen     = Sizeof();
00135    fObjlen     = nbytes;
00136    Create(nbytes);
00137 }
00138 
00139 //______________________________________________________________________________
00140 TKey::TKey(const TString &name, const TString &title, const TClass *cl, Int_t nbytes, TDirectory* motherDir)
00141       : TNamed(name,title)
00142 {
00143    // Create a TKey object with the specified name, title for the given class.
00144    //
00145    //  WARNING: in name avoid special characters like '^','$','.' that are used 
00146    //  by the regular expression parser (see TRegexp).
00147 
00148    Build(motherDir, cl->GetName(), -1);
00149 
00150    fKeylen     = Sizeof();
00151    fObjlen     = nbytes;
00152    Create(nbytes);
00153 }
00154 
00155 //______________________________________________________________________________
00156 TKey::TKey(const TObject *obj, const char *name, Int_t bufsize, TDirectory* motherDir)
00157      : TNamed(name, obj->GetTitle())
00158 {
00159    // Create a TKey object for a TObject* and fill output buffer
00160    //
00161    //  WARNING: in name avoid special characters like '^','$','.' that are used 
00162    //  by the regular expression parser (see TRegexp).
00163 
00164    R__ASSERT(obj);
00165 
00166    if (!obj->IsA()->HasDefaultConstructor()) {
00167       Warning("TKey", "since %s has no public constructor\n"
00168               "\twhich can be called without argument, objects of this class\n"
00169               "\tcan not be read with the current library. You will need to\n"
00170               "\tadd a default constructor before attempting to read it.",
00171               obj->ClassName());
00172    }
00173 
00174    Build(motherDir, obj->ClassName(), -1);
00175 
00176    Int_t lbuf, nout, noutot, bufmax, nzip;
00177    fBufferRef = new TBufferFile(TBuffer::kWrite, bufsize);
00178    fBufferRef->SetParent(GetFile());
00179    fCycle     = fMotherDir->AppendKey(this);
00180 
00181    Streamer(*fBufferRef);         //write key itself
00182    fKeylen    = fBufferRef->Length();
00183    fBufferRef->MapObject(obj);    //register obj in map in case of self reference
00184    ((TObject*)obj)->Streamer(*fBufferRef);    //write object
00185    lbuf       = fBufferRef->Length();
00186    fObjlen    = lbuf - fKeylen;
00187 
00188    Int_t cxlevel = GetFile() ? GetFile()->GetCompressionLevel() : 0;
00189    if (cxlevel && fObjlen > 256) {
00190       if (cxlevel == 2) cxlevel--;
00191       Int_t nbuffers = fObjlen/kMAXBUF;
00192       Int_t buflen = TMath::Max(512,fKeylen + fObjlen + 9*nbuffers + 28); //add 28 bytes in case object is placed in a deleted gap
00193       fBuffer = new char[buflen];
00194       char *objbuf = fBufferRef->Buffer() + fKeylen;
00195       char *bufcur = &fBuffer[fKeylen];
00196       noutot = 0;
00197       nzip   = 0;
00198       for (Int_t i=0;i<=nbuffers;i++) {
00199          if (i == nbuffers) bufmax = fObjlen -nzip;
00200          else               bufmax = kMAXBUF;
00201          R__zip(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout);
00202          if (nout == 0 || nout >= fObjlen) { //this happens when the buffer cannot be compressed
00203             fBuffer = fBufferRef->Buffer();
00204             Create(fObjlen);
00205             fBufferRef->SetBufferOffset(0);
00206             Streamer(*fBufferRef);         //write key itself again
00207             return;
00208          }
00209          bufcur += nout;
00210          noutot += nout;
00211          objbuf += kMAXBUF;
00212          nzip   += kMAXBUF;
00213       }
00214       Create(noutot);
00215       fBufferRef->SetBufferOffset(0);
00216       Streamer(*fBufferRef);         //write key itself again
00217       memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
00218       delete fBufferRef; fBufferRef = 0;
00219    } else {
00220       fBuffer = fBufferRef->Buffer();
00221       Create(fObjlen);
00222       fBufferRef->SetBufferOffset(0);
00223       Streamer(*fBufferRef);         //write key itself again
00224    }
00225 }
00226 
00227 //______________________________________________________________________________
00228 TKey::TKey(const void *obj, const TClass *cl, const char *name, Int_t bufsize, TDirectory* motherDir)
00229      : TNamed(name, "object title")
00230 {
00231    // Create a TKey object for any object obj of class cl d and fill
00232    // output buffer.
00233    //
00234    //  WARNING: in name avoid special characters like '^','$','.' that are used 
00235    //  by the regular expression parser (see TRegexp).
00236 
00237    R__ASSERT(obj && cl);
00238 
00239    if (!cl->HasDefaultConstructor()) {
00240       Warning("TKey", "since %s has no public constructor\n"
00241               "\twhich can be called without argument, objects of this class\n"
00242               "\tcan not be read with the current library. You will need to\n"
00243               "\tadd a default constructor before attempting to read it.",
00244               cl->GetName());
00245    }
00246 
00247    TClass *clActual = cl->GetActualClass(obj);
00248    const void* actualStart;
00249    if (clActual) {
00250       const char *temp = (const char*) obj;
00251       // clActual->GetStreamerInfo();
00252       Int_t offset = (cl != clActual) ?
00253                      clActual->GetBaseClassOffset(cl) : 0;
00254       temp -= offset;
00255       actualStart = temp;
00256    } else {
00257       // We could not determine the real type of this object,
00258       // let's assume it is the one given by the caller.
00259       clActual = const_cast<TClass*>(cl);
00260       actualStart = obj;
00261    }
00262 
00263    Build(motherDir, clActual->GetName(), -1);
00264 
00265    fBufferRef = new TBufferFile(TBuffer::kWrite, bufsize);
00266    fBufferRef->SetParent(GetFile());
00267    fCycle     = fMotherDir->AppendKey(this);
00268 
00269    Streamer(*fBufferRef);         //write key itself
00270    fKeylen    = fBufferRef->Length();
00271 
00272    Int_t lbuf, nout, noutot, bufmax, nzip;
00273 
00274    fBufferRef->MapObject(actualStart,clActual);         //register obj in map in case of self reference
00275    clActual->Streamer((void*)actualStart, *fBufferRef); //write object
00276    lbuf       = fBufferRef->Length();
00277    fObjlen    = lbuf - fKeylen;
00278 
00279    Int_t cxlevel = GetFile() ? GetFile()->GetCompressionLevel() : 0;
00280    if (cxlevel && fObjlen > 256) {
00281       if (cxlevel == 2) cxlevel--;
00282       Int_t nbuffers = fObjlen/kMAXBUF;
00283       Int_t buflen = TMath::Max(512,fKeylen + fObjlen + 9*nbuffers + 28); //add 28 bytes in case object is placed in a deleted gap
00284       fBuffer = new char[buflen];
00285       char *objbuf = fBufferRef->Buffer() + fKeylen;
00286       char *bufcur = &fBuffer[fKeylen];
00287       noutot = 0;
00288       nzip   = 0;
00289       for (Int_t i=0;i<=nbuffers;i++) {
00290          if (i == nbuffers) bufmax = fObjlen -nzip;
00291          else               bufmax = kMAXBUF;
00292          R__zip(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout);
00293          if (nout == 0 || nout >= fObjlen) { //this happens when the buffer cannot be compressed
00294             fBuffer = fBufferRef->Buffer();
00295             Create(fObjlen);
00296             fBufferRef->SetBufferOffset(0);
00297             Streamer(*fBufferRef);         //write key itself again
00298             return;
00299          }
00300          bufcur += nout;
00301          noutot += nout;
00302          objbuf += kMAXBUF;
00303          nzip   += kMAXBUF;
00304       }
00305       Create(noutot);
00306       fBufferRef->SetBufferOffset(0);
00307       Streamer(*fBufferRef);         //write key itself again
00308       memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
00309       delete fBufferRef; fBufferRef = 0;
00310    } else {
00311       fBuffer = fBufferRef->Buffer();
00312       Create(fObjlen);
00313       fBufferRef->SetBufferOffset(0);
00314       Streamer(*fBufferRef);         //write key itself again
00315    }
00316 }
00317 
00318 //______________________________________________________________________________
00319 void TKey::Build(TDirectory* motherDir, const char* classname, Long64_t filepos)
00320 {
00321    // method used in all TKey constructor to initialize basic data fields
00322    // filepos is used to calculate correct version number of key
00323    // if filepos==-1, end of file position is used
00324 
00325    fMotherDir = motherDir;
00326 
00327    fPidOffset  = 0;
00328    fNbytes     = 0;
00329    fBuffer     = 0;
00330    fKeylen     = 0;
00331    fObjlen     = 0;
00332    fBufferRef  = 0;
00333    fCycle      = 0;
00334    fSeekPdir   = 0;
00335    fSeekKey    = 0;
00336    fLeft       = 0;
00337 
00338    fClassName = classname;
00339    //the following test required for forward and backward compatibility
00340    if (fClassName == "TDirectoryFile") fClassName = "TDirectory";
00341 
00342    fVersion = TKey::Class_Version();
00343 
00344    if ((filepos==-1) && GetFile()) filepos = GetFile()->GetEND();
00345    if (filepos > TFile::kStartBigFile) fVersion += 1000;
00346 
00347    if (fTitle.Length() > kTitleMax) fTitle.Resize(kTitleMax);
00348 }
00349 
00350 //______________________________________________________________________________
00351 void TKey::Browse(TBrowser *b)
00352 {
00353    // Read object from disk and call its Browse() method.
00354    // If object with same name already exist in memory delete it (like
00355    // TDirectoryFile::Get() is doing), except when the key references a
00356    // folder in which case we don't want to re-read the folder object
00357    // since it might contain new objects not yet saved.
00358 
00359    if (fMotherDir==0) return;
00360 
00361    TClass *objcl = TClass::GetClass(GetClassName());
00362 
00363    void* obj = fMotherDir->GetList()->FindObject(GetName());
00364    if (obj && objcl->InheritsFrom(TObject::Class())) {
00365       TObject *tobj = (TObject*)obj;
00366       if (!tobj->IsFolder()) {
00367          if (tobj->InheritsFrom(TCollection::Class()))
00368             tobj->Delete();   // delete also collection elements
00369          delete tobj;
00370          obj = 0;
00371       }
00372    } 
00373 
00374    if (!obj)
00375       obj = ReadObj();
00376 
00377    if (b && obj) {
00378       objcl->Browse(obj,b);
00379       b->SetRefreshFlag(kTRUE);
00380    }
00381 }
00382 
00383 //______________________________________________________________________________
00384 void TKey::Create(Int_t nbytes, TFile* externFile)
00385 {
00386    // Create a TKey object of specified size
00387    // if externFile!=0, key will be allocated in specified file,
00388    // otherwise file of mother directory will be used
00389 
00390    keyAbsNumber++; SetUniqueID(keyAbsNumber);
00391 
00392    TFile *f = externFile;
00393    if (!f) f = GetFile();
00394    if (!f) {
00395       Error("Create","Cannot create key without file");
00396       return;
00397    }
00398 
00399    Int_t nsize      = nbytes + fKeylen;
00400    TList *lfree     = f->GetListOfFree();
00401    TFree *f1        = (TFree*)lfree->First();
00402 //*-*-------------------find free segment
00403 //*-*                    =================
00404    TFree *bestfree  = f1->GetBestFree(lfree,nsize);
00405    if (bestfree == 0) {
00406       Error("Create","Cannot allocate %d bytes for ID = %s Title = %s",
00407             nsize,GetName(),GetTitle());
00408       return;
00409    }
00410    fDatime.Set();
00411    fSeekKey  = bestfree->GetFirst();
00412 //*-*----------------- Case Add at the end of the file
00413    if (fSeekKey >= f->GetEND()) {
00414       f->SetEND(fSeekKey+nsize);
00415       bestfree->SetFirst(fSeekKey+nsize);
00416       fLeft   = -1;
00417       if (!fBuffer) fBuffer = new char[nsize];
00418    } else {
00419       fLeft = Int_t(bestfree->GetLast() - fSeekKey - nsize + 1);
00420    }
00421 //*-*----------------- Case where new object fills exactly a deleted gap
00422    fNbytes = nsize;
00423    if (fLeft == 0) {
00424       if (!fBuffer) {
00425          fBuffer = new char[nsize];
00426       }
00427       lfree->Remove(bestfree);
00428       delete bestfree;
00429    }
00430 //*-*----------------- Case where new object is placed in a deleted gap larger than itself
00431    if (fLeft > 0) {    // found a bigger segment
00432       if (!fBuffer) {
00433          fBuffer = new char[nsize+sizeof(Int_t)];
00434       }
00435       char *buffer  = fBuffer+nsize;
00436       Int_t nbytesleft = -fLeft;  // set header of remaining record
00437       tobuf(buffer, nbytesleft);
00438       bestfree->SetFirst(fSeekKey+nsize);
00439    }
00440 
00441    fSeekPdir = externFile ? externFile->GetSeekDir() : fMotherDir->GetSeekDir();
00442 }
00443 
00444 //______________________________________________________________________________
00445 TKey::~TKey()
00446 {
00447    // TKey default destructor.
00448 
00449    //   delete [] fBuffer; fBuffer = 0;
00450    //   delete fBufferRef; fBufferRef = 0;
00451 
00452    DeleteBuffer();
00453 }
00454 
00455 //______________________________________________________________________________
00456 void TKey::Delete(Option_t *option)
00457 {
00458    // Delete an object from the file.
00459    // Note: the key is not deleted. You still have to call "delete key".
00460    // This is different from the behaviour of TObject::Delete()!
00461 
00462    if (option && option[0] == 'v') printf("Deleting key: %s at address %lld, nbytes = %d\n",GetName(),fSeekKey,fNbytes);
00463    Long64_t first = fSeekKey;
00464    Long64_t last  = fSeekKey + fNbytes -1;
00465    if (GetFile()) GetFile()->MakeFree(first, last);  // release space used by this key
00466    fMotherDir->GetListOfKeys()->Remove(this);
00467 }
00468 
00469 //______________________________________________________________________________
00470 void TKey::DeleteBuffer()
00471 {
00472    // Delete key buffer(s).
00473 
00474    if (fBufferRef) {
00475       delete fBufferRef;
00476       fBufferRef = 0;
00477    } else {
00478       // We only need to delete fBuffer if fBufferRef is zero because
00479       // if fBufferRef exists, we delegate ownership of fBuffer to fBufferRef.
00480       if (fBuffer) {
00481          delete [] fBuffer;
00482       }
00483    }
00484    fBuffer = 0;
00485 }
00486 
00487 //______________________________________________________________________________
00488 Short_t TKey::GetCycle() const
00489 {
00490    // Return cycle number associated to this key.
00491 
00492    return ((fCycle >0) ? fCycle : -fCycle);
00493 }
00494 
00495 //______________________________________________________________________________
00496 TFile *TKey::GetFile() const
00497 {
00498    // Returns file to which key belong
00499 
00500    return fMotherDir!=0 ? fMotherDir->GetFile() : gFile;
00501 }
00502 
00503 //______________________________________________________________________________
00504 Short_t TKey::GetKeep() const
00505 {
00506    // Returns the "KEEP" status.
00507 
00508    return ((fCycle >0) ? 0 : 1);
00509 }
00510 
00511 //______________________________________________________________________________
00512 void TKey::FillBuffer(char *&buffer)
00513 {
00514    // Encode key header into output buffer.
00515 
00516    tobuf(buffer, fNbytes);
00517    Version_t version = fVersion;
00518    tobuf(buffer, version);
00519 
00520    tobuf(buffer, fObjlen);
00521    fDatime.FillBuffer(buffer);
00522    tobuf(buffer, fKeylen);
00523    tobuf(buffer, fCycle);
00524    if (fVersion > 1000) {
00525       tobuf(buffer, fSeekKey);
00526 
00527       // We currently store in the 16 highest bit of fSeekPdir the value of
00528       // fPidOffset.  This offset is used when a key (or basket) is transfered from one
00529       // file to the other.  In this case the TRef and TObject might have stored a
00530       // pid index (to retrieve TProcessIDs) which refered to their order on the original
00531       // file, the fPidOffset is to be added to those values to correctly find the
00532       // TProcessID.  This fPidOffset needs to be increment if the key/basket is copied
00533       // and need to be zero for new key/basket.
00534       Long64_t pdir = (((Long64_t)fPidOffset)<<kPidOffsetShift) | (kPidOffsetMask & fSeekPdir);
00535       tobuf(buffer, pdir);
00536    } else {
00537       tobuf(buffer, (Int_t)fSeekKey);
00538       tobuf(buffer, (Int_t)fSeekPdir);
00539    }
00540    fClassName.FillBuffer(buffer);
00541    fName.FillBuffer(buffer);
00542    fTitle.FillBuffer(buffer);
00543 }
00544 
00545 //______________________________________________________________________________
00546 ULong_t TKey::Hash() const
00547 {
00548    // This Hash function should redefine the default from TNamed.
00549 
00550    return TNamed::Hash();
00551 }
00552 
00553 //______________________________________________________________________________
00554 void TKey::IncrementPidOffset(UShort_t offset)
00555 {
00556    // Increment fPidOffset by 'offset'.
00557    // This offset is used when a key (or basket) is transfered from one file to
00558    // the other.  In this case the TRef and TObject might have stored a pid
00559    // index (to retrieve TProcessIDs) which refered to their order on the
00560    // original file, the fPidOffset is to be added to those values to correctly
00561    // find the TProcessID.  This fPidOffset needs to be increment if the
00562    // key/basket is copied and need to be zero for new key/basket.
00563 
00564    fPidOffset += offset;
00565    if (fPidOffset) {
00566       // We currently store fPidOffset in the 16 highest bit of fSeekPdir, which
00567       // need to be store as a 64 bit integer.  So we require this key to be
00568       // a 'large file' key.
00569       if (fVersion<1000) fVersion += 1000;
00570    }
00571 }
00572 
00573 //______________________________________________________________________________
00574 Bool_t TKey::IsFolder() const
00575 {
00576    // Check if object referenced by the key is a folder.
00577 
00578    Bool_t ret = kFALSE;
00579 
00580    TClass *classPtr = TClass::GetClass((const char *) fClassName);
00581    if (classPtr && classPtr->GetClassInfo() && classPtr->InheritsFrom(TObject::Class())) {
00582       TObject *obj = (TObject *) classPtr->New(TClass::kDummyNew);
00583       if (obj) {
00584          ret = obj->IsFolder();
00585          delete obj;
00586       }
00587    }
00588 
00589    return ret;
00590 }
00591 
00592 //______________________________________________________________________________
00593 void TKey::Keep()
00594 {
00595    // Set the "KEEP" status.
00596    // When the KEEP flag is set to 1 the object cannot be purged.
00597 
00598    if (fCycle >0)  fCycle = -fCycle;
00599 }
00600 
00601 //______________________________________________________________________________
00602 void TKey::ls(Option_t *) const
00603 {
00604    // List Key contents.
00605 
00606    TROOT::IndentLevel();
00607    cout <<"KEY: "<<fClassName<<"\t"<<GetName()<<";"<<GetCycle()<<"\t"<<GetTitle()<<endl;
00608 }
00609 
00610 //______________________________________________________________________________
00611 void TKey::Print(Option_t *) const
00612 {
00613    // Print key contents.
00614 
00615    printf("TKey Name = %s, Title = %s, Cycle = %d\n",GetName(),GetTitle(),GetCycle());
00616 }
00617 
00618 //______________________________________________________________________________
00619 TObject *TKey::ReadObj()
00620 {
00621    // To read a TObject* from the file.
00622    //
00623    //  The object associated to this key is read from the file into memory
00624    //  Once the key structure is read (via Streamer) the class identifier
00625    //  of the object is known.
00626    //  Using the class identifier we find the TClass object for this class.
00627    //  A TClass object contains a full description (i.e. dictionary) of the
00628    //  associated class. In particular the TClass object can create a new
00629    //  object of the class type it describes. This new object now calls its
00630    //  Streamer function to rebuilt itself.
00631    //
00632    //  see TKey::ReadObjectAny to read any object non-derived from TObject
00633    //
00634    //  NOTE:
00635    //  In case the class of this object derives from TObject but not
00636    //  as a first inheritance, one must cast the return value twice.
00637    //  Example1: Normal case:
00638    //      class MyClass : public TObject, public AnotherClass
00639    //   then on return, one can do:
00640    //    MyClass *obj = (MyClass*)key->ReadObj();
00641    //
00642    //  Example2: Special case:
00643    //      class MyClass : public AnotherClass, public TObject
00644    //   then on return, one must do:
00645    //    MyClass *obj = dynamic_cast<MyClass*>(key->ReadObj());
00646    //
00647    //  Of course, dynamic_cast<> can also be used in the example 1.
00648 
00649    TClass *cl = TClass::GetClass(fClassName.Data());
00650    if (!cl) {
00651       Error("ReadObj", "Unknown class %s", fClassName.Data());
00652       return 0;
00653    }
00654    if (!cl->InheritsFrom(TObject::Class())) {
00655       // in principle user should call TKey::ReadObjectAny!
00656       return (TObject*)ReadObjectAny(0);
00657    }
00658 
00659    fBufferRef = new TBufferFile(TBuffer::kRead, fObjlen+fKeylen);
00660    if (!fBufferRef) {
00661       Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
00662       return 0;
00663    }
00664    if (GetFile()==0) return 0;
00665    fBufferRef->SetParent(GetFile());
00666    fBufferRef->SetPidOffset(fPidOffset);
00667 
00668    if (fObjlen > fNbytes-fKeylen) {
00669       fBuffer = new char[fNbytes];
00670       ReadFile();                    //Read object structure from file
00671       memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
00672    } else {
00673       fBuffer = fBufferRef->Buffer();
00674       ReadFile();                    //Read object structure from file
00675    }
00676 
00677    // get version of key
00678    fBufferRef->SetBufferOffset(sizeof(fNbytes));
00679    Version_t kvers = fBufferRef->ReadVersion();
00680 
00681    fBufferRef->SetBufferOffset(fKeylen);
00682    TObject *tobj = 0;
00683    // Create an instance of this class
00684 
00685    char *pobj = (char*)cl->New();
00686    Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
00687    if (baseOffset==-1) {
00688       // cl does not inherit from TObject.
00689       // Since this is not possible yet, the only reason we could reach this code
00690       // is because something is screw up in the ROOT code.
00691       Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
00692             fClassName.Data());
00693    }
00694    tobj = (TObject*)(pobj+baseOffset);
00695    if (!pobj) {
00696       Error("ReadObj", "Cannot create new object of class %s", fClassName.Data());
00697       return 0;
00698    }
00699    if (kvers > 1)
00700       fBufferRef->MapObject(pobj,cl);  //register obj in map to handle self reference
00701 
00702    if (fObjlen > fNbytes-fKeylen) {
00703       char *objbuf = fBufferRef->Buffer() + fKeylen;
00704       UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
00705       Int_t nin, nout, nbuf;
00706       Int_t noutot = 0;
00707       while (1) {
00708          Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
00709          if (hc!=0) break;
00710          R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
00711          if (!nout) break;
00712          noutot += nout;
00713          if (noutot >= fObjlen) break;
00714          bufcur += nin;
00715          objbuf += nout;
00716       }
00717       if (nout) {
00718          tobj->Streamer(*fBufferRef); //does not work with example 2 above
00719          delete [] fBuffer;
00720       } else {
00721          delete [] fBuffer;
00722          delete pobj;
00723          pobj = 0;
00724          tobj = 0;
00725          goto CLEAR;
00726       }
00727    } else {
00728       tobj->Streamer(*fBufferRef);
00729    }
00730 
00731    if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
00732 
00733    if (cl->InheritsFrom(TDirectoryFile::Class())) {
00734       TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
00735       dir->SetName(GetName());
00736       dir->SetTitle(GetTitle());
00737       dir->SetMother(fMotherDir);
00738       fMotherDir->Append(dir);
00739    }
00740 
00741    // Append the object to the directory if requested:
00742    { 
00743       ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
00744       if (addfunc) {
00745          addfunc(pobj, fMotherDir);
00746       }
00747    }
00748 
00749 CLEAR:
00750    delete fBufferRef;
00751    fBufferRef = 0;
00752    fBuffer    = 0;
00753 
00754    return tobj;
00755 }
00756 
00757 //______________________________________________________________________________
00758 TObject *TKey::ReadObjWithBuffer(char *bufferRead)
00759 {
00760    // To read a TObject* from bufferRead.
00761    // This function is identical to TKey::ReadObj, but it reads directly
00762    // from bufferRead instead of reading from a file.
00763    //  The object associated to this key is read from the buffer into memory
00764    //  Using the class identifier we find the TClass object for this class.
00765    //  A TClass object contains a full description (i.e. dictionary) of the
00766    //  associated class. In particular the TClass object can create a new
00767    //  object of the class type it describes. This new object now calls its
00768    //  Streamer function to rebuilt itself.
00769    //
00770    //  NOTE :
00771    //  This function is called only internally by ROOT classes.
00772    //  Although being public it is not supposed to be used outside ROOT.
00773    //  If used, you must make sure that the bufferRead is large enough to
00774    //  accomodate the object being read.
00775    
00776 
00777    TClass *cl = TClass::GetClass(fClassName.Data());
00778    if (!cl) {
00779       Error("ReadObjWithBuffer", "Unknown class %s", fClassName.Data());
00780       return 0;
00781    }
00782    if (!cl->InheritsFrom(TObject::Class())) {
00783       // in principle user should call TKey::ReadObjectAny!
00784       return (TObject*)ReadObjectAny(0);
00785    }
00786 
00787    fBufferRef = new TBufferFile(TBuffer::kRead, fObjlen+fKeylen);
00788    if (!fBufferRef) {
00789       Error("ReadObjWithBuffer", "Cannot allocate buffer: fObjlen = %d", fObjlen);
00790       return 0;
00791    }
00792    if (GetFile()==0) return 0;
00793    fBufferRef->SetParent(GetFile());
00794    fBufferRef->SetPidOffset(fPidOffset);
00795 
00796    if (fObjlen > fNbytes-fKeylen) {
00797       fBuffer = bufferRead;
00798       memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
00799    } else {
00800       fBuffer = fBufferRef->Buffer();
00801       ReadFile();                    //Read object structure from file
00802    }
00803 
00804    // get version of key
00805    fBufferRef->SetBufferOffset(sizeof(fNbytes));
00806    Version_t kvers = fBufferRef->ReadVersion();
00807 
00808    fBufferRef->SetBufferOffset(fKeylen);
00809    TObject *tobj = 0;
00810    // Create an instance of this class
00811 
00812    char *pobj = (char*)cl->New();
00813    Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
00814    if (baseOffset==-1) {
00815       // cl does not inherit from TObject.
00816       // Since this is not possible yet, the only reason we could reach this code
00817       // is because something is screw up in the ROOT code.
00818       Fatal("ReadObjWithBuffer","Incorrect detection of the inheritance from TObject for class %s.\n",
00819             fClassName.Data());
00820    }
00821    tobj = (TObject*)(pobj+baseOffset);
00822    if (!pobj) {
00823       Error("ReadObjWithBuffer", "Cannot create new object of class %s", fClassName.Data());
00824       return 0;
00825    }
00826    if (kvers > 1)
00827       fBufferRef->MapObject(pobj,cl);  //register obj in map to handle self reference
00828 
00829    if (fObjlen > fNbytes-fKeylen) {
00830       char *objbuf = fBufferRef->Buffer() + fKeylen;
00831       UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
00832       Int_t nin, nout, nbuf;
00833       Int_t noutot = 0;
00834       while (1) {
00835          Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
00836          if (hc!=0) break;
00837          R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
00838          if (!nout) break;
00839          noutot += nout;
00840          if (noutot >= fObjlen) break;
00841          bufcur += nin;
00842          objbuf += nout;
00843       }
00844       if (nout) {
00845          tobj->Streamer(*fBufferRef); //does not work with example 2 above
00846       } else {
00847          delete pobj;
00848          pobj = 0;
00849          tobj = 0;
00850          goto CLEAR;
00851       }
00852    } else {
00853       tobj->Streamer(*fBufferRef);
00854    }
00855 
00856    if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
00857 
00858    if (cl->InheritsFrom(TDirectoryFile::Class())) {
00859       TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
00860       dir->SetName(GetName());
00861       dir->SetTitle(GetTitle());
00862       dir->SetMother(fMotherDir);
00863       fMotherDir->Append(dir);
00864    }
00865 
00866    // Append the object to the directory if requested:
00867    { 
00868       ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
00869       if (addfunc) {
00870          addfunc(pobj, fMotherDir);
00871       }
00872    }
00873 
00874 CLEAR:
00875    delete fBufferRef;
00876    fBufferRef = 0;
00877    fBuffer    = 0;
00878 
00879    return tobj;
00880 }
00881 
00882 //______________________________________________________________________________
00883 void *TKey::ReadObjectAny(const TClass* expectedClass)
00884 {
00885    //  To read an object (non deriving from TObject) from the file.
00886    //
00887    //  If expectedClass is not null, we checked that that actual class of
00888    //  the object stored is suitable to be stored in a pointer pointing
00889    //  to an object of class 'expectedClass'.  We also adjust the value
00890    //  of the returned address so that it is suitable to be cast (C-Style)
00891    //  a  a pointer pointing to an object of class 'expectedClass'.
00892    //
00893    //  So for example if the class Bottom inherits from Top and the object
00894    //  stored is of type Bottom you can safely do:
00895    //
00896    //     TClass *TopClass = TClass::GetClass("Top");
00897    //     Top *ptr = (Top*) key->ReadObjectAny( TopClass );
00898    //     if (ptr==0) printError("the object stored in the key is not of the expected type\n");
00899    //
00900    //  The object associated to this key is read from the file into memory
00901    //  Once the key structure is read (via Streamer) the class identifier
00902    //  of the object is known.
00903    //  Using the class identifier we find the TClass object for this class.
00904    //  A TClass object contains a full description (i.e. dictionary) of the
00905    //  associated class. In particular the TClass object can create a new
00906    //  object of the class type it describes. This new object now calls its
00907    //  Streamer function to rebuilt itself.
00908 
00909    fBufferRef = new TBufferFile(TBuffer::kRead, fObjlen+fKeylen);
00910    if (!fBufferRef) {
00911       Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
00912       return 0;
00913    }
00914    if (GetFile()==0) return 0;
00915    fBufferRef->SetParent(GetFile());
00916    fBufferRef->SetPidOffset(fPidOffset);
00917 
00918    if (fObjlen > fNbytes-fKeylen) {
00919       fBuffer = new char[fNbytes];
00920       ReadFile();                    //Read object structure from file
00921       memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
00922    } else {
00923       fBuffer = fBufferRef->Buffer();
00924       ReadFile();                    //Read object structure from file
00925    }
00926 
00927    // get version of key
00928    fBufferRef->SetBufferOffset(sizeof(fNbytes));
00929    Version_t kvers = fBufferRef->ReadVersion();
00930 
00931    fBufferRef->SetBufferOffset(fKeylen);
00932    TClass *cl = TClass::GetClass(fClassName.Data());
00933    TClass *clOnfile = 0;
00934    if (!cl) {
00935       Error("ReadObjectAny", "Unknown class %s", fClassName.Data());
00936       return 0;
00937    }
00938    Int_t baseOffset = 0;
00939    if (expectedClass) {
00940        // baseOffset will be -1 if cl does not inherit from expectedClass
00941       baseOffset = cl->GetBaseClassOffset(expectedClass);
00942       if (baseOffset == -1) {
00943          // The 2 classes are unrelated, maybe there is a converter between the 2.  
00944 
00945          if (!expectedClass->GetSchemaRules() || 
00946              !expectedClass->GetSchemaRules()->HasRuleWithSourceClass(cl->GetName())) 
00947          {
00948             // There is no converter
00949             return 0;
00950          }
00951          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 ....
00952          clOnfile = cl;
00953          cl = const_cast<TClass*>(expectedClass);
00954          Info("ReadObjectAny","Using Converter StreamerInfo from %s to %s",clOnfile->GetName(),expectedClass->GetName());
00955       }
00956       if (cl->GetClassInfo() && !expectedClass->GetClassInfo()) {
00957          //we cannot mix a compiled class with an emulated class in the inheritance
00958          Warning("ReadObjectAny",
00959                  "Trying to read an emulated class (%s) to store in a compiled pointer (%s)",
00960                  cl->GetName(),expectedClass->GetName());
00961       }
00962    }
00963    // Create an instance of this class
00964 
00965    void *pobj = cl->New();
00966    if (!pobj) {
00967       Error("ReadObjectAny", "Cannot create new object of class %s", fClassName.Data());
00968       return 0;
00969    }
00970 
00971    if (kvers > 1)
00972       fBufferRef->MapObject(pobj,cl);  //register obj in map to handle self reference
00973 
00974    if (fObjlen > fNbytes-fKeylen) {
00975       char *objbuf = fBufferRef->Buffer() + fKeylen;
00976       UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
00977       Int_t nin, nout, nbuf;
00978       Int_t noutot = 0;
00979       while (1) {
00980          Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
00981          if (hc!=0) break;
00982          R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
00983          if (!nout) break;
00984          noutot += nout;
00985          if (noutot >= fObjlen) break;
00986          bufcur += nin;
00987          objbuf += nout;
00988       }
00989       if (nout) {
00990          cl->Streamer((void*)pobj, *fBufferRef, clOnfile);    //read object
00991          delete [] fBuffer;
00992       } else {
00993          delete [] fBuffer;
00994          cl->Destructor(pobj);
00995          pobj = 0;
00996          goto CLEAR;
00997       }
00998    } else {
00999       cl->Streamer((void*)pobj, *fBufferRef, clOnfile);    //read object
01000    }
01001 
01002    if (cl->InheritsFrom(TObject::Class())) {
01003       baseOffset = cl->GetBaseClassOffset(TObject::Class());
01004       if (baseOffset==-1) {
01005          Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
01006             fClassName.Data());
01007       }
01008       TObject *tobj = (TObject*)( ((char*)pobj) +baseOffset);
01009 
01010       // See similar adjustments in ReadObj
01011       if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
01012 
01013       if (cl->InheritsFrom(TDirectoryFile::Class())) {
01014          TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
01015          dir->SetName(GetName());
01016          dir->SetTitle(GetTitle());
01017          dir->SetMother(fMotherDir);
01018          fMotherDir->Append(dir);
01019       }
01020    }
01021 
01022    {
01023       // Append the object to the directory if requested:
01024       ROOT::DirAutoAdd_t addfunc = cl->GetDirectoryAutoAdd();
01025       if (addfunc) {
01026          addfunc(pobj, fMotherDir);
01027       }
01028    }
01029 
01030    CLEAR:
01031    delete fBufferRef;
01032    fBufferRef = 0;
01033    fBuffer    = 0;
01034 
01035    return ( ((char*)pobj) + baseOffset );
01036 }
01037 
01038 //______________________________________________________________________________
01039 Int_t TKey::Read(TObject *obj)
01040 {
01041    // To read an object from the file.
01042    // The object associated to this key is read from the file into memory.
01043    // Before invoking this function, obj has been created via the
01044    // default constructor.
01045 
01046    if (!obj || (GetFile()==0)) return 0;
01047 
01048    fBufferRef = new TBufferFile(TBuffer::kRead, fObjlen+fKeylen);
01049    fBufferRef->SetParent(GetFile());
01050    fBufferRef->SetPidOffset(fPidOffset);
01051 
01052    if (fVersion > 1)
01053       fBufferRef->MapObject(obj);  //register obj in map to handle self reference
01054 
01055    if (fObjlen > fNbytes-fKeylen) {
01056       fBuffer = new char[fNbytes];
01057       ReadFile();                    //Read object structure from file
01058       memcpy(fBufferRef->Buffer(),fBuffer,fKeylen);
01059    } else {
01060       fBuffer = fBufferRef->Buffer();
01061       ReadFile();                    //Read object structure from file
01062    }
01063    fBufferRef->SetBufferOffset(fKeylen);
01064    if (fObjlen > fNbytes-fKeylen) {
01065       char *objbuf = fBufferRef->Buffer() + fKeylen;
01066       UChar_t *bufcur = (UChar_t *)&fBuffer[fKeylen];
01067       Int_t nin, nout, nbuf;
01068       Int_t noutot = 0;
01069       while (1) {
01070          Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
01071          if (hc!=0) break;
01072          R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
01073          if (!nout) break;
01074          noutot += nout;
01075          if (noutot >= fObjlen) break;
01076          bufcur += nin;
01077          objbuf += nout;
01078       }
01079       if (nout) obj->Streamer(*fBufferRef);
01080       delete [] fBuffer;
01081    } else {
01082       obj->Streamer(*fBufferRef);
01083    }
01084    delete fBufferRef;
01085    fBufferRef = 0;
01086    fBuffer    = 0;
01087    return fNbytes;
01088 }
01089 
01090 //______________________________________________________________________________
01091 void TKey::ReadBuffer(char *&buffer)
01092 {
01093    // Decode input buffer.
01094    // In some situation will add key to gDirectory ???
01095 
01096    ReadKeyBuffer(buffer);
01097 
01098    if (!gROOT->ReadingObject() && gDirectory) {
01099       if (fSeekPdir != gDirectory->GetSeekDir()) gDirectory->AppendKey(this);
01100    }
01101 }
01102 
01103 //______________________________________________________________________________
01104 void TKey::ReadKeyBuffer(char *&buffer)
01105 {
01106    // Decode input buffer.
01107 
01108    frombuf(buffer, &fNbytes);
01109    Version_t version;
01110    frombuf(buffer,&version);
01111    fVersion = (Int_t)version;
01112    frombuf(buffer, &fObjlen);
01113    fDatime.ReadBuffer(buffer);
01114    frombuf(buffer, &fKeylen);
01115    frombuf(buffer, &fCycle);
01116    if (fVersion > 1000) {
01117       frombuf(buffer, &fSeekKey);
01118 
01119       // We currently store in the 16 highest bit of fSeekPdir the value of
01120       // fPidOffset.  This offset is used when a key (or basket) is transfered from one
01121       // file to the other.  In this case the TRef and TObject might have stored a
01122       // pid index (to retrieve TProcessIDs) which refered to their order on the original
01123       // file, the fPidOffset is to be added to those values to correctly find the
01124       // TProcessID.  This fPidOffset needs to be increment if the key/basket is copied
01125       // and need to be zero for new key/basket.
01126       Long64_t pdir;
01127       frombuf(buffer, &pdir);
01128       fPidOffset = pdir >> kPidOffsetShift;
01129       fSeekPdir = pdir & kPidOffsetMask;
01130    } else {
01131       Int_t seekkey,seekdir;
01132       frombuf(buffer, &seekkey); fSeekKey = (Long64_t)seekkey;
01133       frombuf(buffer, &seekdir); fSeekPdir= (Long64_t)seekdir;
01134    }
01135    fClassName.ReadBuffer(buffer);
01136    //the following test required for forward and backward compatibility
01137    if (fClassName == "TDirectory") fClassName = "TDirectoryFile";
01138 
01139    fName.ReadBuffer(buffer);
01140    fTitle.ReadBuffer(buffer);
01141 }
01142 
01143 //______________________________________________________________________________
01144 void TKey::ReadFile()
01145 {
01146    // Read the key structure from the file
01147 
01148    TFile* f = GetFile();
01149    if (f==0) return;
01150 
01151    Int_t nsize = fNbytes;
01152    f->Seek(fSeekKey);
01153 #if 0
01154    for (Int_t i = 0; i < nsize; i += kMAXFILEBUFFER) {
01155       int nb = kMAXFILEBUFFER;
01156       if (i+nb > nsize) nb = nsize - i;
01157       f->ReadBuffer(fBuffer+i,nb);
01158    }
01159 #else
01160    f->ReadBuffer(fBuffer,nsize);
01161 #endif
01162    if (gDebug) {
01163       cout << "TKey Reading "<<nsize<< " bytes at address "<<fSeekKey<<endl;
01164    }
01165 }
01166 
01167 //______________________________________________________________________________
01168 void TKey::SetParent(const TObject *parent)
01169 {
01170    // Set parent in key buffer.
01171 
01172    if (fBufferRef) fBufferRef->SetParent((TObject*)parent);
01173 }
01174 
01175 //______________________________________________________________________________
01176 void TKey::Reset()
01177 {
01178    // Reset the key as it had not been 'filled' yet.
01179    
01180    fPidOffset  = 0;
01181    fNbytes     = 0;
01182    fBuffer     = 0;
01183    fObjlen     = 0;
01184    fCycle      = 0;
01185    fSeekPdir   = 0;
01186    fSeekKey    = 0;
01187    fLeft       = 0;
01188    fDatime     = (UInt_t)0;
01189 
01190    // fBufferRef and fKeylen intentionally not reset/changed
01191    
01192    keyAbsNumber++; SetUniqueID(keyAbsNumber);   
01193 }
01194 
01195 //______________________________________________________________________________
01196 Int_t TKey::Sizeof() const
01197 {
01198    // Return the size in bytes of the key header structure.
01199    // Int_t nbytes = sizeof fNbytes;      4
01200    //             += sizeof(Version_t);   2
01201    //             += sizeof fObjlen;      4
01202    //             += sizeof fKeylen;      2
01203    //             += sizeof fCycle;       2
01204    //             += sizeof fSeekKey;     4 or 8
01205    //             += sizeof fSeekPdir;    4 or 8
01206    //              =                     22
01207 
01208    Int_t nbytes = 22; if (fVersion > 1000) nbytes += 8;
01209    nbytes      += fDatime.Sizeof();
01210    nbytes      += fClassName.Sizeof();
01211    nbytes      += fName.Sizeof();
01212    nbytes      += fTitle.Sizeof();
01213    return nbytes;
01214 }
01215 
01216 //_______________________________________________________________________
01217 void TKey::Streamer(TBuffer &b)
01218 {
01219    // Stream a class object.
01220 
01221    Version_t version;
01222    if (b.IsReading()) {
01223       b >> fNbytes;
01224       b >> version; fVersion = (Int_t)version;
01225       b >> fObjlen;
01226       fDatime.Streamer(b);
01227       b >> fKeylen;
01228       b >> fCycle;
01229       if (fVersion > 1000) {
01230          b >> fSeekKey;
01231 
01232          // We currently store in the 16 highest bit of fSeekPdir the value of
01233          // fPidOffset.  This offset is used when a key (or basket) is transfered from one
01234          // file to the other.  In this case the TRef and TObject might have stored a
01235          // pid index (to retrieve TProcessIDs) which refered to their order on the original
01236          // file, the fPidOffset is to be added to those values to correctly find the
01237          // TProcessID.  This fPidOffset needs to be increment if the key/basket is copied
01238          // and need to be zero for new key/basket.
01239          Long64_t pdir;
01240          b >> pdir;
01241          fPidOffset = pdir >> kPidOffsetShift;
01242          fSeekPdir = pdir & kPidOffsetMask;
01243       } else {
01244          Int_t seekkey, seekdir;
01245          b >> seekkey; fSeekKey = (Long64_t)seekkey;
01246          b >> seekdir; fSeekPdir= (Long64_t)seekdir;
01247       }
01248       fClassName.Streamer(b);
01249       fName.Streamer(b);
01250       fTitle.Streamer(b);
01251       if (fKeylen < 0) {
01252          Error("Streamer","The value of fKeylen is incorrect (%d) ; trying to recover by setting it to zero",fKeylen);
01253          MakeZombie();
01254          fKeylen = 0;
01255       }
01256       if (fObjlen < 0) {
01257          Error("Streamer","The value of fObjlen is incorrect (%d) ; trying to recover by setting it to zero",fObjlen);
01258          MakeZombie();
01259          fObjlen = 0;
01260       }
01261       if (fNbytes < 0) {
01262          Error("Streamer","The value of fNbytes is incorrect (%d) ; trying to recover by setting it to zero",fNbytes);
01263          MakeZombie();
01264          fNbytes = 0;
01265       }
01266       
01267          
01268    } else {
01269       b << fNbytes;
01270       version = (Version_t)fVersion;
01271       b << version;
01272       b << fObjlen;
01273       if (fDatime.Get() == 0) fDatime.Set();
01274       fDatime.Streamer(b);
01275       b << fKeylen;
01276       b << fCycle;
01277       if (fVersion > 1000) {
01278          b << fSeekKey;
01279 
01280          // We currently store in the 16 highest bit of fSeekPdir the value of
01281          // fPidOffset.  This offset is used when a key (or basket) is transfered from one
01282          // file to the other.  In this case the TRef and TObject might have stored a
01283          // pid index (to retrieve TProcessIDs) which refered to their order on the original
01284          // file, the fPidOffset is to be added to those values to correctly find the
01285          // TProcessID.  This fPidOffset needs to be increment if the key/basket is copied
01286          // and need to be zero for new key/basket.
01287          Long64_t pdir = (((Long64_t)fPidOffset)<<kPidOffsetShift) | (kPidOffsetMask & fSeekPdir);
01288          b << pdir;
01289       } else {
01290          b << (Int_t)fSeekKey;
01291          b << (Int_t)fSeekPdir;
01292       }
01293       fClassName.Streamer(b);
01294       fName.Streamer(b);
01295       fTitle.Streamer(b);
01296    }
01297 }
01298 
01299 //______________________________________________________________________________
01300 Int_t TKey::WriteFile(Int_t cycle, TFile* f)
01301 {
01302    // Write the encoded object supported by this key.
01303    // The function returns the number of bytes committed to the file.
01304    // If a write error occurs, the number of bytes returned is -1.
01305 
01306    if (!f) f = GetFile();
01307    if (!f) return -1;
01308 
01309    Int_t nsize  = fNbytes;
01310    char *buffer = fBuffer;
01311    if (cycle) {
01312       fCycle = cycle;
01313       FillBuffer(buffer);
01314       buffer = fBuffer;
01315    }
01316 
01317    if (fLeft > 0) nsize += sizeof(Int_t);
01318    f->Seek(fSeekKey);
01319 #if 0
01320    for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
01321       Int_t nb = kMAXFILEBUFFER;
01322       if (i+nb > nsize) nb = nsize - i;
01323       f->WriteBuffer(buffer,nb);
01324       buffer += nb;
01325    }
01326 #else
01327    Bool_t result = f->WriteBuffer(buffer,nsize);
01328 #endif
01329    //f->Flush(); Flushing takes too much time.
01330    //            Let user flush the file when he wants.
01331    if (gDebug) {
01332       cout <<"   TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
01333            <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<endl;
01334    }
01335 
01336    DeleteBuffer();
01337    return result==kTRUE ? -1 : nsize;
01338 }
01339 
01340 //______________________________________________________________________________
01341 Int_t TKey::WriteFileKeepBuffer(TFile *f)
01342 {
01343    // Write the encoded object supported by this key.
01344    // The function returns the number of bytes committed to the file.
01345    // If a write error occurs, the number of bytes returned is -1.
01346    
01347    if (!f) f = GetFile();
01348    if (!f) return -1;
01349    
01350    Int_t nsize  = fNbytes;
01351    char *buffer = fBuffer;
01352    
01353    if (fLeft > 0) nsize += sizeof(Int_t);
01354    f->Seek(fSeekKey);
01355 #if 0
01356    for (Int_t i=0;i<nsize;i+=kMAXFILEBUFFER) {
01357       Int_t nb = kMAXFILEBUFFER;
01358       if (i+nb > nsize) nb = nsize - i;
01359       f->WriteBuffer(buffer,nb);
01360       buffer += nb;
01361    }
01362 #else
01363    Bool_t result = f->WriteBuffer(buffer,nsize);
01364 #endif
01365    //f->Flush(); Flushing takes too much time.
01366    //            Let user flush the file when he wants.
01367    if (gDebug) {
01368       cout <<"   TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
01369       <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<endl;
01370    }
01371    
01372    return result==kTRUE ? -1 : nsize;
01373 }
01374 
01375 //______________________________________________________________________________
01376 const char *TKey::GetIconName() const
01377 {
01378    // Title can keep 32x32 xpm thumbnail/icon of the parent object.
01379 
01380    return (!fTitle.IsNull() && fTitle.BeginsWith("/* ") ?  fTitle.Data() : 0);
01381 }
01382 
01383 //______________________________________________________________________________
01384 const char *TKey::GetTitle() const
01385 {
01386    // Returns title (title can contain 32x32 xpm thumbnail/icon).
01387 
01388    if (!fTitle.IsNull() && fTitle.BeginsWith("/* ")) { // title contains xpm thumbnail
01389       static TString ret;
01390       int start = fTitle.Index("/*") + 3;
01391       int stop = fTitle.Index("*/") - 1;
01392       ret = fTitle(start, stop - start);
01393       return ret.Data();
01394    }
01395    return fTitle.Data();
01396 }

Generated on Tue Jul 5 14:30:18 2011 for ROOT_528-00b_version by  doxygen 1.5.1