/*
<img src="gif/fildir.gif">
*/
//End_Html
#include "Riostream.h"
#include "Strlen.h"
#include "TDirectoryFile.h"
#include "TFile.h"
#include "TBufferFile.h"
#include "TMapFile.h"
#include "TClassTable.h"
#include "TInterpreter.h"
#include "THashList.h"
#include "TBrowser.h"
#include "TFree.h"
#include "TKey.h"
#include "TStreamerInfo.h"
#include "TROOT.h"
#include "TError.h"
#include "Bytes.h"
#include "TClass.h"
#include "TRegexp.h"
#include "TSystem.h"
#include "TStreamerElement.h"
#include "TProcessUUID.h"
#include "TVirtualMutex.h"
const UInt_t kIsBigFile = BIT(16);
const Int_t  kMaxLen = 2048;
ClassImp(TDirectoryFile)
TDirectoryFile::TDirectoryFile() : TDirectory()
   , fModified(kFALSE), fWritable(kFALSE), fNbytesKeys(0), fNbytesName(0)
   , fBufferSize(0), fSeekDir(0), fSeekParent(0), fSeekKeys(0)
   , fFile(0), fKeys(0)
{
}
TDirectoryFile::TDirectoryFile(const char *name, const char *title, Option_t *classname, TDirectory* initMotherDir)
           : TDirectory()
{
   fName = name;
   fTitle = title;
   
   if (initMotherDir==0) initMotherDir = gDirectory;
   if (strchr(name,'/')) {
      ::Error("TDirectoryFile","directory name (%s) cannot contain a slash", name);
      gDirectory = 0;
      return;
   }
   if (strlen(GetName()) == 0) {
      ::Error("TDirectoryFile","directory name cannot be \"\"");
      gDirectory = 0;
      return;
   }
   Build(initMotherDir ? initMotherDir->GetFile() : 0, initMotherDir);
   TDirectory* motherdir = GetMotherDir();
   TFile* f = GetFile();
   if ((motherdir==0) || (f==0)) return;
   if (!f->IsWritable()) return; 
   if (motherdir->GetKey(name)) {
      Error("TDirectoryFile","An object with name %s exists already", name);
      return;
   }
   TClass *cl = IsA();
   if (strlen(classname) != 0) cl = TClass::GetClass(classname);
   if (!cl) {
      Error("TDirectoryFile","Invalid class name: %s",classname);
      return;
   }
   fBufferSize  = 0;
   fWritable    = kTRUE;
   if (f->IsBinary()) {
      fSeekParent  = f->GetSeekDir();
      Int_t nbytes = TDirectoryFile::Sizeof();
      TKey *key    = new TKey(fName,fTitle,cl,nbytes,motherdir);
      fNbytesName  = key->GetKeylen();
      fSeekDir     = key->GetSeekKey();
      if (fSeekDir == 0) return;
      char *buffer = key->GetBuffer();
      TDirectoryFile::FillBuffer(buffer);
      Int_t cycle = motherdir->AppendKey(key);
      key->WriteFile(cycle);
   } else {
      fSeekParent  = 0;
      fNbytesName  = 0;
      fSeekDir     = f->DirCreateEntry(this);
      if (fSeekDir == 0) return;
   }
   fModified = kFALSE;
   R__LOCKGUARD2(gROOTMutex);
   gROOT->GetUUIDs()->AddUUID(fUUID,this);
}
TDirectoryFile::TDirectoryFile(const TDirectoryFile & directory) : TDirectory(directory)
{
   
   ((TDirectoryFile&)directory).Copy(*this);
}
TDirectoryFile::~TDirectoryFile()
{
   
   if (fKeys) {
      fKeys->Delete("slow");
      SafeDelete(fKeys);
   }
   CleanTargets();
   if (gDebug) {
      Info("~TDirectoryFile", "dtor called for %s", GetName());
   }
}
void TDirectoryFile::Append(TObject *obj)
{
   
   if (obj == 0 || fList == 0) return;
   fList->Add(obj);
   obj->SetBit(kMustCleanup);
   if (!fMother) return;
   if (fMother->IsA() == TMapFile::Class()) {
      TMapFile *mfile = (TMapFile*)fMother;
      mfile->Add(obj);
   }
}
Int_t TDirectoryFile::AppendKey(TKey *key)
{
   fModified = kTRUE;
   key->SetMotherDir(this);
   
   TKey *oldkey = (TKey*)fKeys->FindObject(key->GetName());
   if (!oldkey) {
      fKeys->Add(key);
      return 1;
   }
   
   
   TObjLink *lnk = fKeys->FirstLink();
   while (lnk) {
      oldkey = (TKey*)lnk->GetObject();
      if (!strcmp(oldkey->GetName(), key->GetName()))
         break;
      lnk = lnk->Next();
   }
   fKeys->AddBefore(lnk, key);
   return oldkey->GetCycle() + 1;
}
void TDirectoryFile::Browse(TBrowser *b)
{
   
   Char_t name[kMaxLen];
   if (b) {
      TObject *obj = 0;
      TIter nextin(fList);
      TKey *key = 0, *keyo = 0;
      TIter next(fKeys);
      cd();
      
      while ((obj = nextin())) {
         if (fKeys->FindObject(obj->GetName())) continue;
         b->Add(obj, obj->GetName());
      }
      
      while ((key = (TKey *) next())) {
         int skip = 0;
         if (!keyo || (keyo && strcmp(keyo->GetName(), key->GetName()))) {
            skip = 0;
            obj = fList->FindObject(key->GetName());
            if (obj) {
               sprintf(name, "%s", obj->GetName());
               b->Add(obj, name);
               if (obj->IsFolder()) skip = 1;
            }
         }
         if (!skip) {
            sprintf(name, "%s;%d", key->GetName(), key->GetCycle());
            b->Add(key, name);
         }
         keyo = key;
      }
   }
}
void TDirectoryFile::Build(TFile* motherFile, TDirectory* motherDir)
{
   
   
   
   if (motherDir && strlen(GetName()) != 0) motherDir->Append(this);
   fModified   = kTRUE;
   fWritable   = kFALSE;
   fDatimeC.Set();
   fDatimeM.Set();
   fNbytesKeys = 0;
   fSeekDir    = 0;
   fSeekParent = 0;
   fSeekKeys   = 0;
   fList       = new THashList(100,50);
   fKeys       = new THashList(100,50);
   fMother     = motherDir;
   fFile       = motherFile ? motherFile : gFile;
   SetBit(kCanDelete);
}
Bool_t TDirectoryFile::cd(const char *path)
{
   
   
   
   
   
   
   Bool_t ok = TDirectory::cd(path);
   if (ok) gFile = fFile;
   return ok;
}
void TDirectoryFile::CleanTargets() 
{
   
   TDirectory::CleanTargets();
   
   
   if (gFile == this) {
      gFile = 0;
   }
}
TObject *TDirectoryFile::CloneObject(const TObject *obj)
{
   
   
   
   
   
   TObject *newobj = (TObject *)obj->IsA()->New();
   if (!newobj) return 0;
   
   TFile *filsav = gFile;
   gFile = 0;
   const Int_t bufsize = 10000;
   TBuffer *buffer = new TBufferFile(TBuffer::kWrite,bufsize);
   buffer->MapObject(obj);  
   ((TObject*)obj)->Streamer(*buffer);
   
   buffer->SetReadMode();
   buffer->ResetMap();
   buffer->SetBufferOffset(0);
   buffer->MapObject(newobj);  
   newobj->Streamer(*buffer);
   newobj->ResetBit(kIsReferenced);
   newobj->ResetBit(kCanDelete);
   gFile = filsav;
   delete buffer;
   return newobj;
}
TObject *TDirectoryFile::FindObjectAnyFile(const char *name) const
{
   
   TFile *f;
   TIter next(gROOT->GetListOfFiles());
   while ((f = (TFile*)next())) {
      TObject *obj = f->GetList()->FindObject(name);
      if (obj) return obj;
   }
   return 0;
}
TDirectory *TDirectoryFile::GetDirectory(const char *apath,
                                     Bool_t printError, const char *funcname)
{
   
   
   
   
   
   
   
   
   
   
   Int_t nch = 0;
   if (apath) nch = strlen(apath);
   if (!nch) {
      return this;
   }
   if (funcname==0 || strlen(funcname)==0) funcname = "GetDirectory";
   TDirectory *result = this;
   char *path = new char[nch+1]; path[0] = 0;
   if (nch) strcpy(path,apath);
   char *s = (char*)strchr(path, ':');
   if (s) {
      *s = '\0';
      R__LOCKGUARD2(gROOTMutex);
      TDirectory *f = (TDirectory *)gROOT->GetListOfFiles()->FindObject(path);
      if (!f && !strcmp(gROOT->GetName(), path)) f = gROOT;
      if (s) *s = ':';
      if (f) {
         result = f;
         if (s && *(s+1)) result = f->GetDirectory(s+1,printError,funcname);
         delete [] path; return result;
      } else {
         if (printError) Error(funcname, "No such file %s", path);
         delete [] path; return 0;
      }
   }
   
   if (path[0] == '/') {
      TDirectory *td = fFile;
      if (!fFile) td = gROOT;
      result = td->GetDirectory(path+1,printError,funcname);
      delete [] path; return result;
   }
   TObject *obj;
   char *slash = (char*)strchr(path,'/');
   if (!slash) {                     
      if (!strcmp(path, "..")) {
         result = GetMotherDir();
         delete [] path; return result;
      }
      obj = Get(path);
      if (!obj) {
         if (printError) Error(funcname,"Unknown directory %s", path);
         delete [] path; return 0;
      }
      
      if (!obj->InheritsFrom(TDirectoryFile::Class())) {
         if (printError) Error(funcname,"Object %s is not a directory", path);
         delete [] path; return 0;
      }
      delete [] path; return (TDirectory*)obj;
   }
   char subdir[kMaxLen];
   strcpy(subdir,path);
   slash = (char*)strchr(subdir,'/');
   *slash = 0;
   
   if (!strcmp(subdir, "..")) {
      TDirectory* mom = GetMotherDir();
      if (mom)
         result = mom->GetDirectory(slash+1,printError,funcname);
      delete [] path; return result;
   }
   obj = Get(subdir);
   if (!obj) {
      if (printError) Error(funcname,"Unknown directory %s", subdir);
      delete [] path; return 0;
   }
   
   if (!obj->InheritsFrom(TDirectoryFile::Class())) {
      if (printError) Error(funcname,"Object %s is not a directory", subdir);
      delete [] path; return 0;
   }
   result = ((TDirectory*)obj)->GetDirectory(slash+1,printError,funcname);
   delete [] path; return result;
}
void TDirectoryFile::Close(Option_t *)
{
   
   if (!fList) {
      return;
   }
   
   Save();
   Bool_t fast = kTRUE;
   TObjLink *lnk = fList->FirstLink();
   while (lnk) {
      if (lnk->GetObject()->IsA() == TDirectoryFile::Class()) {fast = kFALSE;break;}
      lnk = lnk->Next();
   }
   
   
   
   
   
   if (fast) fList->Delete();
   else      fList->Delete("slow");
   
   if (fKeys) {
      fKeys->Delete("slow");
   }
   CleanTargets();
}
void TDirectoryFile::Delete(const char *namecycle)
{
   if (gDebug)
     Info("Delete","Call for this = %s namecycle = %s",
               GetName(), (namecycle ? namecycle : "null"));
   TDirectory::TContext ctxt(gDirectory, this);
   Short_t  cycle;
   char     name[kMaxLen];
   DecodeNameCycle(namecycle, name, cycle);
   Int_t deleteall    = 0;
   Int_t deletetree   = 0;
   if(strcmp(name,"*") == 0)   deleteall = 1;
   if(strcmp(name,"*T") == 0){ deleteall = 1; deletetree = 1;}
   if(strcmp(name,"T*") == 0){ deleteall = 1; deletetree = 1;}
   if(strlen(namecycle) == 0){ deleteall = 1; deletetree = 1;}
   TRegexp re(name,kTRUE);
   TString s;
   Int_t deleteOK = 0;
   if (cycle >= 9999 ) {
      TNamed *idcur;
      TIter   next(fList);
      while ((idcur = (TNamed *) next())) {
         deleteOK = 0;
         s = idcur->GetName();
         if (deleteall || s.Index(re) != kNPOS) {
            deleteOK = 1;
            if (idcur->IsA() == TDirectoryFile::Class()) {
               deleteOK = 2;
               if (!deletetree && deleteall) deleteOK = 0;
            }
         }
         if (deleteOK != 0) {
            fList->Remove(idcur);
            if (deleteOK==2) {
               
               if (deletetree)
                  ((TDirectory*) idcur)->ReadAll("dirs");
               idcur->Delete(deletetree ? "T*;*" : "*");
               delete idcur;
            } else
               idcur->Delete(name);
         }
      }
   }
   if (cycle != 9999 ) {
      if (IsWritable()) {
         TKey *key;
         TIter nextkey(GetListOfKeys());
         while ((key = (TKey *) nextkey())) {
            deleteOK = 0;
            s = key->GetName();
            if (deleteall || s.Index(re) != kNPOS) {
               if (cycle == key->GetCycle()) deleteOK = 1;
               if (cycle > 9999) deleteOK = 1;
               
               if (strstr(key->GetClassName(),"TDirectory")) {
                  deleteOK = 2;
                  if (!deletetree && deleteall) deleteOK = 0;
                  if (cycle == key->GetCycle()) deleteOK = 2;
               }
            }
            if (deleteOK) {
               if (deleteOK==2) {
                  
                  TDirectory* dir = GetDirectory(key->GetName(), kTRUE, "Delete");
                  if (dir!=0) {
                     dir->Delete("T*;*");
                     fList->Remove(dir);
                     delete dir;
                  }
               }
               key->Delete();
               fKeys->Remove(key);
               fModified = kTRUE;
               delete key;
            }
         }
         TFile* f = GetFile();
         if (fModified && (f!=0)) {
            WriteKeys();            
            WriteDirHeader();       
            f->WriteFree();     
            f->WriteHeader();   
         }
      }
   }
}
void TDirectoryFile::FillBuffer(char *&buffer)
{
   Version_t version = TDirectoryFile::Class_Version();
   if (fSeekKeys > TFile::kStartBigFile) version += 1000;
   tobuf(buffer, version);
   fDatimeC.FillBuffer(buffer);
   fDatimeM.FillBuffer(buffer);
   tobuf(buffer, fNbytesKeys);
   tobuf(buffer, fNbytesName);
   if (version > 1000) {
      tobuf(buffer, fSeekDir);
      tobuf(buffer, fSeekParent);
      tobuf(buffer, fSeekKeys);
   } else {
      tobuf(buffer, (Int_t)fSeekDir);
      tobuf(buffer, (Int_t)fSeekParent);
      tobuf(buffer, (Int_t)fSeekKeys);
   }
   fUUID.FillBuffer(buffer);
   if (fFile && fFile->GetVersion() < 40000) return;
   if (version <=1000) for (Int_t i=0;i<3;i++) tobuf(buffer,Int_t(0));
}
TKey *TDirectoryFile::FindKey(const char *keyname) const
{
   
   Short_t  cycle;
   char     name[kMaxLen];
   DecodeNameCycle(keyname, name, cycle);
   return GetKey(name,cycle);
}
TKey *TDirectoryFile::FindKeyAny(const char *keyname) const
{
   
   
   
   
   TDirectory *dirsav = gDirectory;
   Short_t  cycle;
   char     name[kMaxLen];
   DecodeNameCycle(keyname, name, cycle);
   TIter next(GetListOfKeys());
   TKey *key;
   while ((key = (TKey *) next())) {
      if (!strcmp(name, key->GetName()))
         if ((cycle == 9999) || (cycle >= key->GetCycle()))  {
            ((TDirectory*)this)->cd(); 
            return key;
         }
   }
   
   next.Reset();
   while ((key = (TKey *) next())) {
      
      if (strstr(key->GetClassName(),"TDirectory")) {
         TDirectory* subdir =
           ((TDirectory*)this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
         TKey *k = (subdir!=0) ? subdir->FindKeyAny(keyname) : 0;
         if (k) return k;
      }
   }
   if (dirsav) dirsav->cd();
   return 0;
}
TObject *TDirectoryFile::FindObjectAny(const char *aname) const
{
   
   
   
   
   
   
   TObject *obj = fList->FindObject(aname);
   if (obj) return obj;
   TDirectory *dirsav = gDirectory;
   Short_t  cycle;
   char     name[kMaxLen];
   DecodeNameCycle(aname, name, cycle);
   TIter next(GetListOfKeys());
   TKey *key;
   
   while ((key = (TKey *) next())) {
      if (!strcmp(name, key->GetName())) {
         if (cycle == 9999)             return key->ReadObj();
         if (cycle >= key->GetCycle())  return key->ReadObj();
      }
   }
   
   next.Reset();
   while ((key = (TKey *) next())) {
      
      if (strstr(key->GetClassName(),"TDirectory")) {
         TDirectory* subdir =
           ((TDirectory*)this)->GetDirectory(key->GetName(), kTRUE, "FindKeyAny");
         TKey *k = subdir==0 ? 0 : subdir->FindKeyAny(aname);
         if (k) { if (dirsav) dirsav->cd(); return k->ReadObj();}
      }
   }
   if (dirsav) dirsav->cd();
   return 0;
}
TObject *TDirectoryFile::Get(const char *namecycle)
{
   Short_t  cycle;
   char     name[kMaxLen];
   DecodeNameCycle(namecycle, name, cycle);
   char *namobj = name;
   Int_t nch = strlen(name);
   for (Int_t i = nch-1; i > 0; i--) {
      if (name[i] == '/') {
         name[i] = 0;
         TDirectory* dirToSearch=GetDirectory(name);
         namobj = name + i + 1;
         name[i] = '/';
         return dirToSearch?dirToSearch->Get(namobj):0;
      }
   }
   TObject *idcur = fList->FindObject(namobj);
   if (idcur) {
      if (idcur==this && strlen(namobj)!=0) {
         
         
         
         idcur = 0;
      } else if (cycle == 9999) {
         return idcur;
      } else {
         if (idcur->InheritsFrom(TCollection::Class()))
            idcur->Delete();  
         delete idcur;
         idcur = 0;
      }
   }
   TKey *key;
   TIter nextkey(GetListOfKeys());
   while ((key = (TKey *) nextkey())) {
      if (strcmp(namobj,key->GetName()) == 0) {
         if ((cycle == 9999) || (cycle == key->GetCycle())) {
            TDirectory::TContext ctxt(this);
            idcur = key->ReadObj();
            break;
         }
      }
   }
   return idcur;
}
void *TDirectoryFile::GetObjectUnchecked(const char *namecycle)
{
   return GetObjectChecked(namecycle,(TClass*)0);
}
void *TDirectoryFile::GetObjectChecked(const char *namecycle, const char* classname)
{
   return GetObjectChecked(namecycle,TClass::GetClass(classname));
}
void *TDirectoryFile::GetObjectChecked(const char *namecycle, const TClass* expectedClass)
{
   Short_t  cycle;
   char     name[kMaxLen];
   DecodeNameCycle(namecycle, name, cycle);
   char *namobj = name;
   Int_t nch = strlen(name);
   for (Int_t i = nch-1; i > 0; i--) {
      if (name[i] == '/') {
         name[i] = 0;
         TDirectory* dirToSearch=GetDirectory(name);
         namobj = name + i + 1;
         name[i] = '/';
         if (dirToSearch) {
            return dirToSearch->GetObjectChecked(namobj, expectedClass);
         } else {
            return 0;
         }
      }
   }
   if (expectedClass==0 || expectedClass->InheritsFrom(TObject::Class())) {
      TObject *objcur = fList->FindObject(namobj);
      if (objcur) {
         if (objcur==this && strlen(namobj)!=0) {
            
            
            
            objcur = 0;
         } else if (cycle == 9999) {
            
            if (expectedClass && objcur->IsA()->GetBaseClassOffset(expectedClass) == -1) return 0;
            else return objcur;
         } else {
            if (objcur->InheritsFrom(TCollection::Class()))
               objcur->Delete();  
            delete objcur;
            objcur = 0;
         }
      }
   }
   void *idcur = 0;
   TKey *key;
   TIter nextkey(GetListOfKeys());
   while ((key = (TKey *) nextkey())) {
      if (strcmp(namobj,key->GetName()) == 0) {
         if ((cycle == 9999) || (cycle == key->GetCycle())) {
            TDirectory::TContext ctxt(this);
            idcur = key->ReadObjectAny(expectedClass);
            break;
         }
      }
   }
   return idcur;
}
Int_t TDirectoryFile::GetBufferSize() const
{
   
   
   
   if (fBufferSize <= 0) return fFile->GetBestBuffer();
   else                  return fBufferSize;
}
TKey *TDirectoryFile::GetKey(const char *name, Short_t cycle) const
{
   TKey *key;
   TIter next(GetListOfKeys());
   while ((key = (TKey *) next()))
      if (!strcmp(name, key->GetName())) {
         if (cycle == 9999)             return key;
         if (cycle >= key->GetCycle())  return key;
      }
   return 0;
}
void TDirectoryFile::ls(Option_t *option) const
{
   TROOT::IndentLevel();
   cout <<ClassName()<<"*\t\t"<<GetName()<<"\t"<<GetTitle()<<endl;
   TROOT::IncreaseDirLevel();
   TString opta = option;
   TString opt  = opta.Strip(TString::kBoth);
   Bool_t memobj  = kTRUE;
   Bool_t diskobj = kTRUE;
   TString reg = "*";
   if (opt.BeginsWith("-m")) {
      diskobj = kFALSE;
      if (opt.Length() > 2)
         reg = opt(2,opt.Length());
   } else if (opt.BeginsWith("-d")) {
      memobj  = kFALSE;
      if (opt.Length() > 2)
         reg = opt(2,opt.Length());
   } else if (!opt.IsNull())
      reg = opt;
   TRegexp re(reg, kTRUE);
   if (memobj) {
      TObject *obj;
      TIter nextobj(fList);
      while ((obj = (TObject *) nextobj())) {
         TString s = obj->GetName();
         if (s.Index(re) == kNPOS) continue;
         obj->ls(option);            
      }
   }
   if (diskobj) {
      TKey *key;
      TIter next(GetListOfKeys());
      while ((key = (TKey *) next())) {
         TString s = key->GetName();
         if (s.Index(re) == kNPOS) continue;
         key->ls();                 
      }
   }
   TROOT::DecreaseDirLevel();
}
TFile *TDirectoryFile::OpenFile(const char *name, Option_t *option,const char *ftitle, Int_t compress, Int_t netopt)
{
   
   return TFile::Open(name,option,ftitle,compress,netopt);
}
TDirectory *TDirectoryFile::mkdir(const char *name, const char *title)
{
   
   
   
   
   if (!name || !title || !strlen(name)) return 0;
   if (!strlen(title)) title = name;
   if (strchr(name,'/')) {
      ::Error("TDirectoryFile::mkdir","directory name (%s) cannot contain a slash", name);
      return 0;
   }
   if (GetKey(name)) {
      Error("mkdir","An object with name %s exists already",name);
      return 0;
   }
   TDirectory::TContext ctxt(this);
   TDirectoryFile *newdir = new TDirectoryFile(name, title, "", this);
   return newdir;
}
void TDirectoryFile::Purge(Short_t)
{
   
   
   
   if (!IsWritable()) return;
   TDirectory::TContext ctxt(this);
   TKey  *key;
   TIter  prev(GetListOfKeys(), kIterBackward);
   while ((key = (TKey*)prev())) {      
      TKey *keyprev = (TKey*)GetListOfKeys()->Before(key);
      if (!keyprev) break;
      if (key->GetKeep() == 0) {
         if (strcmp(key->GetName(), keyprev->GetName()) == 0) key->Delete();
      }
   }
   TFile* f = GetFile();
   if (fModified && (f!=0)) {
      WriteKeys();                   
      WriteDirHeader();              
      f->WriteFree();                
      f->WriteHeader();              
   }
}
void TDirectoryFile::ReadAll(Option_t* opt)
{
   
   
   
   
   
   TDirectory::TContext ctxt(this);
   TKey *key;
   TIter next(GetListOfKeys());
   Bool_t readdirs = ((opt!=0) && ((strcmp(opt,"dirs")==0) || (strcmp(opt,"dirs*")==0)));
   if (readdirs)
      while ((key = (TKey *) next())) {
         
         if (strstr(key->GetClassName(),"TDirectory")==0) continue;
         TDirectory *dir = GetDirectory(key->GetName(), kTRUE, "ReadAll");
         if ((dir!=0) && (strcmp(opt,"dirs*")==0)) dir->ReadAll("dirs*");
      }
   else
      while ((key = (TKey *) next())) {
         TObject *thing = GetList()->FindObject(key->GetName());
         if (thing) { delete thing; }
         thing = key->ReadObj();
      }
}
Int_t TDirectoryFile::ReadKeys()
{
   if (fFile==0) return 0;
   if (!fFile->IsBinary())
      return fFile->DirReadKeys(this);
   TDirectory::TContext ctxt(this);
   fKeys->Delete();
   
   
   Int_t nbytes = fNbytesName + TDirectoryFile::Sizeof();
   char *header       = new char[nbytes];
   char *buffer       = header;
   fFile->Seek(fSeekDir);
   fFile->ReadBuffer(buffer,nbytes);
   buffer += fNbytesName;
   Version_t versiondir;
   frombuf(buffer,&versiondir);
   fDatimeC.ReadBuffer(buffer);
   fDatimeM.ReadBuffer(buffer);
   frombuf(buffer, &fNbytesKeys);
   frombuf(buffer, &fNbytesName);
   if (versiondir > 1000) {
      frombuf(buffer, &fSeekDir);
      frombuf(buffer, &fSeekParent);
      frombuf(buffer, &fSeekKeys);
   } else {
      Int_t sdir,sparent,skeys;
      frombuf(buffer, &sdir);    fSeekDir    = (Long64_t)sdir;
      frombuf(buffer, &sparent); fSeekParent = (Long64_t)sparent;
      frombuf(buffer, &skeys);   fSeekKeys   = (Long64_t)skeys;
   }
   delete [] header;
   Int_t nkeys = 0;
   Long64_t fsize = fFile->GetSize();
   if ( fSeekKeys >  0) {
      TKey *headerkey    = new TKey(fSeekKeys, fNbytesKeys, this);
      headerkey->ReadFile();
      buffer = headerkey->GetBuffer();
      headerkey->ReadKeyBuffer(buffer);
      TKey *key;
      frombuf(buffer, &nkeys);
      for (Int_t i = 0; i < nkeys; i++) {
         key = new TKey(this);
         key->ReadKeyBuffer(buffer);
         if (key->GetSeekKey() < 64 || key->GetSeekKey() > fsize) {
            Error("ReadKeys","reading illegal key, exiting after %d keys",i);
            fKeys->Remove(key);
            nkeys = i;
            break;
         }
         if (key->GetSeekPdir() < 64 || key->GetSeekPdir() > fsize) {
            Error("ReadKeys","reading illegal key, exiting after %d keys",i);
            fKeys->Remove(key);
            nkeys = i;
            break;
         }
         fKeys->Add(key);
      }
      delete headerkey;
   }
   return nkeys;
}
Int_t TDirectoryFile::ReadTObject(TObject *obj, const char *keyname)
{
   
   
   
   
   
   
   if (!fFile) { Error("Read","No file open"); return 0; }
   TKey *key = (TKey*)fKeys->FindObject(keyname);
   if (!key)   { Error("Read","Key not found"); return 0; }
   return key->Read(obj);
}
void TDirectoryFile::rmdir(const char *name)
{
   
   
   
   
   if ((name==0) || (*name==0)) return;
   TString mask(name);
   mask+=";*";
   Delete(mask);
}
void TDirectoryFile::Save()
{
   TDirectory::TContext ctxt(this);
   SaveSelf();
   
   if (fList) {
      TObject *idcur;
      TIter    next(fList);
      while ((idcur = next())) {
         if (idcur->InheritsFrom(TDirectoryFile::Class())) {
            TDirectoryFile *dir = (TDirectoryFile*)idcur;
            dir->Save();
         }
      }
   }
}
Int_t TDirectoryFile::SaveObjectAs(const TObject *obj, const char *filename, Option_t *option)
{
   
   
   
   
   
   
   if (!obj) return 0;
   TDirectory *dirsav = gDirectory;
   TString fname = filename;
   if (!filename || strlen(filename) == 0) {
      fname = Form("%s.root",obj->GetName());
   }
   TFile *local = TFile::Open(fname.Data(),"recreate");
   if (!local) return 0;
   Int_t nbytes = obj->Write();
   delete local;
   if (dirsav) dirsav->cd();
   TString opt = option;
   opt.ToLower();
   if (!opt.Contains("q")) {
      if (!gSystem->AccessPathName(fname.Data())) obj->Info("SaveAs", "ROOT file %s has been created", fname.Data());
   }
   return nbytes;
}
void TDirectoryFile::SaveSelf(Bool_t force)
{
   if (IsWritable() && (fModified || force) && fFile) {
      Bool_t dowrite = kTRUE;
      if (fFile->GetListOfFree())
        dowrite = fFile->GetListOfFree()->First() != 0;
      if (dowrite) {
         TDirectory *dirsav = gDirectory;
         if (dirsav != this) cd();
         WriteKeys();          
         WriteDirHeader();     
         if (dirsav && dirsav != this) dirsav->cd();
      }
   }
}
void TDirectoryFile::SetBufferSize(Int_t bufsize)
{
   
   
   fBufferSize = bufsize;
}
void TDirectoryFile::SetTRefAction(TObject *ref, TObject *parent)
{
   
   
   
   
   
   
   
   Int_t offset = (char*)ref - (char*)parent;
   TClass *cl = parent->IsA();
   cl->BuildRealData(parent);
   TStreamerInfo *info = (TStreamerInfo*)cl->GetStreamerInfo();
   TIter next(info->GetElements());
   TStreamerElement *element;
   while((element = (TStreamerElement*)next())) {
      if (element->GetOffset() != offset) continue;
      Int_t execid = element->GetExecID();
      if (execid > 0) ref->SetBit(execid << 8);
      return;
   }
}
void TDirectoryFile::SetWritable(Bool_t writable)
{
   TDirectory::TContext ctxt(this);
   fWritable = writable;
   
   if (fList) {
      TObject *idcur;
      TIter    next(fList);
      while ((idcur = next())) {
         if (idcur->InheritsFrom(TDirectoryFile::Class())) {
            TDirectoryFile *dir = (TDirectoryFile*)idcur;
            dir->SetWritable(writable);
         }
      }
   }
}
Int_t TDirectoryFile::Sizeof() const
{
   
   
   
   
   
   
   
   
   
   Int_t nbytes = 22;
   nbytes     += fDatimeC.Sizeof();
   nbytes     += fDatimeM.Sizeof();
   nbytes     += fUUID.Sizeof();
    
   if (fFile && fFile->GetVersion() >= 40000) nbytes += 12;
   return nbytes;
}
void TDirectoryFile::Streamer(TBuffer &b)
{
   Version_t v,version;
   if (b.IsReading()) {
      Build((TFile*)b.GetParent(), 0);
      if (fFile && fFile->IsWritable()) fWritable = kTRUE;
      if (fFile && !fFile->IsBinary()) {
         Version_t R__v = b.ReadVersion(0, 0);
         
         TClass* dirclass = (R__v < 5) ? TDirectory::Class() : TDirectoryFile::Class();
         
         b.ClassBegin(dirclass, R__v);
         TString sbuf;
         b.ClassMember("CreateTime","TString");
         sbuf.Streamer(b);
         TDatime timeC(sbuf.Data());
         fDatimeC = timeC;
         b.ClassMember("ModifyTime","TString");
         sbuf.Streamer(b);
         TDatime timeM(sbuf.Data());
         fDatimeM = timeM;
         b.ClassMember("UUID","TString");
         sbuf.Streamer(b);
         TUUID id(sbuf.Data());
         fUUID = id;
         b.ClassEnd(dirclass);
         fSeekKeys = 0; 
      } else {
         b >> version;
         fDatimeC.Streamer(b);
         fDatimeM.Streamer(b);
         b >> fNbytesKeys;
         b >> fNbytesName;
         if (version > 1000) {
            SetBit(kIsBigFile);
            b >> fSeekDir;
            b >> fSeekParent;
            b >> fSeekKeys;
         } else {
            Int_t sdir,sparent,skeys;
            b >> sdir;    fSeekDir    = (Long64_t)sdir;
            b >> sparent; fSeekParent = (Long64_t)sparent;
            b >> skeys;   fSeekKeys   = (Long64_t)skeys;
         }
         v = version%1000;
         if (v == 2) {
            fUUID.StreamerV1(b);
         } else if (v > 2) {
            fUUID.Streamer(b);
         }
      }
      R__LOCKGUARD2(gROOTMutex);
      gROOT->GetUUIDs()->AddUUID(fUUID,this);
      if (fSeekKeys) ReadKeys();
   } else {
      if (fFile && !fFile->IsBinary()) {
         b.WriteVersion(TDirectoryFile::Class());
         TString sbuf;
         b.ClassBegin(TDirectoryFile::Class());
         b.ClassMember("CreateTime","TString");
         sbuf = fDatimeC.AsSQLString();
         sbuf.Streamer(b);
         b.ClassMember("ModifyTime","TString");
         fDatimeM.Set();
         sbuf = fDatimeM.AsSQLString();
         sbuf.Streamer(b);
         b.ClassMember("UUID","TString");
         sbuf = fUUID.AsString();
         sbuf.Streamer(b);
         b.ClassEnd(TDirectoryFile::Class());
      } else {
         version = TDirectoryFile::Class_Version();
         if (fFile && fFile->GetEND() > TFile::kStartBigFile) version += 1000;
         b << version;
         fDatimeC.Streamer(b);
         fDatimeM.Streamer(b);
         b << fNbytesKeys;
         b << fNbytesName;
         if (version > 1000) {
            b << fSeekDir;
            b << fSeekParent;
            b << fSeekKeys;
         } else {
            b << (Int_t)fSeekDir;
            b << (Int_t)fSeekParent;
            b << (Int_t)fSeekKeys;
         }
         fUUID.Streamer(b);
         if (version <=1000) for (Int_t i=0;i<3;i++) b << Int_t(0);
      }
   }
}
Int_t TDirectoryFile::Write(const char *, Int_t opt, Int_t bufsize)
{
   
   
   
   
   
   if (!IsWritable()) return 0;
   TDirectory::TContext ctxt(this);
   
   TIter next(fList);
   TObject *obj;
   Int_t nbytes = 0;
   while ((obj=next())) {
      nbytes += obj->Write(0,opt,bufsize);
   }
   SaveSelf(kTRUE);   
   return nbytes;
}
Int_t TDirectoryFile::Write(const char *n, Int_t opt, Int_t bufsize) const
{
   
   Error("Write const","A const TDirectory object should not be saved. We try to proceed anyway.");
   return const_cast<TDirectoryFile*>(this)->Write(n, opt, bufsize);
}
Int_t TDirectoryFile::WriteTObject(const TObject *obj, const char *name, Option_t *option, Int_t bufsize)
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   TDirectory::TContext ctxt(this);
   if (fFile==0) return 0;
   if (!fFile->IsWritable()) {
      if (!fFile->TestBit(TFile::kWriteError)) {
         
         Error("WriteTObject","Directory %s is not writable", fFile->GetName());
      }
      return 0;
   }
   if (!obj) return 0;
   TString opt = option;
   opt.ToLower();
   TKey *key=0, *oldkey=0;
   Int_t bsize = GetBufferSize();
   if (bufsize > 0) bsize = bufsize;
   const char *oname;
   if (name && *name)
      oname = name;
   else
      oname = obj->GetName();
   
   Int_t nch = strlen(oname);
   char *newName = 0;
   if (oname[nch-1] == ' ') {
      newName = new char[nch+1];
      strcpy(newName,oname);
      for (Int_t i=0;i<nch;i++) {
         if (newName[nch-i-1] != ' ') break;
         newName[nch-i-1] = 0;
      }
      oname = newName;
   }
   if (opt.Contains("overwrite")) {
      
      
      key = GetKey(oname);
      if (key) {
         key->Delete();
         delete key;
      }
   }
   if (opt.Contains("writedelete")) {
      oldkey = GetKey(oname);
   }
   key = fFile->CreateKey(this, obj, oname, bsize);
   if (newName) delete [] newName;
   if (!key->GetSeekKey()) {
      fKeys->Remove(key);
      delete key;
      if (bufsize) fFile->SetBufferSize(bufsize);
      return 0;
   }
   fFile->SumBuffer(key->GetObjlen());
   Int_t nbytes = key->WriteFile(0);
   if (fFile->TestBit(TFile::kWriteError)) {
      if (bufsize) fFile->SetBufferSize(bufsize);
      return 0;
   }
   if (oldkey) {
      oldkey->Delete();
      delete oldkey;
   }
   if (bufsize) fFile->SetBufferSize(bufsize);
   return nbytes;
}
Int_t TDirectoryFile::WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option, Int_t bufsize)
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   TClass *cl = TClass::GetClass(classname);
   if (!cl) {
      Error("WriteObjectAny","Unknown class: %s",classname);
      return 0;
   }
   return WriteObjectAny(obj,cl,name,option,bufsize);
}
Int_t TDirectoryFile::WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option, Int_t bufsize)
{
   
   
   
   
   
   
   TDirectory::TContext ctxt(this);
   if (fFile==0) return 0;
   if (!fFile->IsWritable()) {
      if (!fFile->TestBit(TFile::kWriteError)) {
         
         Error("WriteObject","File %s is not writable", fFile->GetName());
      }
      return 0;
   }
   if (!obj || !cl) return 0;
   TKey *key, *oldkey=0;
   Int_t bsize = GetBufferSize();
   if (bufsize > 0) bsize = bufsize;
   TString opt = option;
   opt.ToLower();
   const char *oname;
   if (name && *name)
      oname = name;
   else
      oname = cl->GetName();
   
   Int_t nch = strlen(oname);
   char *newName = 0;
   if (oname[nch-1] == ' ') {
      newName = new char[nch+1];
      strcpy(newName,oname);
      for (Int_t i=0;i<nch;i++) {
         if (newName[nch-i-1] != ' ') break;
         newName[nch-i-1] = 0;
      }
      oname = newName;
   }
   if (opt.Contains("overwrite")) {
      
      
      key = GetKey(oname);
      if (key) {
         key->Delete();
         delete key;
      }
   }
   if (opt.Contains("writedelete")) {
      oldkey = GetKey(oname);
   }
   key = fFile->CreateKey(this, obj, cl, oname, bsize);
   if (newName) delete [] newName;
   if (!key->GetSeekKey()) {
      fKeys->Remove(key);
      delete key;
      return 0;
   }
   fFile->SumBuffer(key->GetObjlen());
   Int_t nbytes = key->WriteFile(0);
   if (fFile->TestBit(TFile::kWriteError)) return 0;
   if (oldkey) {
      oldkey->Delete();
      delete oldkey;
   }
   return nbytes;
}
void TDirectoryFile::WriteDirHeader()
{
   TFile* f = GetFile();
   if (f==0) return;
   if (!f->IsBinary()) {
      fDatimeM.Set();
      f->DirWriteHeader(this);
      return;
   }
   Int_t nbytes  = TDirectoryFile::Sizeof();  
   char * header = new char[nbytes];
   char * buffer = header;
   fDatimeM.Set();
   TDirectoryFile::FillBuffer(buffer);
   Long64_t pointer = fSeekDir + fNbytesName; 
   fModified     = kFALSE;
   f->Seek(pointer);
   f->WriteBuffer(header, nbytes);
   if (f->MustFlush()) f->Flush();
   delete [] header;
}
void TDirectoryFile::WriteKeys()
{
   TFile* f = GetFile();
   if (f==0) return;
   if (!f->IsBinary()) {
      f->DirWriteKeys(this);
      return;
   }
   if (fSeekKeys != 0) {
      f->MakeFree(fSeekKeys, fSeekKeys + fNbytesKeys -1);
   }
   TIter next(fKeys);
   TKey *key;
   Int_t nkeys  = fKeys->GetSize();
   Int_t nbytes = sizeof nkeys;          
   if (f->GetEND() > TFile::kStartBigFile) nbytes += 8;
   while ((key = (TKey*)next())) {
      nbytes += key->Sizeof();
   }
   TKey *headerkey  = new TKey(fName,fTitle,IsA(),nbytes,this);
   if (headerkey->GetSeekKey() == 0) {
      delete headerkey;
      return;
   }
   char *buffer = headerkey->GetBuffer();
   next.Reset();
   tobuf(buffer, nkeys);
   while ((key = (TKey*)next())) {
      key->FillBuffer(buffer);
   }
   fSeekKeys     = headerkey->GetSeekKey();
   fNbytesKeys   = headerkey->GetNbytes();
   headerkey->WriteFile();
   delete headerkey;
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.