TDirectoryFile.cxx

Go to the documentation of this file.
00001 // @(#)root/io:$Id: TDirectoryFile.cxx 37531 2010-12-10 20:38:06Z pcanal $
00002 // Author: Rene Brun   22/01/2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2007, 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 // A ROOT file is structured in Directories (like a file system).
00015 // Each Directory has a list of Keys (see TKeys) and a list of objects
00016 // in memory. A Key is a small object that describes the type and location
00017 // of a persistent object in a file. The persistent object may be a directory.
00018 //Begin_Html
00019 /*
00020 <img src="gif/fildir.gif">
00021 */
00022 //End_Html
00023 //
00024 //      The structure of a file is shown in TFile::TFile
00025 //______________________________________________________________________________
00026 
00027 #include "Riostream.h"
00028 #include "Strlen.h"
00029 #include "TDirectoryFile.h"
00030 #include "TFile.h"
00031 #include "TBufferFile.h"
00032 #include "TMapFile.h"
00033 #include "TClassTable.h"
00034 #include "TInterpreter.h"
00035 #include "THashList.h"
00036 #include "TBrowser.h"
00037 #include "TFree.h"
00038 #include "TKey.h"
00039 #include "TStreamerInfo.h"
00040 #include "TROOT.h"
00041 #include "TError.h"
00042 #include "Bytes.h"
00043 #include "TClass.h"
00044 #include "TRegexp.h"
00045 #include "TSystem.h"
00046 #include "TStreamerElement.h"
00047 #include "TProcessUUID.h"
00048 #include "TVirtualMutex.h"
00049 
00050 const UInt_t kIsBigFile = BIT(16);
00051 const Int_t  kMaxLen = 2048;
00052 
00053 ClassImp(TDirectoryFile)
00054 
00055 
00056 //______________________________________________________________________________
00057 TDirectoryFile::TDirectoryFile() : TDirectory()
00058    , fModified(kFALSE), fWritable(kFALSE), fNbytesKeys(0), fNbytesName(0)
00059    , fBufferSize(0), fSeekDir(0), fSeekParent(0), fSeekKeys(0)
00060    , fFile(0), fKeys(0)
00061 {
00062 //*-*-*-*-*-*-*-*-*-*-*-*Directory default constructor-*-*-*-*-*-*-*-*-*-*-*-*
00063 //*-*                    =============================
00064 }
00065 
00066 //______________________________________________________________________________
00067 TDirectoryFile::TDirectoryFile(const char *name, const char *title, Option_t *classname, TDirectory* initMotherDir)
00068            : TDirectory()
00069    , fModified(kFALSE), fWritable(kFALSE), fNbytesKeys(0), fNbytesName(0)
00070    , fBufferSize(0), fSeekDir(0), fSeekParent(0), fSeekKeys(0)
00071    , fFile(0), fKeys(0)
00072 {
00073 //*-*-*-*-*-*-*-*-*-*-*-* Create a new DirectoryFile *-*-*-*-*-*-*-*-*-*-*-*-*-*
00074 //*-*                     ==========================
00075 //  A new directory with name,title is created in the current directory
00076 //  The directory header information is immediatly saved on the file
00077 //  A new key is added in the parent directory
00078 //
00079 //  When this constructor is called from a class directly derived
00080 //  from TDirectoryFile, the third argument classname MUST be specified.
00081 //  In this case, classname must be the name of the derived class.
00082 //
00083 //  Note that the directory name cannot contain slashes.
00084 
00085    fName = name;
00086    fTitle = title;
00087 
00088    if (initMotherDir==0) initMotherDir = gDirectory;
00089 
00090    if (strchr(name,'/')) {
00091       ::Error("TDirectoryFile","directory name (%s) cannot contain a slash", name);
00092       gDirectory = 0;
00093       return;
00094    }
00095    if (strlen(GetName()) == 0) {
00096       ::Error("TDirectoryFile","directory name cannot be \"\"");
00097       gDirectory = 0;
00098       return;
00099    }
00100 
00101    Build(initMotherDir ? initMotherDir->GetFile() : 0, initMotherDir);
00102 
00103    TDirectory* motherdir = GetMotherDir();
00104    TFile* f = GetFile();
00105 
00106    if ((motherdir==0) || (f==0)) return;
00107    if (!f->IsWritable()) return; //*-* in case of a directory in memory
00108    if (motherdir->GetKey(name)) {
00109       Error("TDirectoryFile","An object with name %s exists already", name);
00110       return;
00111    }
00112    TClass *cl = IsA();
00113    if (strlen(classname) != 0) cl = TClass::GetClass(classname);
00114 
00115    if (!cl) {
00116       Error("TDirectoryFile","Invalid class name: %s",classname);
00117       return;
00118    }
00119    fBufferSize  = 0;
00120    fWritable    = kTRUE;
00121 
00122    if (f->IsBinary()) {
00123       fSeekParent  = f->GetSeekDir();
00124       Int_t nbytes = TDirectoryFile::Sizeof();
00125       TKey *key    = new TKey(fName,fTitle,cl,nbytes,motherdir);
00126       fNbytesName  = key->GetKeylen();
00127       fSeekDir     = key->GetSeekKey();
00128       if (fSeekDir == 0) return;
00129       char *buffer = key->GetBuffer();
00130       TDirectoryFile::FillBuffer(buffer);
00131       Int_t cycle = motherdir->AppendKey(key);
00132       key->WriteFile(cycle);
00133    } else {
00134       fSeekParent  = 0;
00135       fNbytesName  = 0;
00136       fSeekDir     = f->DirCreateEntry(this);
00137       if (fSeekDir == 0) return;
00138    }
00139 
00140    fModified = kFALSE;
00141    R__LOCKGUARD2(gROOTMutex);
00142    gROOT->GetUUIDs()->AddUUID(fUUID,this);
00143 }
00144 
00145 //______________________________________________________________________________
00146 TDirectoryFile::TDirectoryFile(const TDirectoryFile & directory) : TDirectory(directory)
00147    , fModified(kFALSE), fWritable(kFALSE), fNbytesKeys(0), fNbytesName(0)
00148    , fBufferSize(0), fSeekDir(0), fSeekParent(0), fSeekKeys(0)
00149    , fFile(0), fKeys(0)
00150 {
00151    // Copy constructor.
00152    ((TDirectoryFile&)directory).Copy(*this);
00153 }
00154 
00155 //______________________________________________________________________________
00156 TDirectoryFile::~TDirectoryFile()
00157 {
00158    // -- Destructor.
00159 
00160    if (fKeys) {
00161       fKeys->Delete("slow");
00162       SafeDelete(fKeys);
00163    }
00164 
00165    CleanTargets();
00166 
00167    if (gDebug) {
00168       Info("~TDirectoryFile", "dtor called for %s", GetName());
00169    }
00170 }
00171 
00172 //______________________________________________________________________________
00173 void TDirectoryFile::Append(TObject *obj, Bool_t replace /* = kFALSE */)
00174 {
00175    // Append object to this directory.
00176    //
00177    // If replace is true:
00178    //   remove any existing objects with the same same (if the name is not ""
00179 
00180    if (obj == 0 || fList == 0) return;
00181 
00182    TDirectory::Append(obj,replace);
00183    
00184    if (!fMother) return;
00185    if (fMother->IsA() == TMapFile::Class()) {
00186       TMapFile *mfile = (TMapFile*)fMother;
00187       mfile->Add(obj);
00188    }
00189 }
00190 
00191 //______________________________________________________________________________
00192 Int_t TDirectoryFile::AppendKey(TKey *key)
00193 {
00194 //*-*-*-*-*-*-*Insert key in the linked list of keys of this directory*-*-*-*
00195 //*-*          =======================================================
00196 
00197    fModified = kTRUE;
00198 
00199    key->SetMotherDir(this);
00200 
00201    // This is a fast hash lookup in case the key does not already exist
00202    TKey *oldkey = (TKey*)fKeys->FindObject(key->GetName());
00203    if (!oldkey) {
00204       fKeys->Add(key);
00205       return 1;
00206    }
00207 
00208    // If the key name already exists we have to make a scan for it
00209    // and insert the new key ahead of the current one
00210    TObjLink *lnk = fKeys->FirstLink();
00211    while (lnk) {
00212       oldkey = (TKey*)lnk->GetObject();
00213       if (!strcmp(oldkey->GetName(), key->GetName()))
00214          break;
00215       lnk = lnk->Next();
00216    }
00217 
00218    fKeys->AddBefore(lnk, key);
00219    return oldkey->GetCycle() + 1;
00220 }
00221 
00222 //______________________________________________________________________________
00223 void TDirectoryFile::Browse(TBrowser *b)
00224 {
00225    // Browse the content of the directory.
00226 
00227    TString name;
00228 
00229    if (b) {
00230       TObject *obj = 0;
00231       TIter nextin(fList);
00232       TKey *key = 0, *keyo = 0;
00233       TIter next(fKeys);
00234 
00235       cd();
00236 
00237       //Add objects that are only in memory
00238       while ((obj = nextin())) {
00239          if (fKeys->FindObject(obj->GetName())) continue;
00240          b->Add(obj, obj->GetName());
00241       }
00242 
00243       //Add keys
00244       while ((key = (TKey *) next())) {
00245          int skip = 0;
00246          if (!keyo || (keyo && strcmp(keyo->GetName(), key->GetName()))) {
00247             skip = 0;
00248             obj = fList->FindObject(key->GetName());
00249 
00250             if (obj) {
00251                b->Add(obj, obj->GetName());
00252                if (obj->IsFolder() && !obj->InheritsFrom("TTree"))
00253                   skip = 1;
00254             }
00255          }
00256 
00257          if (!skip) {
00258             name.Form("%s;%d", key->GetName(), key->GetCycle());
00259             b->Add(key, name);
00260          }
00261 
00262          keyo = key;
00263       }
00264    }
00265 }
00266 
00267 //______________________________________________________________________________
00268 void TDirectoryFile::Build(TFile* motherFile, TDirectory* motherDir)
00269 {
00270 //*-*-*-*-*-*-*-*-*-*-*-*Initialise directory to defaults*-*-*-*-*-*-*-*-*-*
00271 //*-*                    ================================
00272 
00273    // If directory is created via default ctor (when dir is read from file)
00274    // don't add it here to the directory since its name is not yet known.
00275    // It will be added to the directory in TKey::ReadObj().
00276 
00277    if (motherDir && strlen(GetName()) != 0) motherDir->Append(this);
00278 
00279    fModified   = kTRUE;
00280    fWritable   = kFALSE;
00281    fDatimeC.Set();
00282    fDatimeM.Set();
00283    fNbytesKeys = 0;
00284    fSeekDir    = 0;
00285    fSeekParent = 0;
00286    fSeekKeys   = 0;
00287    fList       = new THashList(100,50);
00288    fKeys       = new THashList(100,50);
00289    fMother     = motherDir;
00290    fFile       = motherFile ? motherFile : gFile;
00291    SetBit(kCanDelete);
00292 }
00293 
00294 //______________________________________________________________________________
00295 Bool_t TDirectoryFile::cd(const char *path)
00296 {
00297    // Change current directory to "this" directory . Using path one can
00298    // change the current directory to "path". The absolute path syntax is:
00299    // file.root:/dir1/dir2
00300    // where file.root is the file and /dir1/dir2 the desired subdirectory
00301    // in the file. Relative syntax is relative to "this" directory. E.g:
00302    // ../aa. Returns kTRUE in case of success.
00303 
00304    Bool_t ok = TDirectory::cd(path);
00305    if (ok) gFile = fFile;
00306    return ok;
00307 }
00308 
00309 //______________________________________________________________________________
00310 void TDirectoryFile::CleanTargets()
00311 {
00312    // Clean the pointers to this object (gDirectory, TContext, etc.)
00313 
00314    TDirectory::CleanTargets();
00315 
00316    // After CleanTargets either gFile was changed appropriately
00317    // by a cd() or needs to be set to zero.
00318    if (gFile == this) {
00319       gFile = 0;
00320    }
00321 }
00322 
00323 //______________________________________________________________________________
00324 TObject *TDirectoryFile::CloneObject(const TObject *obj, Bool_t autoadd /* = kTRUE */)
00325 {
00326    // Make a clone of an object using the Streamer facility.
00327    // If the object derives from TNamed, this function is called
00328    // by TNamed::Clone. TNamed::Clone uses the optional argument newname to set
00329    // a new name to the newly created object.
00330    // 
00331    // If autoadd is true and if the object class has a
00332    // DirectoryAutoAdd function, it will be called at the end of the
00333    // function with the parameter gDirector.  This usually means that
00334    // the object will be appended to the current ROOT directory.
00335 
00336    // if no default ctor return immediately (error issued by New())
00337    char *pobj = (char*)obj->IsA()->New();
00338    if (!pobj) return 0;
00339    
00340    Int_t baseOffset = obj->IsA()->GetBaseClassOffset(TObject::Class());
00341    if (baseOffset==-1) {
00342       // cl does not inherit from TObject.
00343       // Since this is not supported in this function, the only reason we could reach this code
00344       // is because something is screwed up in the ROOT code.
00345       Fatal("CloneObject","Incorrect detection of the inheritance from TObject for class %s.\n",
00346             obj->IsA()->GetName());
00347    }
00348    TObject *newobj = (TObject*)(pobj+baseOffset);
00349 
00350    //create a buffer where the object will be streamed
00351    TFile *filsav = gFile;
00352    gFile = 0;
00353    const Int_t bufsize = 10000;
00354    TBuffer *buffer = new TBufferFile(TBuffer::kWrite,bufsize);
00355    buffer->MapObject(obj);  //register obj in map to handle self reference
00356    {
00357       Bool_t isRef = obj->TestBit(kIsReferenced); 
00358       ((TObject*)obj)->ResetBit(kIsReferenced); 
00359       
00360       ((TObject*)obj)->Streamer(*buffer);
00361       
00362       if (isRef) ((TObject*)obj)->SetBit(kIsReferenced);
00363    }
00364 
00365    // read new object from buffer
00366    buffer->SetReadMode();
00367    buffer->ResetMap();
00368    buffer->SetBufferOffset(0);
00369    buffer->MapObject(newobj);  //register obj in map to handle self reference
00370    newobj->Streamer(*buffer);
00371    newobj->ResetBit(kIsReferenced);
00372    newobj->ResetBit(kCanDelete);
00373    gFile = filsav;
00374 
00375    delete buffer;
00376 
00377    if (autoadd) {
00378       ROOT::DirAutoAdd_t func = obj->IsA()->GetDirectoryAutoAdd();
00379       if (func) {
00380          func(newobj,this);
00381       }  
00382    }
00383    return newobj;
00384 }
00385 
00386 //______________________________________________________________________________
00387 TObject *TDirectoryFile::FindObjectAnyFile(const char *name) const
00388 {
00389    // Scan the memory lists of all files for an object with name
00390 
00391    TFile *f;
00392    TIter next(gROOT->GetListOfFiles());
00393    while ((f = (TFile*)next())) {
00394       TObject *obj = f->GetList()->FindObject(name);
00395       if (obj) return obj;
00396    }
00397    return 0;
00398 }
00399 
00400 
00401 
00402 //______________________________________________________________________________
00403 TDirectory *TDirectoryFile::GetDirectory(const char *apath,
00404                                          Bool_t printError, const char *funcname)
00405 {
00406    // Find a directory named "apath".
00407    // It apath is null or empty, returns "this" directory.
00408    // Otherwise use the name "apath" to find a directory.
00409    // The absolute path syntax is:
00410    //    file.root:/dir1/dir2
00411    // where file.root is the file and /dir1/dir2 the desired subdirectory
00412    // in the file. Relative syntax is relative to "this" directory. E.g:
00413    // ../aa.
00414    // Returns 0 in case path does not exist.
00415    // If printError is true, use Error with 'funcname' to issue an error message.
00416 
00417    Int_t nch = 0;
00418    if (apath) nch = strlen(apath);
00419    if (!nch) {
00420       return this;
00421    }
00422 
00423    if (funcname==0 || strlen(funcname)==0) funcname = "GetDirectory";
00424 
00425    TDirectory *result = this;
00426 
00427    char *path = new char[nch+1]; path[0] = 0;
00428    if (nch) strlcpy(path,apath,nch+1);
00429    char *s = (char*)strchr(path, ':');
00430    if (s) {
00431       *s = '\0';
00432       R__LOCKGUARD2(gROOTMutex);
00433       TDirectory *f = (TDirectory *)gROOT->GetListOfFiles()->FindObject(path);
00434       if (!f && !strcmp(gROOT->GetName(), path)) f = gROOT;
00435       if (s) *s = ':';
00436       if (f) {
00437          result = f;
00438          if (s && *(s+1)) result = f->GetDirectory(s+1,printError,funcname);
00439          delete [] path; return result;
00440       } else {
00441          if (printError) Error(funcname, "No such file %s", path);
00442          delete [] path; return 0;
00443       }
00444    }
00445 
00446    // path starts with a slash (assumes current file)
00447    if (path[0] == '/') {
00448       TDirectory *td = fFile;
00449       if (!fFile) td = gROOT;
00450       result = td->GetDirectory(path+1,printError,funcname);
00451       delete [] path; return result;
00452    }
00453 
00454    TObject *obj;
00455    char *slash = (char*)strchr(path,'/');
00456    if (!slash) {                     // we are at the lowest level
00457       if (!strcmp(path, "..")) {
00458          result = GetMotherDir();
00459          delete [] path; return result;
00460       }
00461       obj = Get(path);
00462       if (!obj) {
00463          if (printError) Error(funcname,"Unknown directory %s", path);
00464          delete [] path; return 0;
00465       }
00466 
00467       //Check return object is a directory
00468       if (!obj->InheritsFrom(TDirectoryFile::Class())) {
00469          if (printError) Error(funcname,"Object %s is not a directory", path);
00470          delete [] path; return 0;
00471       }
00472       delete [] path; return (TDirectory*)obj;
00473    }
00474 
00475    TString subdir(path);
00476    slash = (char*)strchr(subdir.Data(),'/');
00477    *slash = 0;
00478    //Get object with path from current directory/file
00479    if (!strcmp(subdir, "..")) {
00480       TDirectory* mom = GetMotherDir();
00481       if (mom)
00482          result = mom->GetDirectory(slash+1,printError,funcname);
00483       delete [] path; return result;
00484    }
00485    obj = Get(subdir);
00486    if (!obj) {
00487       if (printError) Error(funcname,"Unknown directory %s", subdir.Data());
00488       delete [] path; return 0;
00489    }
00490 
00491    //Check return object is a directory
00492    if (!obj->InheritsFrom(TDirectoryFile::Class())) {
00493       if (printError) Error(funcname,"Object %s is not a directory", subdir.Data());
00494       delete [] path; return 0;
00495    }
00496    result = ((TDirectory*)obj)->GetDirectory(slash+1,printError,funcname);
00497    delete [] path; return result;
00498 }
00499 
00500 //______________________________________________________________________________
00501 void TDirectoryFile::Close(Option_t *)
00502 {
00503    // -- Delete all objects from memory and directory structure itself.
00504 
00505    if (!fList || !fSeekDir) {
00506       return;
00507    }
00508 
00509    // Save the directory key list and header
00510    Save();
00511 
00512    Bool_t fast = kTRUE;
00513    TObjLink *lnk = fList->FirstLink();
00514    while (lnk) {
00515       if (lnk->GetObject()->IsA() == TDirectoryFile::Class()) {fast = kFALSE;break;}
00516       lnk = lnk->Next();
00517    }
00518    // Delete objects from directory list, this in turn, recursively closes all
00519    // sub-directories (that were allocated on the heap)
00520    // if this dir contains subdirs, we must use the slow option for Delete!
00521    // we must avoid "slow" as much as possible, in particular Delete("slow")
00522    // with a large number of objects (eg >10^5) would take for ever.
00523    if (fast) fList->Delete();
00524    else      fList->Delete("slow");
00525 
00526    // Delete keys from key list (but don't delete the list header)
00527    if (fKeys) {
00528       fKeys->Delete("slow");
00529    }
00530 
00531    CleanTargets();
00532 }
00533 
00534 //______________________________________________________________________________
00535 void TDirectoryFile::Delete(const char *namecycle)
00536 {
00537 //*-*-*-*-*-*-*-* Delete Objects or/and keys in a directory *-*-*-*-*-*-*-*
00538 //*-*             =========================================
00539 //   namecycle has the format name;cycle
00540 //   namecycle = "" same as namecycle ="T*"
00541 //   name  = * means all
00542 //   cycle = * means all cycles (memory and keys)
00543 //   cycle = "" or cycle = 9999 ==> apply to a memory object
00544 //   When name=* use T* to delete subdirectories also
00545 //
00546 //   To delete one directory, you must specify the directory cycle,
00547 //      eg.  file.Delete("dir1;1");
00548 //
00549 //   examples:
00550 //     foo   : delete object named foo in memory
00551 //     foo*  : delete all objects with a name starting with foo
00552 //     foo;1 : delete cycle 1 of foo on file
00553 //     foo;* : delete all cycles of foo on file and also from memory
00554 //     *;2   : delete all objects on file having the cycle 2
00555 //     *;*   : delete all objects from memory and file
00556 //    T*;*   : delete all objects from memory and file and all subdirectories
00557 //          WARNING
00558 //    If the key to be deleted contains special characters ("+","^","?", etc
00559 //    that have a special meaning for the regular expression parser (see TRegexp)
00560 //    then you must specify 2 backslash characters to escape the regular expression.
00561 //    For example, if the key to be deleted is namecycle = "C++", you must call
00562 //       mydir.Delete("C\\+\\+")).
00563 
00564    if (gDebug)
00565      Info("Delete","Call for this = %s namecycle = %s",
00566                GetName(), (namecycle ? namecycle : "null"));
00567 
00568    TDirectory::TContext ctxt(gDirectory, this);
00569    Short_t  cycle;
00570    char     name[kMaxLen];
00571    DecodeNameCycle(namecycle, name, cycle);
00572 
00573    Int_t deleteall    = 0;
00574    Int_t deletetree   = 0;
00575    if(strcmp(name,"*") == 0)   deleteall = 1;
00576    if(strcmp(name,"*T") == 0){ deleteall = 1; deletetree = 1;}
00577    if(strcmp(name,"T*") == 0){ deleteall = 1; deletetree = 1;}
00578    if(namecycle==0 || strlen(namecycle) == 0){ deleteall = 1; deletetree = 1;}
00579    TRegexp re(name,kTRUE);
00580    TString s;
00581    Int_t deleteOK = 0;
00582 
00583 //*-*---------------------Case of Object in memory---------------------
00584 //                        ========================
00585    if (cycle >= 9999 ) {
00586       TNamed *idcur;
00587       TIter   next(fList);
00588       while ((idcur = (TNamed *) next())) {
00589          deleteOK = 0;
00590          s = idcur->GetName();
00591          if (deleteall || s.Index(re) != kNPOS) {
00592             deleteOK = 1;
00593             if (idcur->IsA() == TDirectoryFile::Class()) {
00594                deleteOK = 2;
00595                if (!deletetree && deleteall) deleteOK = 0;
00596             }
00597          }
00598          if (deleteOK != 0) {
00599             fList->Remove(idcur);
00600             if (deleteOK==2) {
00601                // read subdirectories to correctly delete them
00602                if (deletetree)
00603                   ((TDirectory*) idcur)->ReadAll("dirs");
00604                idcur->Delete(deletetree ? "T*;*" : "*");
00605                delete idcur;
00606             } else
00607                idcur->Delete(name);
00608          }
00609       }
00610 //      if (deleteOK == 2) {
00611 //         Info("Delete","Dir:%lx %s", fList->FindObject(name), name);
00612 //         delete fList->FindObject(name); //deleting a TDirectory
00613 //      }
00614    }
00615 //*-*---------------------Case of Key---------------------
00616 //                        ===========
00617    if (cycle != 9999 ) {
00618       if (IsWritable()) {
00619          TKey *key;
00620          TIter nextkey(GetListOfKeys());
00621          while ((key = (TKey *) nextkey())) {
00622             deleteOK = 0;
00623             s = key->GetName();
00624             if (deleteall || s.Index(re) != kNPOS) {
00625                if (cycle == key->GetCycle()) deleteOK = 1;
00626                if (cycle > 9999) deleteOK = 1;
00627                //if (!strcmp(key->GetClassName(),"TDirectory")) {
00628                if (strstr(key->GetClassName(),"TDirectory")) {
00629                   deleteOK = 2;
00630                   if (!deletetree && deleteall) deleteOK = 0;
00631                   if (cycle == key->GetCycle()) deleteOK = 2;
00632                }
00633             }
00634             if (deleteOK) {
00635                if (deleteOK==2) {
00636                   // read directory with subdirectories to correctly delete and free key structure
00637                   TDirectory* dir = GetDirectory(key->GetName(), kTRUE, "Delete");
00638                   if (dir!=0) {
00639                      dir->Delete("T*;*");
00640                      fList->Remove(dir);
00641                      delete dir;
00642                   }
00643                }
00644 
00645                key->Delete();
00646                fKeys->Remove(key);
00647                fModified = kTRUE;
00648                delete key;
00649             }
00650          }
00651          TFile* f = GetFile();
00652          if (fModified && (f!=0)) {
00653             WriteKeys();            //*-* Write new keys structure
00654             WriteDirHeader();       //*-* Write new directory header
00655             f->WriteFree();     //*-* Write new free segments list
00656             f->WriteHeader();   //*-* Write new file header
00657          }
00658       }
00659    }
00660 }
00661 
00662 //______________________________________________________________________________
00663 void TDirectoryFile::FillBuffer(char *&buffer)
00664 {
00665 //*-*-*-*-*-*-*-*-*-*-*-*Encode directory header into output buffer*-*-*-*-*-*
00666 //*-*                    =========================================
00667    Version_t version = TDirectoryFile::Class_Version();
00668    if (fSeekKeys > TFile::kStartBigFile) version += 1000;
00669    tobuf(buffer, version);
00670    fDatimeC.FillBuffer(buffer);
00671    fDatimeM.FillBuffer(buffer);
00672    tobuf(buffer, fNbytesKeys);
00673    tobuf(buffer, fNbytesName);
00674    if (version > 1000) {
00675       tobuf(buffer, fSeekDir);
00676       tobuf(buffer, fSeekParent);
00677       tobuf(buffer, fSeekKeys);
00678    } else {
00679       tobuf(buffer, (Int_t)fSeekDir);
00680       tobuf(buffer, (Int_t)fSeekParent);
00681       tobuf(buffer, (Int_t)fSeekKeys);
00682    }
00683    fUUID.FillBuffer(buffer);
00684    if (fFile && fFile->GetVersion() < 40000) return;
00685    if (version <=1000) for (Int_t i=0;i<3;i++) tobuf(buffer,Int_t(0));
00686 }
00687 
00688 //______________________________________________________________________________
00689 TKey *TDirectoryFile::FindKey(const char *keyname) const
00690 {
00691    // Find key with name keyname in the current directory
00692 
00693    Short_t  cycle;
00694    char     name[kMaxLen];
00695 
00696    DecodeNameCycle(keyname, name, cycle);
00697    return GetKey(name,cycle);
00698 }
00699 
00700 //______________________________________________________________________________
00701 TKey *TDirectoryFile::FindKeyAny(const char *keyname) const
00702 {
00703    // Find key with name keyname in the current directory or
00704    // its subdirectories.
00705    // NOTE that If a key is found, the directory containing the key becomes
00706    // the current directory
00707 
00708    TDirectory *dirsav = gDirectory;
00709    Short_t  cycle;
00710    char     name[kMaxLen];
00711 
00712    DecodeNameCycle(keyname, name, cycle);
00713 
00714    TIter next(GetListOfKeys());
00715    TKey *key;
00716    while ((key = (TKey *) next())) {
00717       if (!strcmp(name, key->GetName()))
00718          if ((cycle == 9999) || (cycle >= key->GetCycle()))  {
00719             ((TDirectory*)this)->cd(); // may be we should not make cd ???
00720             return key;
00721          }
00722    }
00723    //try with subdirectories
00724    next.Reset();
00725    while ((key = (TKey *) next())) {
00726       //if (!strcmp(key->GetClassName(),"TDirectory")) {
00727       if (strstr(key->GetClassName(),"TDirectory")) {
00728          TDirectory* subdir =
00729            ((TDirectory*)this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
00730          TKey *k = (subdir!=0) ? subdir->FindKeyAny(keyname) : 0;
00731          if (k) return k;
00732       }
00733    }
00734    if (dirsav) dirsav->cd();
00735    return 0;
00736 }
00737 
00738 //______________________________________________________________________________
00739 TObject *TDirectoryFile::FindObjectAny(const char *aname) const
00740 {
00741    // Find object by name in the list of memory objects of the current
00742    // directory or its sub-directories.
00743    // After this call the current directory is not changed.
00744    // To automatically set the current directory where the object is found,
00745    // use FindKeyAny(aname)->ReadObj().
00746 
00747    //object may be already in the list of objects in memory
00748    TObject *obj = TDirectory::FindObjectAny(aname);
00749    if (obj) return obj;
00750 
00751    TDirectory *dirsav = gDirectory;
00752    Short_t  cycle;
00753    char     name[kMaxLen];
00754 
00755    DecodeNameCycle(aname, name, cycle);
00756 
00757    TIter next(GetListOfKeys());
00758    TKey *key;
00759    //may be a key in the current directory
00760    while ((key = (TKey *) next())) {
00761       if (!strcmp(name, key->GetName())) {
00762          if (cycle == 9999)             return key->ReadObj();
00763          if (cycle >= key->GetCycle())  return key->ReadObj();
00764       }
00765    }
00766    //try with subdirectories
00767    next.Reset();
00768    while ((key = (TKey *) next())) {
00769       //if (!strcmp(key->GetClassName(),"TDirectory")) {
00770       if (strstr(key->GetClassName(),"TDirectory")) {
00771          TDirectory* subdir =
00772            ((TDirectory*)this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
00773          TKey *k = subdir==0 ? 0 : subdir->FindKeyAny(aname);
00774          if (k) { if (dirsav) dirsav->cd(); return k->ReadObj();}
00775       }
00776    }
00777    if (dirsav) dirsav->cd();
00778    return 0;
00779 }
00780 
00781 //______________________________________________________________________________
00782 TObject *TDirectoryFile::Get(const char *namecycle)
00783 {
00784 //  return pointer to object identified by namecycle
00785 //
00786 //   namecycle has the format name;cycle
00787 //   name  = * is illegal, cycle = * is illegal
00788 //   cycle = "" or cycle = 9999 ==> apply to a memory object
00789 //
00790 //   examples:
00791 //     foo   : get object named foo in memory
00792 //             if object is not in memory, try with highest cycle from file
00793 //     foo;1 : get cycle 1 of foo on file
00794 //
00795 //  The retrieved object should in principle derive from TObject.
00796 //  If not, the function TDirectoryFile::GetObject should be called.
00797 //  However, this function will still work for a non-TObject, providing that
00798 //  the calling application cast the return type to the correct type (which
00799 //  is the actual type of the object).
00800 //
00801 //  NOTE:
00802 //  The method GetObject offers better protection and avoids the need
00803 //  for any cast:
00804 //      MyClass *obj;
00805 //      directory->GetObject("some object",obj);
00806 //      if (obj) { ... the object exist and inherits from MyClass ... }
00807 //
00808 //  VERY IMPORTANT NOTE:
00809 //  In case the class of this object derives from TObject but not
00810 //  as a first inheritance, one must use dynamic_cast<>().
00811 //  Example 1: Normal case:
00812 //      class MyClass : public TObject, public AnotherClass
00813 //   then on return, one can do:
00814 //      MyClass *obj = (MyClass*)directory->Get("some object of MyClass");
00815 //
00816 //  Example 2: Special case:
00817 //      class MyClass : public AnotherClass, public TObject
00818 //  then on return, one must do:
00819 //      MyClass *obj = dynamic_cast<MyClass*>(directory->Get("some object of MyClass"));
00820 //
00821 //  Of course, dynamic_cast<> can also be used in the example 1.
00822 //
00823 
00824    Short_t  cycle;
00825    char     name[kMaxLen];
00826 
00827    DecodeNameCycle(namecycle, name, cycle);
00828    char *namobj = name;
00829    Int_t nch = strlen(name);
00830    for (Int_t i = nch-1; i > 0; i--) {
00831       if (name[i] == '/') {
00832          name[i] = 0;
00833          TDirectory* dirToSearch=GetDirectory(name);
00834          namobj = name + i + 1;
00835          name[i] = '/';
00836          return dirToSearch?dirToSearch->Get(namobj):0;
00837       }
00838    }
00839 
00840 //*-*---------------------Case of Object in memory---------------------
00841 //                        ========================
00842    TObject *idcur = fList->FindObject(namobj);
00843    if (idcur) {
00844       if (idcur==this && strlen(namobj)!=0) {
00845          // The object has the same name has the directory and
00846          // that's what we picked-up!  We just need to ignore
00847          // it ...
00848          idcur = 0;
00849       } else if (cycle == 9999) {
00850          return idcur;
00851       } else {
00852          if (idcur->InheritsFrom(TCollection::Class()))
00853             idcur->Delete();  // delete also list elements
00854          delete idcur;
00855          idcur = 0;
00856       }
00857    }
00858 
00859 //*-*---------------------Case of Key---------------------
00860 //                        ===========
00861    TKey *key;
00862    TIter nextkey(GetListOfKeys());
00863    while ((key = (TKey *) nextkey())) {
00864       if (strcmp(namobj,key->GetName()) == 0) {
00865          if ((cycle == 9999) || (cycle == key->GetCycle())) {
00866             TDirectory::TContext ctxt(this);
00867             idcur = key->ReadObj();
00868             break;
00869          }
00870       }
00871    }
00872 
00873    return idcur;
00874 }
00875 
00876 //______________________________________________________________________________
00877 void *TDirectoryFile::GetObjectUnchecked(const char *namecycle)
00878 {
00879 // return pointer to object identified by namecycle.
00880 // The returned object may or may not derive from TObject.
00881 //
00882 //   namecycle has the format name;cycle
00883 //   name  = * is illegal, cycle = * is illegal
00884 //   cycle = "" or cycle = 9999 ==> apply to a memory object
00885 //
00886 //  VERY IMPORTANT NOTE:
00887 //  The calling application must cast the returned object to
00888 //  the final type, eg
00889 //      MyClass *obj = (MyClass*)directory->GetObject("some object of MyClass");
00890 
00891    return GetObjectChecked(namecycle,(TClass*)0);
00892 }
00893 
00894 //_________________________________________________________________________________
00895 void *TDirectoryFile::GetObjectChecked(const char *namecycle, const char* classname)
00896 {
00897 // See documentation of TDirectoryFile::GetObjectCheck(const char *namecycle, const TClass *cl)
00898 
00899    return GetObjectChecked(namecycle,TClass::GetClass(classname));
00900 }
00901 
00902 
00903 //____________________________________________________________________________
00904 void *TDirectoryFile::GetObjectChecked(const char *namecycle, const TClass* expectedClass)
00905 {
00906 // return pointer to object identified by namecycle if and only if the actual
00907 // object is a type suitable to be stored as a pointer to a "expectedClass"
00908 // If expectedClass is null, no check is performed.
00909 //
00910 //   namecycle has the format name;cycle
00911 //   name  = * is illegal, cycle = * is illegal
00912 //   cycle = "" or cycle = 9999 ==> apply to a memory object
00913 //
00914 //  VERY IMPORTANT NOTE:
00915 //  The calling application must cast the returned pointer to
00916 //  the type described by the 2 arguments (i.e. cl):
00917 //      MyClass *obj = (MyClass*)directory->GetObjectChecked("some object of MyClass","MyClass"));
00918 //
00919 //  Note: We recommend using the method TDirectoryFile::GetObject:
00920 //      MyClass *obj = 0;
00921 //      directory->GetObject("some object inheriting from MyClass",obj);
00922 //      if (obj) { ... we found what we are looking for ... }
00923 
00924    Short_t  cycle;
00925    char     name[kMaxLen];
00926 
00927    DecodeNameCycle(namecycle, name, cycle);
00928    char *namobj = name;
00929    Int_t nch = strlen(name);
00930    for (Int_t i = nch-1; i > 0; i--) {
00931       if (name[i] == '/') {
00932          name[i] = 0;
00933          TDirectory* dirToSearch=GetDirectory(name);
00934          namobj = name + i + 1;
00935          name[i] = '/';
00936          if (dirToSearch) {
00937             return dirToSearch->GetObjectChecked(namobj, expectedClass);
00938          } else {
00939             return 0;
00940          }
00941       }
00942    }
00943 
00944 //*-*---------------------Case of Object in memory---------------------
00945 //                        ========================
00946    if (expectedClass==0 || expectedClass->InheritsFrom(TObject::Class())) {
00947       TObject *objcur = fList->FindObject(namobj);
00948       if (objcur) {
00949          if (objcur==this && strlen(namobj)!=0) {
00950             // The object has the same name has the directory and
00951             // that's what we picked-up!  We just need to ignore
00952             // it ...
00953             objcur = 0;
00954          } else if (cycle == 9999) {
00955             // Check type
00956             if (expectedClass && objcur->IsA()->GetBaseClassOffset(expectedClass) == -1) return 0;
00957             else return objcur;
00958          } else {
00959             if (objcur->InheritsFrom(TCollection::Class()))
00960                objcur->Delete();  // delete also list elements
00961             delete objcur;
00962             objcur = 0;
00963          }
00964       }
00965    }
00966 
00967 //*-*---------------------Case of Key---------------------
00968 //                        ===========
00969    void *idcur = 0;
00970    TKey *key;
00971    TIter nextkey(GetListOfKeys());
00972    while ((key = (TKey *) nextkey())) {
00973       if (strcmp(namobj,key->GetName()) == 0) {
00974          if ((cycle == 9999) || (cycle == key->GetCycle())) {
00975             TDirectory::TContext ctxt(this);
00976             idcur = key->ReadObjectAny(expectedClass);
00977             break;
00978          }
00979       }
00980    }
00981 
00982    return idcur;
00983 }
00984 
00985 //______________________________________________________________________________
00986 Int_t TDirectoryFile::GetBufferSize() const
00987 {
00988    // Return the buffer size to create new TKeys.
00989    // If the stored fBufferSize is null, the value returned is the average
00990    // buffer size of objects in the file so far.
00991 
00992    if (fBufferSize <= 0) return fFile->GetBestBuffer();
00993    else                  return fBufferSize;
00994 }
00995 
00996 
00997 //______________________________________________________________________________
00998 TKey *TDirectoryFile::GetKey(const char *name, Short_t cycle) const
00999 {
01000 //*-*-*-*-*-*-*-*-*-*-*Return pointer to key with name,cycle*-*-*-*-*-*-*-*
01001 //*-*                  =====================================
01002 //  if cycle = 9999 returns highest cycle
01003 //
01004    TKey *key;
01005    TIter next(GetListOfKeys());
01006    while ((key = (TKey *) next()))
01007       if (!strcmp(name, key->GetName())) {
01008          if (cycle == 9999)             return key;
01009          if (cycle >= key->GetCycle())  return key;
01010       }
01011    return 0;
01012 }
01013 
01014 //______________________________________________________________________________
01015 void TDirectoryFile::ls(Option_t *option) const
01016 {
01017 //*-*-*-*-*-*-*-*-*-*-*-*List Directory contents*-*-*-*-*-*-*-*-*-*-*-*-*-*
01018 //*-*                    =======================
01019 //  Indentation is used to identify the directory tree
01020 //  Subdirectories are listed first, then objects in memory, then objects on the file
01021 //
01022 //  The option can has the following format:
01023 //     [-d |-m][<regexp>]
01024 //  Option -d means: only list objects in the file
01025 //         -m means: only list objects in memory
01026 //  The <regexp> will be used to match the name of the objects.
01027 //  By default memory and disk objects are listed.
01028 //
01029    TROOT::IndentLevel();
01030    cout <<ClassName()<<"*\t\t"<<GetName()<<"\t"<<GetTitle()<<endl;
01031    TROOT::IncreaseDirLevel();
01032 
01033    TString opta = option;
01034    TString opt  = opta.Strip(TString::kBoth);
01035    Bool_t memobj  = kTRUE;
01036    Bool_t diskobj = kTRUE;
01037    TString reg = "*";
01038    if (opt.BeginsWith("-m")) {
01039       diskobj = kFALSE;
01040       if (opt.Length() > 2)
01041          reg = opt(2,opt.Length());
01042    } else if (opt.BeginsWith("-d")) {
01043       memobj  = kFALSE;
01044       if (opt.Length() > 2)
01045          reg = opt(2,opt.Length());
01046    } else if (!opt.IsNull())
01047       reg = opt;
01048 
01049    TRegexp re(reg, kTRUE);
01050 
01051    if (memobj) {
01052       TObject *obj;
01053       TIter nextobj(fList);
01054       while ((obj = (TObject *) nextobj())) {
01055          TString s = obj->GetName();
01056          if (s.Index(re) == kNPOS) continue;
01057          obj->ls(option);            //*-* Loop on all the objects in memory
01058       }
01059    }
01060 
01061    if (diskobj) {
01062       TKey *key;
01063       TIter next(GetListOfKeys());
01064       while ((key = (TKey *) next())) {
01065          TString s = key->GetName();
01066          if (s.Index(re) == kNPOS) continue;
01067          key->ls();                 //*-* Loop on all the keys
01068       }
01069    }
01070    TROOT::DecreaseDirLevel();
01071 }
01072 
01073 //______________________________________________________________________________
01074 TFile *TDirectoryFile::OpenFile(const char *name, Option_t *option,const char *ftitle, Int_t compress, Int_t netopt)
01075 {
01076    // Interface to TFile::Open
01077 
01078    return TFile::Open(name,option,ftitle,compress,netopt);
01079 
01080 }
01081 
01082 
01083 //______________________________________________________________________________
01084 TDirectory *TDirectoryFile::mkdir(const char *name, const char *title)
01085 {
01086    // Create a sub-directory and return a pointer to the created directory.
01087    // Returns 0 in case of error.
01088    // Returns 0 if a directory with the same name already exists.
01089    // Note that the directory name may be of the form "a/b/c" to create a hierarchy of directories.
01090    // In this case, the function returns the pointer to the "a" directory if the operation is successful.
01091 
01092    if (!name || !title || !strlen(name)) return 0;
01093    if (!strlen(title)) title = name;
01094    if (GetKey(name)) {
01095       Error("mkdir","An object with name %s exists already",name);
01096       return 0;
01097    }
01098    TDirectoryFile *newdir = 0;
01099    if (const char *slash = strchr(name,'/')) {
01100       Long_t size = Long_t(slash-name);
01101       char *workname = new char[size+1];
01102       strncpy(workname, name, size);
01103       workname[size] = 0;
01104       TDirectoryFile *tmpdir = (TDirectoryFile*)mkdir(workname,title);
01105       if (!tmpdir) return 0;
01106       if (!newdir) newdir = tmpdir;
01107       tmpdir->mkdir(slash+1);
01108       delete[] workname;
01109       return newdir;
01110    }
01111 
01112    TDirectory::TContext ctxt(this);
01113 
01114    newdir = new TDirectoryFile(name, title, "", this);
01115 
01116    return newdir;
01117 }
01118 
01119 //______________________________________________________________________________
01120 void TDirectoryFile::Purge(Short_t)
01121 {
01122    // Purge lowest key cycles in a directory.
01123    // By default, only the highest cycle of a key is kept. Keys for which
01124    // the "KEEP" flag has been set are not removed. See TKey::Keep().
01125 
01126    if (!IsWritable()) return;
01127 
01128    TDirectory::TContext ctxt(this);
01129 
01130    TKey  *key;
01131    TIter  prev(GetListOfKeys(), kIterBackward);
01132 
01133    while ((key = (TKey*)prev())) {      // reverse loop on keys
01134       TKey *keyprev = (TKey*)GetListOfKeys()->Before(key);
01135       if (!keyprev) break;
01136       if (key->GetKeep() == 0) {
01137          if (strcmp(key->GetName(), keyprev->GetName()) == 0) {
01138             key->Delete(); // Remove from the file.
01139             delete key;    // Remove from memory.
01140          }
01141       }
01142    }
01143    TFile* f = GetFile();
01144    if (fModified && (f!=0)) {
01145       WriteKeys();                   // Write new keys structure
01146       WriteDirHeader();              // Write new directory header
01147       f->WriteFree();                // Write new free segments list
01148       f->WriteHeader();              // Write new file header
01149    }
01150 }
01151 
01152 //______________________________________________________________________________
01153 void TDirectoryFile::ReadAll(Option_t* opt)
01154 {
01155    // Read objects from a ROOT db file directory into memory.
01156    // If an object is already in memory, the memory copy is deleted
01157    // and the object is again read from the file.
01158    // If opt=="dirs", only subdirectories will be read
01159    // If opt=="dirs*" complete directory tree will be read
01160 
01161    TDirectory::TContext ctxt(this);
01162 
01163    TKey *key;
01164    TIter next(GetListOfKeys());
01165 
01166    Bool_t readdirs = ((opt!=0) && ((strcmp(opt,"dirs")==0) || (strcmp(opt,"dirs*")==0)));
01167 
01168    if (readdirs)
01169       while ((key = (TKey *) next())) {
01170 
01171          //if (strcmp(key->GetClassName(),"TDirectory")!=0) continue;
01172          if (strstr(key->GetClassName(),"TDirectory")==0) continue;
01173 
01174          TDirectory *dir = GetDirectory(key->GetName(), kTRUE, "ReadAll");
01175 
01176          if ((dir!=0) && (strcmp(opt,"dirs*")==0)) dir->ReadAll("dirs*");
01177       }
01178    else
01179       while ((key = (TKey *) next())) {
01180          TObject *thing = GetList()->FindObject(key->GetName());
01181          if (thing) { delete thing; }
01182          key->ReadObj();
01183       }
01184 }
01185 
01186 //______________________________________________________________________________
01187 Int_t TDirectoryFile::ReadKeys(Bool_t forceRead)
01188 {
01189 //*-*-*-*-*-*-*-*-*-*-*-*-*Read the KEYS linked list*-*-*-*-*-*-*-*-*-*-*-*-*
01190 //*-*                      =========================
01191 //  Every directory has a linked list (fKeys). This linked list has been
01192 //  written on the file via WriteKeys as a single data record.
01193 //
01194 //  It is interesting to call this function in the following situation.
01195 //  Assume another process1 is connecting this directory in Update mode
01196 //    -Process1 is adding/updating objects in this directory
01197 //    -You want to see the latest status from process1.
01198 //  Example Process1:
01199 //    obj1.Write();
01200 //    obj2.Write();
01201 //    gDirectory->SaveSelf();
01202 //
01203 //  Example Process2
01204 //    gDirectory->ReadKeys();
01205 //    obj1->Draw();
01206 //
01207 //  This is an efficient way (without opening/closing files) to view
01208 //  the latest updates of a file being modified by another process
01209 //  as it is typically the case in a data acquisition system.
01210 
01211    if (fFile==0) return 0;
01212 
01213    if (!fFile->IsBinary())
01214       return fFile->DirReadKeys(this);
01215 
01216    TDirectory::TContext ctxt(this);
01217 
01218    char *buffer;
01219    if (forceRead) {
01220       fKeys->Delete();
01221       //In case directory was updated by another process, read new
01222       //position for the keys
01223       Int_t nbytes = fNbytesName + TDirectoryFile::Sizeof();
01224       char *header = new char[nbytes];
01225       buffer       = header;
01226       fFile->Seek(fSeekDir);
01227       fFile->ReadBuffer(buffer,nbytes);
01228       buffer += fNbytesName;
01229       Version_t versiondir;
01230       frombuf(buffer,&versiondir);
01231       fDatimeC.ReadBuffer(buffer);
01232       fDatimeM.ReadBuffer(buffer);
01233       frombuf(buffer, &fNbytesKeys);
01234       frombuf(buffer, &fNbytesName);
01235       if (versiondir > 1000) {
01236          frombuf(buffer, &fSeekDir);
01237          frombuf(buffer, &fSeekParent);
01238          frombuf(buffer, &fSeekKeys);
01239       } else {
01240          Int_t sdir,sparent,skeys;
01241          frombuf(buffer, &sdir);    fSeekDir    = (Long64_t)sdir;
01242          frombuf(buffer, &sparent); fSeekParent = (Long64_t)sparent;
01243          frombuf(buffer, &skeys);   fSeekKeys   = (Long64_t)skeys;
01244       }
01245       delete [] header;
01246    }
01247    
01248    Int_t nkeys = 0;
01249    Long64_t fsize = fFile->GetSize();
01250    if ( fSeekKeys >  0) {
01251       TKey *headerkey    = new TKey(fSeekKeys, fNbytesKeys, this);
01252       headerkey->ReadFile();
01253       buffer = headerkey->GetBuffer();
01254       headerkey->ReadKeyBuffer(buffer);
01255 
01256       TKey *key;
01257       frombuf(buffer, &nkeys);
01258       for (Int_t i = 0; i < nkeys; i++) {
01259          key = new TKey(this);
01260          key->ReadKeyBuffer(buffer);
01261          if (key->GetSeekKey() < 64 || key->GetSeekKey() > fsize) {
01262             Error("ReadKeys","reading illegal key, exiting after %d keys",i);
01263             fKeys->Remove(key);
01264             nkeys = i;
01265             break;
01266          }
01267          if (key->GetSeekPdir() < 64 || key->GetSeekPdir() > fsize) {
01268             Error("ReadKeys","reading illegal key, exiting after %d keys",i);
01269             fKeys->Remove(key);
01270             nkeys = i;
01271             break;
01272          }
01273          fKeys->Add(key);
01274       }
01275       delete headerkey;
01276    }
01277 
01278    return nkeys;
01279 }
01280 
01281 
01282 //______________________________________________________________________________
01283 Int_t TDirectoryFile::ReadTObject(TObject *obj, const char *keyname)
01284 {
01285    // Read object with keyname from the current directory
01286    // Read contents of object with specified name from the current directory.
01287    // First the key with keyname is searched in the current directory,
01288    // next the key buffer is deserialized into the object.
01289    // The object must have been created before via the default constructor.
01290    // See TObject::Write().
01291 
01292    if (!fFile) { Error("Read","No file open"); return 0; }
01293    TKey *key = (TKey*)fKeys->FindObject(keyname);
01294    if (!key)   { Error("Read","Key not found"); return 0; }
01295    return key->Read(obj);
01296 }
01297 
01298 //______________________________________________________________________________
01299 void TDirectoryFile::rmdir(const char *name)
01300 {
01301    // Removes subdirectory from the directory
01302    // When diredctory is deleted, all keys in all subdirectories will be
01303    // read first and deleted from file (if exists)
01304    // Equivalent call is Delete("name;*");
01305 
01306    if ((name==0) || (*name==0)) return;
01307 
01308    TString mask(name);
01309    mask+=";*";
01310    Delete(mask);
01311 }
01312 
01313 //______________________________________________________________________________
01314 void TDirectoryFile::Save()
01315 {
01316 //*-*-*-*-*-*-*-*-*-*Save recursively all directory keys and headers-*-*-*-*-*
01317 //*-*                ===============================================
01318 
01319    TDirectory::TContext ctxt(this);
01320 
01321    SaveSelf();
01322 
01323    // recursively save all sub-directories
01324    if (fList) {
01325       TObject *idcur;
01326       TIter    next(fList);
01327       while ((idcur = next())) {
01328          if (idcur->InheritsFrom(TDirectoryFile::Class())) {
01329             TDirectoryFile *dir = (TDirectoryFile*)idcur;
01330             dir->Save();
01331          }
01332       }
01333    }
01334 }
01335 
01336 //______________________________________________________________________________
01337 Int_t TDirectoryFile::SaveObjectAs(const TObject *obj, const char *filename, Option_t *option) const
01338 {
01339    // Save object in filename,
01340    // if filename is 0 or "", a file with "objectname.root" is created.
01341    // The name of the key is the object name.
01342    // If the operation is successful, it returns the number of bytes written to the file
01343    // otherwise it returns 0.
01344    // By default a message is printed. Use option "q" to not print the message.
01345 
01346    if (!obj) return 0;
01347    TDirectory *dirsav = gDirectory;
01348    TString fname = filename;
01349    if (!filename || strlen(filename) == 0) {
01350       fname = Form("%s.root",obj->GetName());
01351    }
01352    TFile *local = TFile::Open(fname.Data(),"recreate");
01353    if (!local) return 0;
01354    Int_t nbytes = obj->Write();
01355    delete local;
01356    if (dirsav) dirsav->cd();
01357    TString opt = option;
01358    opt.ToLower();
01359    if (!opt.Contains("q")) {
01360       if (!gSystem->AccessPathName(fname.Data())) obj->Info("SaveAs", "ROOT file %s has been created", fname.Data());
01361    }
01362    return nbytes;
01363 }
01364 
01365 //______________________________________________________________________________
01366 void TDirectoryFile::SaveSelf(Bool_t force)
01367 {
01368 //*-*-*-*-*-*-*-*-*-*Save Directory keys and header*-*-*-*-*-*-*-*-*-*-*-*
01369 //*-*                ==============================
01370 //  If the directory has been modified (fModified set), write the keys
01371 //  and the directory header. This function assumes the cd is correctly set.
01372 //
01373 //  It is recommended to use this function in the following situation:
01374 //  Assume a process1 using a directory in Update mode
01375 //    -New objects or modified objects have been written to the directory
01376 //    -You do not want to close the file
01377 //    -You want your changes be visible from another process2 already connected
01378 //     to this directory in read mode
01379 //    -Call this function
01380 //    -In process2, use TDirectoryFile::ReadKeys to refresh the directory
01381 
01382    if (IsWritable() && (fModified || force) && fFile) {
01383       Bool_t dowrite = kTRUE;
01384       if (fFile->GetListOfFree())
01385         dowrite = fFile->GetListOfFree()->First() != 0;
01386       if (dowrite) {
01387          TDirectory *dirsav = gDirectory;
01388          if (dirsav != this) cd();
01389          WriteKeys();          //*-*- Write keys record
01390          WriteDirHeader();     //*-*- Update directory record
01391          if (dirsav && dirsav != this) dirsav->cd();
01392       }
01393    }
01394 }
01395 
01396 //______________________________________________________________________________
01397 void TDirectoryFile::SetBufferSize(Int_t bufsize)
01398 {
01399    // set the default buffer size when creating new TKeys
01400    // see also TDirectoryFile::GetBufferSize
01401 
01402    fBufferSize = bufsize;
01403 }
01404 
01405 //______________________________________________________________________________
01406 void TDirectoryFile::SetTRefAction(TObject *ref, TObject *parent)
01407 {
01408    // Find the action to be executed in the dictionary of the parent class
01409    // and store the corresponding exec number into fBits.
01410    // This function searches a data member in the class of parent with an
01411    // offset corresponding to this.
01412    // If a comment "TEXEC:" is found in the comment field of the data member,
01413    // the function stores the exec identifier of the exec statement
01414    // following this keyword.
01415 
01416    Int_t offset = (char*)ref - (char*)parent;
01417    TClass *cl = parent->IsA();
01418    cl->BuildRealData(parent);
01419    TStreamerInfo *info = (TStreamerInfo*)cl->GetStreamerInfo();
01420    TIter next(info->GetElements());
01421    TStreamerElement *element;
01422    while((element = (TStreamerElement*)next())) {
01423       if (element->GetOffset() != offset) continue;
01424       Int_t execid = element->GetExecID();
01425       if (execid > 0) ref->SetBit(execid << 8);
01426       return;
01427    }
01428 }
01429 
01430 //______________________________________________________________________________
01431 void TDirectoryFile::SetWritable(Bool_t writable)
01432 {
01433 //  Set the new value of fWritable recursively
01434 
01435    TDirectory::TContext ctxt(this);
01436 
01437    fWritable = writable;
01438 
01439    // recursively set all sub-directories
01440    if (fList) {
01441       TObject *idcur;
01442       TIter    next(fList);
01443       while ((idcur = next())) {
01444          if (idcur->InheritsFrom(TDirectoryFile::Class())) {
01445             TDirectoryFile *dir = (TDirectoryFile*)idcur;
01446             dir->SetWritable(writable);
01447          }
01448       }
01449    }
01450 }
01451 
01452 
01453 //______________________________________________________________________________
01454 Int_t TDirectoryFile::Sizeof() const
01455 {
01456 //*-*-*-*-*-*-*Return the size in bytes of the directory header*-*-*-*-*-*-*
01457 //*-*          ================================================
01458    //Int_t nbytes = sizeof(Version_t);    2
01459    //nbytes     += fDatimeC.Sizeof();
01460    //nbytes     += fDatimeM.Sizeof();
01461    //nbytes     += sizeof fNbytesKeys;    4
01462    //nbytes     += sizeof fNbytesName;    4
01463    //nbytes     += sizeof fSeekDir;       4 or 8
01464    //nbytes     += sizeof fSeekParent;    4 or 8
01465    //nbytes     += sizeof fSeekKeys;      4 or 8
01466    //nbytes     += fUUID.Sizeof();
01467    Int_t nbytes = 22;
01468 
01469    nbytes     += fDatimeC.Sizeof();
01470    nbytes     += fDatimeM.Sizeof();
01471    nbytes     += fUUID.Sizeof();
01472     //assume that the file may be above 2 Gbytes if file version is > 4
01473    if (fFile && fFile->GetVersion() >= 40000) nbytes += 12;
01474    return nbytes;
01475 }
01476 
01477 
01478 //_______________________________________________________________________
01479 void TDirectoryFile::Streamer(TBuffer &b)
01480 {
01481 //*-*-*-*-*-*-*-*-*Stream a class object*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
01482 //*-*              =========================================
01483 
01484    Version_t v,version;
01485    if (b.IsReading()) {
01486       Build((TFile*)b.GetParent(), 0);
01487       if (fFile && fFile->IsWritable()) fWritable = kTRUE;
01488 
01489       if (fFile && !fFile->IsBinary()) {
01490          Version_t R__v = b.ReadVersion(0, 0);
01491 
01492          TClass* dirclass = (R__v < 5) ? TDirectory::Class() : TDirectoryFile::Class();
01493 
01494          b.ClassBegin(dirclass, R__v);
01495 
01496          TString sbuf;
01497 
01498          b.ClassMember("CreateTime","TString");
01499          sbuf.Streamer(b);
01500          TDatime timeC(sbuf.Data());
01501          fDatimeC = timeC;
01502 
01503          b.ClassMember("ModifyTime","TString");
01504          sbuf.Streamer(b);
01505          TDatime timeM(sbuf.Data());
01506          fDatimeM = timeM;
01507 
01508          b.ClassMember("UUID","TString");
01509          sbuf.Streamer(b);
01510          TUUID id(sbuf.Data());
01511          fUUID = id;
01512 
01513          b.ClassEnd(dirclass);
01514 
01515          fSeekKeys = 0; // read keys later in the TKeySQL class
01516       } else {
01517          b >> version;
01518          fDatimeC.Streamer(b);
01519          fDatimeM.Streamer(b);
01520          b >> fNbytesKeys;
01521          b >> fNbytesName;
01522          if (version > 1000) {
01523             SetBit(kIsBigFile);
01524             b >> fSeekDir;
01525             b >> fSeekParent;
01526             b >> fSeekKeys;
01527          } else {
01528             Int_t sdir,sparent,skeys;
01529             b >> sdir;    fSeekDir    = (Long64_t)sdir;
01530             b >> sparent; fSeekParent = (Long64_t)sparent;
01531             b >> skeys;   fSeekKeys   = (Long64_t)skeys;
01532          }
01533          v = version%1000;
01534          if (v == 2) {
01535             fUUID.StreamerV1(b);
01536          } else if (v > 2) {
01537             fUUID.Streamer(b);
01538          }
01539       }
01540       R__LOCKGUARD2(gROOTMutex);
01541       gROOT->GetUUIDs()->AddUUID(fUUID,this);
01542       if (fSeekKeys) ReadKeys();
01543    } else {
01544       if (fFile && !fFile->IsBinary()) {
01545          b.WriteVersion(TDirectoryFile::Class());
01546 
01547          TString sbuf;
01548 
01549          b.ClassBegin(TDirectoryFile::Class());
01550 
01551          b.ClassMember("CreateTime","TString");
01552          sbuf = fDatimeC.AsSQLString();
01553          sbuf.Streamer(b);
01554 
01555          b.ClassMember("ModifyTime","TString");
01556          fDatimeM.Set();
01557          sbuf = fDatimeM.AsSQLString();
01558          sbuf.Streamer(b);
01559 
01560          b.ClassMember("UUID","TString");
01561          sbuf = fUUID.AsString();
01562          sbuf.Streamer(b);
01563 
01564          b.ClassEnd(TDirectoryFile::Class());
01565       } else {
01566          version = TDirectoryFile::Class_Version();
01567          if (fFile && fFile->GetEND() > TFile::kStartBigFile) version += 1000;
01568          b << version;
01569          fDatimeC.Streamer(b);
01570          fDatimeM.Streamer(b);
01571          b << fNbytesKeys;
01572          b << fNbytesName;
01573          if (version > 1000) {
01574             b << fSeekDir;
01575             b << fSeekParent;
01576             b << fSeekKeys;
01577          } else {
01578             b << (Int_t)fSeekDir;
01579             b << (Int_t)fSeekParent;
01580             b << (Int_t)fSeekKeys;
01581          }
01582          fUUID.Streamer(b);
01583          if (version <=1000) for (Int_t i=0;i<3;i++) b << Int_t(0);
01584       }
01585    }
01586 }
01587 
01588 //______________________________________________________________________________
01589 Int_t TDirectoryFile::Write(const char *, Int_t opt, Int_t bufsize)
01590 {
01591    // Write all objects in memory to disk.
01592    // Loop on all objects in memory (including subdirectories).
01593    // A new key is created in the KEYS linked list for each object.
01594    // For allowed options see TObject::Write().
01595    // The directory header info is rewritten on the directory header record.
01596 
01597    if (!IsWritable()) return 0;
01598    TDirectory::TContext ctxt(this);
01599 
01600    // Loop on all objects (including subdirs)
01601    TIter next(fList);
01602    TObject *obj;
01603    Int_t nbytes = 0;
01604    while ((obj=next())) {
01605       nbytes += obj->Write(0,opt,bufsize);
01606    }
01607    SaveSelf(kTRUE);   // force save itself
01608 
01609    return nbytes;
01610 }
01611 
01612 //______________________________________________________________________________
01613 Int_t TDirectoryFile::Write(const char *n, Int_t opt, Int_t bufsize) const
01614 {
01615    // One can not save a const TDirectory object.
01616 
01617    Error("Write const","A const TDirectory object should not be saved. We try to proceed anyway.");
01618    return const_cast<TDirectoryFile*>(this)->Write(n, opt, bufsize);
01619 }
01620 
01621 //____________________________________________________________________________________
01622 Int_t TDirectoryFile::WriteTObject(const TObject *obj, const char *name, Option_t *option, Int_t bufsize)
01623 {
01624    // Write object obj to this directory
01625    // The data structure corresponding to this object is serialized.
01626    // The corresponding buffer is written to this directory
01627    // with an associated key with name "name".
01628    //
01629    // Writing an object to a file involves the following steps:
01630    //
01631    //  -Creation of a support TKey object in the directory.
01632    //   The TKey object creates a TBuffer object.
01633    //
01634    //  -The TBuffer object is filled via the class::Streamer function.
01635    //
01636    //  -If the file is compressed (default) a second buffer is created to
01637    //   hold the compressed buffer.
01638    //
01639    //  -Reservation of the corresponding space in the file by looking
01640    //   in the TFree list of free blocks of the file.
01641    //
01642    //  -The buffer is written to the file.
01643    //
01644    //  By default, the buffersize will be taken from the average buffer size
01645    //  of all objects written to the current file so far.
01646    //  Use TDirectoryFile::SetBufferSize to force a given buffer size.
01647    //
01648    //  If a name is specified, it will be the name of the key.
01649    //  If name is not given, the name of the key will be the name as returned
01650    //  by obj->GetName().
01651    //
01652    //  The option can be a combination of:
01653    //    "SingleKey", "Overwrite" or "WriteDelete"
01654    //  Using the "Overwrite" option a previous key with the same name is
01655    //  overwritten. The previous key is deleted before writing the new object.
01656    //  Using the "WriteDelete" option a previous key with the same name is
01657    //  deleted only after the new object has been written. This option
01658    //  is safer than kOverwrite but it is slower.
01659    //  The "SingleKey" option is only used by TCollection::Write() to write
01660    //  a container with a single key instead of each object in the container
01661    //  with its own key.
01662    //
01663    //  An object is read from this directory via TDirectoryFile::Get.
01664    //
01665    //  The function returns the total number of bytes written to the directory.
01666    //  It returns 0 if the object cannot be written.
01667    //
01668    //  WARNING: in name avoid special characters like '^','$','.' that are used 
01669    //  by the regular expression parser (see TRegexp).
01670     
01671    TDirectory::TContext ctxt(this);
01672 
01673    if (fFile==0) {
01674       const char *objname = "no name specified";
01675       if (name) objname = name;
01676       else if (obj) objname = obj->GetName();
01677       Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.",GetName(),objname);
01678       return 0;
01679    }
01680 
01681    if (!fFile->IsWritable()) {
01682       if (!fFile->TestBit(TFile::kWriteError)) {
01683          // Do not print the error if the file already had a SysError.
01684          Error("WriteTObject","Directory %s is not writable", fFile->GetName());
01685       }
01686       return 0;
01687    }
01688 
01689    if (!obj) return 0;
01690 
01691    TString opt = option;
01692    opt.ToLower();
01693 
01694    TKey *key=0, *oldkey=0;
01695    Int_t bsize = GetBufferSize();
01696    if (bufsize > 0) bsize = bufsize;
01697 
01698    const char *oname;
01699    if (name && *name)
01700       oname = name;
01701    else
01702       oname = obj->GetName();
01703 
01704    // Remove trailing blanks in object name
01705    Int_t nch = strlen(oname);
01706    char *newName = 0;
01707    if (oname[nch-1] == ' ') {
01708       newName = new char[nch+1];
01709       strlcpy(newName,oname,nch+1);
01710       for (Int_t i=0;i<nch;i++) {
01711          if (newName[nch-i-1] != ' ') break;
01712          newName[nch-i-1] = 0;
01713       }
01714       oname = newName;
01715    }
01716 
01717    if (opt.Contains("overwrite")) {
01718       //One must use GetKey. FindObject would return the lowest cycle of the key!
01719       //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
01720       key = GetKey(oname);
01721       if (key) {
01722          key->Delete();
01723          delete key;
01724       }
01725    }
01726    if (opt.Contains("writedelete")) {
01727       oldkey = GetKey(oname);
01728    }
01729    key = fFile->CreateKey(this, obj, oname, bsize);
01730    if (newName) delete [] newName;
01731 
01732    if (!key->GetSeekKey()) {
01733       fKeys->Remove(key);
01734       delete key;
01735       if (bufsize) fFile->SetBufferSize(bufsize);
01736       return 0;
01737    }
01738    fFile->SumBuffer(key->GetObjlen());
01739    Int_t nbytes = key->WriteFile(0);
01740    if (fFile->TestBit(TFile::kWriteError)) {
01741       if (bufsize) fFile->SetBufferSize(bufsize);
01742       return 0;
01743    }
01744    if (oldkey) {
01745       oldkey->Delete();
01746       delete oldkey;
01747    }
01748    if (bufsize) fFile->SetBufferSize(bufsize);
01749 
01750    return nbytes;
01751 }
01752 
01753 //______________________________________________________________________________
01754 Int_t TDirectoryFile::WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option, Int_t bufsize)
01755 {
01756    // Write object from pointer of class classname in this directory
01757    // obj may not derive from TObject
01758    // see TDirectoryFile::WriteTObject for comments
01759    //
01760    // VERY IMPORTANT NOTE:
01761    //    The value passed as 'obj' needs to be from a pointer to the type described by classname
01762    //    For example with:
01763    //      TopClass *top;
01764    //      BottomClass *bottom;
01765    //      top = bottom;
01766    //    you can do:
01767    //      directory->WriteObjectAny(top,"top","name of object");
01768    //      directory->WriteObjectAny(bottom,"bottom","name of object");
01769    //    BUT YOU CAN NOT DO (it will fail in particular with multiple inheritance):
01770    //      directory->WriteObjectAny(top,"bottom","name of object");
01771    //
01772    // We STRONGLY recommend to use
01773    //      TopClass *top = ....;
01774    //      directory->WriteObject(top,"name of object")
01775    //
01776    //   see laso remarks in TDirectoryFile::WriteTObject
01777    
01778    TClass *cl = TClass::GetClass(classname);
01779    if (cl == 0) {
01780       TObject *info_obj = *(TObject**)obj;
01781       TVirtualStreamerInfo *info = dynamic_cast<TVirtualStreamerInfo*>(info_obj);
01782       if (info == 0) {
01783          Error("WriteObjectAny","Unknown class: %s",classname);
01784          return 0;
01785       } else {
01786          cl = info->GetClass();
01787       }
01788    }
01789    return WriteObjectAny(obj,cl,name,option,bufsize);
01790 }
01791 
01792 //______________________________________________________________________________
01793 Int_t TDirectoryFile::WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option, Int_t bufsize)
01794 {
01795    // Write object of class with dictionary cl in this directory
01796    // obj may not derive from TObject
01797    // To get the TClass* cl pointer, one can use
01798    //    TClass *cl = TClass::GetClass("classname");
01799    // An alternative is to call the function WriteObjectAny above.
01800    // see TDirectoryFile::WriteTObject for comments
01801 
01802    TDirectory::TContext ctxt(this);
01803 
01804    if (fFile==0) return 0;
01805 
01806    if (!fFile->IsWritable()) {
01807       if (!fFile->TestBit(TFile::kWriteError)) {
01808          // Do not print the error if the file already had a SysError.
01809          Error("WriteObject","File %s is not writable", fFile->GetName());
01810       }
01811       return 0;
01812    }
01813 
01814    if (!obj || !cl) return 0;
01815    TKey *key, *oldkey=0;
01816    Int_t bsize = GetBufferSize();
01817    if (bufsize > 0) bsize = bufsize;
01818 
01819    TString opt = option;
01820    opt.ToLower();
01821 
01822    const char *oname;
01823    if (name && *name)
01824       oname = name;
01825    else
01826       oname = cl->GetName();
01827 
01828    // Remove trailing blanks in object name
01829    Int_t nch = strlen(oname);
01830    char *newName = 0;
01831    if (oname[nch-1] == ' ') {
01832       newName = new char[nch+1];
01833       strlcpy(newName,oname,nch+1);
01834       for (Int_t i=0;i<nch;i++) {
01835          if (newName[nch-i-1] != ' ') break;
01836          newName[nch-i-1] = 0;
01837       }
01838       oname = newName;
01839    }
01840 
01841    if (opt.Contains("overwrite")) {
01842       //One must use GetKey. FindObject would return the lowest cycle of the key!
01843       //key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
01844       key = GetKey(oname);
01845       if (key) {
01846          key->Delete();
01847          delete key;
01848       }
01849    }
01850    if (opt.Contains("writedelete")) {
01851       oldkey = GetKey(oname);
01852    }
01853    key = fFile->CreateKey(this, obj, cl, oname, bsize);
01854    if (newName) delete [] newName;
01855 
01856    if (!key->GetSeekKey()) {
01857       fKeys->Remove(key);
01858       delete key;
01859       return 0;
01860    }
01861    fFile->SumBuffer(key->GetObjlen());
01862    Int_t nbytes = key->WriteFile(0);
01863    if (fFile->TestBit(TFile::kWriteError)) return 0;
01864 
01865    if (oldkey) {
01866       oldkey->Delete();
01867       delete oldkey;
01868    }
01869 
01870    return nbytes;
01871 }
01872 
01873 //______________________________________________________________________________
01874 void TDirectoryFile::WriteDirHeader()
01875 {
01876 //*-*-*-*-*-*-*-*-*-*-*Overwrite the Directory header record*-*-*-*-*-*-*-*-*
01877 //*-*                  =====================================
01878    TFile* f = GetFile();
01879    if (f==0) return;
01880 
01881    if (!f->IsBinary()) {
01882       fDatimeM.Set();
01883       f->DirWriteHeader(this);
01884       return;
01885    }
01886 
01887    Int_t nbytes  = TDirectoryFile::Sizeof();  //Warning ! TFile has a Sizeof()
01888    char * header = new char[nbytes];
01889    char * buffer = header;
01890    fDatimeM.Set();
01891    TDirectoryFile::FillBuffer(buffer);
01892    Long64_t pointer = fSeekDir + fNbytesName; // do not overwrite the name/title part
01893    fModified     = kFALSE;
01894    f->Seek(pointer);
01895    f->WriteBuffer(header, nbytes);
01896    if (f->MustFlush()) f->Flush();
01897    delete [] header;
01898 }
01899 
01900 //______________________________________________________________________________
01901 void TDirectoryFile::WriteKeys()
01902 {
01903 //*-*-*-*-*-*-*-*-*-*-*-*Write KEYS linked list on the file *-*-*-*-*-*-*-*
01904 //*-*                    ==================================
01905 //  The linked list of keys (fKeys) is written as a single data record
01906 //
01907 
01908    TFile* f = GetFile();
01909    if (f==0) return;
01910 
01911    if (!f->IsBinary()) {
01912       f->DirWriteKeys(this);
01913       return;
01914    }
01915 
01916 //*-* Delete the old keys structure if it exists
01917    if (fSeekKeys != 0) {
01918       f->MakeFree(fSeekKeys, fSeekKeys + fNbytesKeys -1);
01919    }
01920 //*-* Write new keys record
01921    TIter next(fKeys);
01922    TKey *key;
01923    Int_t nkeys  = fKeys->GetSize();
01924    Int_t nbytes = sizeof nkeys;          //*-* Compute size of all keys
01925    if (f->GetEND() > TFile::kStartBigFile) nbytes += 8;
01926    while ((key = (TKey*)next())) {
01927       nbytes += key->Sizeof();
01928    }
01929    TKey *headerkey  = new TKey(fName,fTitle,IsA(),nbytes,this);
01930    if (headerkey->GetSeekKey() == 0) {
01931       delete headerkey;
01932       return;
01933    }
01934    char *buffer = headerkey->GetBuffer();
01935    next.Reset();
01936    tobuf(buffer, nkeys);
01937    while ((key = (TKey*)next())) {
01938       key->FillBuffer(buffer);
01939    }
01940 
01941    fSeekKeys     = headerkey->GetSeekKey();
01942    fNbytesKeys   = headerkey->GetNbytes();
01943    headerkey->WriteFile();
01944    delete headerkey;
01945 }

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