// @(#)root/base:$Name: $:$Id: TDirectory.cxx,v 1.71 2005/08/31 19:42:21 pcanal Exp $
// Author: Rene Brun 28/11/94
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
#include "Riostream.h"
#include "Strlen.h"
#include "TDirectory.h"
#include "TMapFile.h"
#include "TClassTable.h"
#include "TInterpreter.h"
#include "THashList.h"
#include "TBrowser.h"
#include "TFree.h"
#include "TKey.h"
#include "TROOT.h"
#include "TError.h"
#include "Bytes.h"
#include "TClass.h"
#include "TRegexp.h"
#include "TProcessUUID.h"
#include "TVirtualMutex.h"
TDirectory *gDirectory; //Pointer to current directory in memory
const UInt_t kIsBigFile = BIT(16);
const Int_t kMaxLen = 2048;
//______________________________________________________________________________
//
/*
*/
//
ClassImp(TDirectory)
//______________________________________________________________________________
//
// A ROOT file is structured in Directories (like a file system).
// Each Directory has a list of Keys (see TKeys) and a list of objects
// in memory. A Key is a small object that describes the type and location
// of a persistent object in a file. The persistent object may be a directory.
//
/*
*/
//
//
// The structure of a file is shown in TFile::TFile
//
//______________________________________________________________________________
TDirectory::TDirectory() : TNamed(), fMother(0)
{
//*-*-*-*-*-*-*-*-*-*-*-*Directory default constructor-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =============================
fFile = 0;
fList = 0;
fKeys = 0;
fWritable = kFALSE;
fBufferSize = 0;
}
//______________________________________________________________________________
TDirectory::TDirectory(const char *name, const char *title, Option_t *classname)
: TNamed(name, title), fMother(0)
{
//*-*-*-*-*-*-*-*-*-*-*-* Create a new Directory *-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ======================
// A new directory with name,title is created in the current directory
// The directory header information is immediatly saved on the file
// A new key is added in the parent directory
//
// When this constructor is called from a class directly derived
// from TDirectory, the third argument classname MUST be specified.
// In this case, classname must be the name of the derived class.
//
// Note that the directory name cannot contain slashes.
//
if (strchr(name,'/')) {
::Error("TDirectory::TDirectory","directory name cannot contain a slash", name);
gDirectory = 0;
return;
}
if (strlen(GetName()) == 0) {
::Error("TDirectory::TDirectory","directory name cannot be \"\"");
gDirectory = 0;
return;
}
Build();
if (gDirectory == 0) return;
if (gFile == 0) return;
if (!gFile->IsWritable()) return; //*-* in case of a directory in memory
if (gDirectory->GetKey(name)) {
Error("TDirectory","An object with name %s exists already",name);
return;
}
TClass *cl = IsA();
if (strlen(classname) != 0) cl = gROOT->GetClass(classname);
if (!cl) {
Error("TDirectory","Invalid class name: %s",classname);
return;
}
fBufferSize = 0;
fWritable = kTRUE;
fSeekParent = gFile->GetSeekDir();
Int_t nbytes = TDirectory::Sizeof();
TKey *key = new TKey(fName,fTitle,cl,nbytes);
fNbytesName = key->GetKeylen();
fSeekDir = key->GetSeekKey();
if (fSeekDir == 0) return;
char *buffer = key->GetBuffer();
TDirectory::FillBuffer(buffer);
Int_t cycle = gDirectory->AppendKey(key);
key->WriteFile(cycle);
fModified = kFALSE;
R__LOCKGUARD2(gROOTMutex);
gROOT->GetUUIDs()->AddUUID(fUUID,this);
}
//______________________________________________________________________________
TDirectory::TDirectory(const TDirectory &directory) : TNamed(directory)
{
((TDirectory&)directory).Copy(*this);
}
//______________________________________________________________________________
TDirectory::~TDirectory()
{
//*-*-*-*-*-*-*-*-*-*-*-*Directory destructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ====================
if (gROOT == 0) return; //when called by TROOT destructor
TCollection::StartGarbageCollection();
if (fList) {
SetBit(kCloseDirectory);
fList->Delete();
SafeDelete(fList);
}
if (fKeys) {
fKeys->Delete();
SafeDelete(fKeys);
}
TCollection::EmptyGarbageCollection();
if (gDirectory==this) {
if (gFile!=this) gFile->cd();
else {
gDirectory = gROOT;
gFile = 0;
}
}
if (fMother && fMother->InheritsFrom(TDirectory::Class())) {
TDirectory *mom = (TDirectory*)fMother;
if (!mom->TestBit(TDirectory::kCloseDirectory))
mom->GetList()->Remove(this);
}
if (gDebug)
Info("~TDirectory", "dtor called for %s", GetName());
}
//______________________________________________________________________________
void TDirectory::Append(TObject *obj)
{
// Append object to this directory.
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 TDirectory::AppendKey(TKey *key)
{
//*-*-*-*-*-*-*Insert key in the linked list of keys of this directory*-*-*-*
//*-* =======================================================
fModified = kTRUE;
// This is a fast hash lookup in case the key does not already exist
TKey *oldkey = (TKey*)fKeys->FindObject(key->GetName());
if (!oldkey) {
fKeys->Add(key);
return 1;
}
// If the key name already exists we have to make a scan for it
// and insert the new key ahead of the current one
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 TDirectory::Browse(TBrowser *b)
{
Char_t name[kMaxLen];
if (b) {
TObject *obj = 0;
TIter nextin(fList);
TKey *key = 0, *keyo = 0;
TIter next(fKeys);
cd();
//Add objects that are only in memory
while ((obj = nextin())) {
if (fKeys->FindObject(obj->GetName())) continue;
b->Add(obj, obj->GetName());
}
//Add keys
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 TDirectory::Build()
{
//*-*-*-*-*-*-*-*-*-*-*-*Initialise directory to defaults*-*-*-*-*-*-*-*-*-*
//*-* ================================
// If directory is created via default ctor (when dir is read from file)
// don't add it here to the directory since its name is not yet known.
// It will be added to the directory in TKey::ReadObj().
if (gDirectory && strlen(GetName()) != 0) gDirectory->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 = gDirectory;
fFile = gFile;
SetBit(kCanDelete);
}
//______________________________________________________________________________
TDirectory *TDirectory::GetDirectory(const char *apath,
Bool_t printError, const char *funcname)
{
// Find a directory using apath.
// It apath is null or empty, returns "this" directory.
// Otherwie use apath to find a directory.
// The absolute path syntax is:
// file.root:/dir1/dir2
// where file.root is the file and /dir1/dir2 the desired subdirectory
// in the file. Relative syntax is relative to "this" directory. E.g:
// ../aa.
// Returns 0 in case path does not exist.
// If printError is true, use Error with 'funcname' to issue an error message.
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;
}
}
// path starts with a slash (assumes current file)
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) { // we are at the lowest level
if (!strcmp(path, "..")) {
if (fMother && fMother->InheritsFrom(TDirectory::Class()))
result = ((TDirectory*)fMother);
delete [] path; return result;
}
obj = Get(path);
if (!obj) {
if (printError) Error(funcname,"Unknown directory %s", path);
delete [] path; return 0;
}
//Check return object is a directory
if (!obj->InheritsFrom(TDirectory::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;
//Get object with path from current directory/file
if (!strcmp(subdir, "..")) {
if (fMother && fMother->InheritsFrom(TDirectory::Class())) {
result = ((TDirectory*)fMother)->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;
}
//Check return object is a directory
if (!obj->InheritsFrom(TDirectory::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;
}
//______________________________________________________________________________
Bool_t TDirectory::cd(const char *path)
{
// Change current directory to "this" directory . Using path one can
// change the current directory to "path". The absolute path syntax is:
// file.root:/dir1/dir2
// where file.root is the file and /dir1/dir2 the desired subdirectory
// in the file. Relative syntax is relative to "this" directory. E.g:
// ../aa. Returns kTRUE in case of success.
return cd1(path);
}
//______________________________________________________________________________
Bool_t TDirectory::cd1(const char *apath)
{
// Change current directory to "this" directory . Using path one can
// change the current directory to "path". The absolute path syntax is:
// file.root:/dir1/dir2
// where file.root is the file and /dir1/dir2 the desired subdirectory
// in the file. Relative syntax is relative to "this" directory. E.g:
// ../aa. Returns kFALSE in case path does not exist.
Int_t nch = 0;
if (apath) nch = strlen(apath);
if (!nch) {
gDirectory = this;
gFile = fFile;
return kTRUE;
}
TDirectory *where = GetDirectory(apath,kTRUE,"cd");
if (where) {
where->cd();
return kTRUE;
}
return kFALSE;
}
//______________________________________________________________________________
Bool_t TDirectory::Cd(const char *path)
{
// Change current directory to "path". The absolute path syntax is:
// file.root:/dir1/dir2
// where file.root is the file and /dir1/dir2 the desired subdirectory
// in the file. Relative syntax is relative to the current directory
// gDirectory, e.g.: ../aa. Returns kTRUE in case of success.
return Cd1(path);
}
//______________________________________________________________________________
Bool_t TDirectory::Cd1(const char *apath)
{
// Change current directory to "path". The path syntax is:
// file.root:/dir1/dir2
// where file.root is the file and /dir1/dir2 the desired subdirectory
// in the file. Returns kFALSE in case path does not exist.
// null path is always true (i.e. stay in the current directory)
Int_t nch = 0;
if (apath) nch = strlen(apath);
if (!nch) return kTRUE;
TDirectory *where = gDirectory->GetDirectory(apath,kTRUE,"Cd");
if (where) {
where->cd();
return kTRUE;
}
return kFALSE;
}
//______________________________________________________________________________
void TDirectory::Clear(Option_t *)
{
//*-*-*-*Delete all objects from a Directory list-*-*-*-*-*
//*-* =======================================
if (fList) fList->Clear();
}
//______________________________________________________________________________
void TDirectory::Close(Option_t *)
{
//*-*-*-*Delete all objects from memory and directory structure itself-*-*-*-*
// ============================================================
if (!fList) return;
TCollection::StartGarbageCollection();
TDirectory *cursav = gDirectory;
cd();
if (cursav == this)
cursav = (TDirectory*) fMother;
// Save the directory key list and header
//SaveSelf();
Save();
// Delete objects from directory list, this in turn, recursively closes all
// sub-directories (that were allocated on the heap)
SetBit(kCloseDirectory);
fList->Delete();
// Delete keys from key list (but don't delete the list header)
if (fKeys) fKeys->Delete();
if (cursav)
cursav->cd();
else {
gFile = 0;
if (this == gROOT)
gDirectory = 0;
else
gDirectory = gROOT;
}
TCollection::EmptyGarbageCollection();
}
//______________________________________________________________________________
void TDirectory::DeleteAll(Option_t *)
{
//*-*-*-*-*-*-*-*-*Delete all objects from memory*-*-*-*-*-*-*-*-*-*
// ==============================
SetBit(kCloseDirectory);
fList->Delete();
ResetBit(kCloseDirectory);
}
//______________________________________________________________________________
void TDirectory::Delete(const char *namecycle)
{
//*-*-*-*-*-*-*-* Delete Objects or/and keys in a directory *-*-*-*-*-*-*-*
//*-* =========================================
// namecycle has the format name;cycle
// namecycle = "" same as namecycle ="T*"
// name = * means all
// cycle = * means all cycles (memory and keys)
// cycle = "" or cycle = 9999 ==> apply to a memory object
// When name=* use T* to delete subdirectories also
//
// To delete one directory, you must specify the directory cycle,
// eg. file.Delete("dir1;1");
//
// examples:
// foo : delete object named foo in memory
// foo* : delete all objects with a name starting with foo
// foo;1 : delete cycle 1 of foo on file
// foo;* : delete all cycles of foo on file and also from memory
// *;2 : delete all objects on file having the cycle 2
// *;* : delete all objects from memory and file
// T*;* : delete all objects from memory and file and all subdirectories
//
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;
//*-*---------------------Case of Object in memory---------------------
// ========================
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() == TDirectory::Class()) {
deleteOK = 2;
if (!deletetree && deleteall) deleteOK = 0;
}
}
if (deleteOK != 0) idcur->Delete(name);
}
if (deleteOK == 2) delete fList->FindObject(name); //deleting a TDirectory
}
//*-*---------------------Case of Key---------------------
// ===========
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 (!strcmp(key->GetClassName(),"TDirectory")) {
if (!deletetree && deleteall) deleteOK = 0;
if (cycle == key->GetCycle()) deleteOK = 1;
}
}
if (deleteOK) {
key->Delete();
fKeys->Remove(key);
fModified = kTRUE;
}
}
if (fModified) {
WriteKeys(); //*-* Write new keys structure
WriteDirHeader(); //*-* Write new directory header
gFile->WriteFree(); //*-* Write new free segments list
gFile->WriteHeader(); //*-* Write new file header
}
}
}
}
//______________________________________________________________________________
void TDirectory::Draw(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*-*Fill Graphics Structure and Paint*-*-*-*-*-*-*-*-*-*
//*-* =================================
// Loop on all objects (memory or file) and all subdirectories
//
fList->ForEach(TObject,Draw)(option);
}
//______________________________________________________________________________
void TDirectory::FillBuffer(char *&buffer)
{
//*-*-*-*-*-*-*-*-*-*-*-*Encode directory header into output buffer*-*-*-*-*-*
//*-* =========================================
Version_t version = TDirectory::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 *TDirectory::FindKey(const char *keyname) const
{
// Find key with name keyname in the current directory
Short_t cycle;
char name[kMaxLen];
DecodeNameCycle(keyname, name, cycle);
return GetKey(name,cycle);
}
//______________________________________________________________________________
TKey *TDirectory::FindKeyAny(const char *keyname) const
{
// Find key with name keyname in the current directory or
// its subdirectories.
// NOTE that If a key is found, the directory containing the key becomes
// the current directory
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) return key;
if (cycle >= key->GetCycle()) return key;
}
}
//try with subdirectories
next.Reset();
while ((key = (TKey *) next())) {
if (!strcmp(key->GetClassName(),"TDirectory")) {
((TDirectory*)this)->cd(key->GetName());
TKey *k = gDirectory->FindKeyAny(keyname);
if (k) return k;
}
}
dirsav->cd();
return 0;
}
//______________________________________________________________________________
TObject *TDirectory::FindObject(const TObject *obj) const
{
// Find object in the list of memory objects.
return fList->FindObject(obj);
}
//______________________________________________________________________________
TObject *TDirectory::FindObject(const char *name) const
{
// Find object by name in the list of memory objects.
return fList->FindObject(name);
}
//______________________________________________________________________________
TObject *TDirectory::FindObjectAny(const char *aname) const
{
// Find object by name in the list of memory objects of the current
// directory or its sub-directories.
// After this call the current directory is not changed.
// To automatically set the current directory where the object is found,
// use FindKeyAny(aname)->ReadObj().
//object may be already in the list of objects in memory
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;
//may be a key in the current directory
while ((key = (TKey *) next())) {
if (!strcmp(name, key->GetName())) {
if (cycle == 9999) return key->ReadObj();
if (cycle >= key->GetCycle()) return key->ReadObj();
}
}
//try with subdirectories
next.Reset();
while ((key = (TKey *) next())) {
if (!strcmp(key->GetClassName(),"TDirectory")) {
((TDirectory*)this)->cd(key->GetName());
TKey *k = gDirectory->FindKeyAny(aname);
if (k) {dirsav->cd(); return k->ReadObj();}
}
}
dirsav->cd();
return 0;
}
//______________________________________________________________________________
TObject *TDirectory::Get(const char *namecycle)
{
// return pointer to object identified by namecycle
//
// namecycle has the format name;cycle
// name = * is illegal, cycle = * is illegal
// cycle = "" or cycle = 9999 ==> apply to a memory object
//
// examples:
// foo : get object named foo in memory
// if object is not in memory, try with highest cycle from file
// foo;1 : get cycle 1 of foo on file
//
// The retrieved object should in principle derive from TObject.
// If not, the function TDirectory::GetObject should be called.
// However, this function will still work for a non-TObject, providing that
// the calling application cast the return type to the correct type (which
// is the actual type of the object).
//
// NOTE:
// The method GetObject offer better protection and avoid the need
// for any cast:
// MyClass *obj;
// directory->GetObject("some object",obj);
// if (obj) { ... the object exist and inherits from MyClass ... }
//
// VERY IMPORTANT NOTE:
// In case the class of this object derives from TObject but not
// as a first inheritance, one must use dynamic_cast<>().
// Example 1: Normal case:
// class MyClass : public TObject, public AnotherClass
// then on return, one can do:
// MyClass *obj = (MyClass*)directory->Get("some object of MyClass");
//
// Example 2: Special case:
// class MyClass : public AnotherClass, public TObject
// then on return, one must do:
// MyClass *obj = dynamic_cast<MyClass*>(directory->Get("some object of MyClass"));
//
// Of course, dynamic_cast<> can also be used in the example 1.
//
Short_t cycle;
char name[kMaxLen];
TDirectory *cursav = gDirectory;
cd();
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;
cd(name);
namobj = name + i + 1;
name[i] = '/';
break;
}
}
//*-*---------------------Case of Object in memory---------------------
// ========================
TObject *idcur = fList->FindObject(namobj);
if (idcur) {
if (idcur==gDirectory && strlen(namobj)!=0) {
// The object has the same name has the directory and
// that's what we picked-up! We just need to ignore
// it ...
idcur = 0;
} else if (cycle == 9999) {
cursav->cd();
return idcur;
} else {
if (idcur->InheritsFrom(TCollection::Class()))
idcur->Delete(); // delete also list elements
delete idcur;
idcur = 0;
}
}
//*-*---------------------Case of Key---------------------
// ===========
TKey *key;
TIter nextkey(gDirectory->GetListOfKeys());
while ((key = (TKey *) nextkey())) {
if (strcmp(namobj,key->GetName()) == 0) {
if ((cycle == 9999) || (cycle == key->GetCycle())) {
idcur = key->ReadObj();
break;
}
}
}
cursav->cd();
return idcur;
}
//______________________________________________________________________________
void *TDirectory::GetObjectUnchecked(const char *namecycle)
{
// return pointer to object identified by namecycle.
// The returned object may or may not derive from TObject.
//
// namecycle has the format name;cycle
// name = * is illegal, cycle = * is illegal
// cycle = "" or cycle = 9999 ==> apply to a memory object
//
// VERY IMPORTANT NOTE:
// The calling application must cast the returned object to
// the final type, eg
// MyClass *obj = (MyClass*)directory->GetObject("some object of MyClass");
return GetObjectChecked(namecycle,(TClass*)0);
}
//_________________________________________________________________________________
void *TDirectory::GetObjectChecked(const char *namecycle, const char* classname)
{
// See documentation of TDirectory::GetObjectCheck(const char *namecycle, const TClass *cl)
return GetObjectChecked(namecycle,ROOT::GetROOT()->GetClass(classname));
}
//____________________________________________________________________________
void *TDirectory::GetObjectChecked(const char *namecycle, const TClass* cl)
{
// return pointer to object identified by namecycle if and only if the actual
// object is a type suitable to be stored as a pointer to a "cl"
// If cl is null, no check is performed.
//
// namecycle has the format name;cycle
// name = * is illegal, cycle = * is illegal
// cycle = "" or cycle = 9999 ==> apply to a memory object
//
// VERY IMPORTANT NOTE:
// The calling application must cast the returned pointer to
// the type described by the 2 arguments (i.e. cl):
// MyClass *obj = (MyClass*)directory->GetObjectChecked("some object of MyClass","MyClass"));
//
// Note: We recommend using the method TDirectory::GetObject:
// MyClass *obj = 0;
// directory->GetObject("some object inheriting from MyClass",obj);
// if (obj) { ... we found what we are looking for ... }
Short_t cycle;
char name[kMaxLen];
TDirectory *cursav = gDirectory;
cd();
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;
cd(name);
namobj = name + i + 1;
name[i] = '/';
break;
}
}
//*-*---------------------Case of Object in memory---------------------
// ========================
if (cl->InheritsFrom(TObject::Class())) {
TObject *objcur = fList->FindObject(namobj);
if (objcur) {
if (objcur==gDirectory && strlen(namobj)!=0) {
// The object has the same name has the directory and
// that's what we picked-up! We just need to ignore
// it ...
objcur = 0;
} else if (cycle == 9999) {
cursav->cd();
return objcur;
} else {
if (objcur->InheritsFrom(TCollection::Class()))
objcur->Delete(); // delete also list elements
delete objcur;
objcur = 0;
}
}
}
//*-*---------------------Case of Key---------------------
// ===========
void *idcur = 0;
TKey *key;
TIter nextkey(gDirectory->GetListOfKeys());
while ((key = (TKey *) nextkey())) {
if (strcmp(namobj,key->GetName()) == 0) {
if ((cycle == 9999) || (cycle == key->GetCycle())) {
idcur = key->ReadObjectAny(cl);
break;
}
}
}
cursav->cd();
return idcur;
}
//______________________________________________________________________________
Int_t TDirectory::GetBufferSize() const
{
// Return the buffer size to create new TKeys.
// If the stored fBufferSize is null, the value returned is the average
// buffer size of objects in the file so far.
if (fBufferSize <= 0) return fFile->GetBestBuffer();
else return fBufferSize;
}
//______________________________________________________________________________
TKey *TDirectory::GetKey(const char *name, Short_t cycle) const
{
//*-*-*-*-*-*-*-*-*-*-*Return pointer to key with name,cycle*-*-*-*-*-*-*-*
//*-* =====================================
// if cycle = 9999 returns highest cycle
//
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;
}
//______________________________________________________________________________
const char *TDirectory::GetPath() const
{
// Returns the full path of the directory. E.g. file:/dir1/dir2.
// The returned path will be re-used by the next call to GetPath().
static char *path = 0;
const int kMAXDEPTH = 128;
const TDirectory *d[kMAXDEPTH];
const TDirectory *cur = this;
int depth = 0, len = 0;
d[depth++] = cur;
len = strlen(cur->GetName()) + 1; // +1 for the /
while (cur->fMother && depth < kMAXDEPTH) {
cur = (TDirectory *)cur->fMother;
d[depth++] = cur;
len += strlen(cur->GetName()) + 1;
}
if (path) delete [] path;
path = new char[len+2];
for (int i = depth-1; i >= 0; i--) {
if (i == depth-1) { // file or TROOT name
strcpy(path, d[i]->GetName());
strcat(path, ":");
if (i == 0) strcat(path, "/");
} else {
strcat(path, "/");
strcat(path, d[i]->GetName());
}
}
return path;
}
//______________________________________________________________________________
TDirectory *TDirectory::mkdir(const char *name, const char *title)
{
// Create a sub-directory and return a pointer to the created directory.
// Returns 0 in case of error.
// Returns 0 if a directory with the same name already exists.
// Note that the directory name cannot contain slashes.
if (!name || !title || !strlen(name)) return 0;
if (!strlen(title)) title = name;
if (strchr(name,'/')) {
::Error("TDirectory::mkdir","directory name cannot contain a slash", name);
return 0;
}
if (GetKey(name)) {
Error("mkdir","An object with name %s exists already",name);
return 0;
}
TDirectory *cursav = gDirectory;
cd();
TDirectory *newdir = new TDirectory(name, title);
cursav->cd();
return newdir;
}
//______________________________________________________________________________
void TDirectory::ls(Option_t *option) const
{
//*-*-*-*-*-*-*-*-*-*-*-*List Directory contents*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =======================
// Indentation is used to identify the directory tree
// Subdirectories are listed first, then objects in memory, then objects on the file
//
// The option can has the following format:
// [-d |-m][<regexp>]
// Option -d means: only list objects in the file
// -m means: only list objects in memory
// The <regexp> will be used to match the name of the objects.
// By default memory and disk objects are listed.
//
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); //*-* Loop on all the objects in memory
}
}
if (diskobj) {
TKey *key;
TIter next(GetListOfKeys());
while ((key = (TKey *) next())) {
TString s = key->GetName();
if (s.Index(re) == kNPOS) continue;
key->ls(); //*-* Loop on all the keys
}
}
TROOT::DecreaseDirLevel();
}
//______________________________________________________________________________
void TDirectory::Paint(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*-*Paint all objects in the directory *-*-*-*-*-*-*-*
//*-* ==================================
//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
fList->ForEach(TObject,Paint)(option);
}
//______________________________________________________________________________
void TDirectory::Print(Option_t *option) const
{
//*-*-*-*-*-*-*-*-*-*-*-*Print all objects in the directory *-*-*-*-*-*-*-*
//*-* ==================================
//
fList->ForEach(TObject,Print)(option);
}
//______________________________________________________________________________
void TDirectory::Purge(Short_t)
{
// Purge lowest key cycles in a directory.
// By default, only the highest cycle of a key is kept. Keys for which
// the "KEEP" flag has been set are not removed. See TKey::Keep().
if (!IsWritable()) return;
TDirectory *cursav = gDirectory;
cd();
TKey *key;
TIter prev(GetListOfKeys(), kIterBackward);
while ((key = (TKey*)prev())) { // reverse loop on keys
TKey *keyprev = (TKey*)GetListOfKeys()->Before(key);
if (!keyprev) break;
if (key->GetKeep() == 0) {
if (strcmp(key->GetName(), keyprev->GetName()) == 0) key->Delete();
}
}
if (fModified) {
WriteKeys(); // Write new keys structure
WriteDirHeader(); // Write new directory header
gFile->WriteFree(); // Write new free segments list
gFile->WriteHeader(); // Write new file header
}
cursav->cd();
}
//______________________________________________________________________________
void TDirectory::pwd() const
{
// Print the path of the directory.
Printf("%s", GetPath());
}
//______________________________________________________________________________
void TDirectory::ReadAll(Option_t *)
{
// Read objects from a ROOT db file directory into memory.
// If an object is already in memory, the memory copy is deleted
// and the object is again read from the file.
TDirectory *cursav = gDirectory;
cd();
TKey *key;
TIter next(GetListOfKeys());
while ((key = (TKey *) next())) {
TNamed *thing = (TNamed*)gDirectory->GetList()->FindObject(key->GetName());
if (thing) { delete thing; }
key->ReadObj();
}
cursav->cd();
}
//______________________________________________________________________________
Int_t TDirectory::ReadKeys()
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Read the KEYS linked list*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =========================
// Every directory has a linked list (fKeys). This linked list has been
// written on the file via WriteKeys as a single data record.
//
// It is interesting to call this function in the following situation.
// Assume another process1 is connecting this directory in Update mode
// -Process1 is adding/updating objects in this directory
// -You want to see the latest status from process1.
// Example Process1:
// obj1.Write();
// obj2.Write();
// gDirectory->SaveSelf();
//
// Example Process2
// gDirectory->ReadKeys();
// obj1->Draw();
//
// This is an efficient way (without opening/closing files) to view
// the latest updates of a file being modified by another process
// as it is typically the case in a data acquisition system.
TDirectory *cursav = gDirectory;
cd();
fKeys->Delete();
//In case directory was updated by another process, read new
//position for the keys
Int_t nbytes = fNbytesName + TDirectory::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);
headerkey->ReadFile();
buffer = headerkey->GetBuffer();
headerkey->ReadBuffer(buffer);
if (fKeys->FindObject(headerkey)) {
// In some error cases headerkey->ReadBuffer will erroneously insert the
// header key in the list. To prevent further crashes (due to the deletion
// below) we remove it explicit and warn of potential problems.
Error("ReadKeys","Abnormal case while reading the header key. The %s (%s) is probably corrupted.",IsA()->GetName(),GetName());
fKeys->Remove(headerkey);
}
TKey *key;
frombuf(buffer, &nkeys);
for (Int_t i = 0; i < nkeys; i++) {
key = new TKey();
key->ReadBuffer(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;
}
cursav->cd();
return nkeys;
}
//______________________________________________________________________________
void TDirectory::RecursiveRemove(TObject *obj)
{
//*-*-*-*-*-*-*-*Recursively remove object from a Directory*-*-*-*-*-*-*-*
//*-* =========================================
fList->RecursiveRemove(obj);
}
//______________________________________________________________________________
void TDirectory::Save()
{
//*-*-*-*-*-*-*-*-*-*Save recursively all directory keys and headers-*-*-*-*-*
//*-* ===============================================
TDirectory *cursav = gDirectory;
cd();
SaveSelf();
// recursively save all sub-directories
if (fList) {
TObject *idcur;
TIter next(fList);
while ((idcur = next())) {
if (idcur->InheritsFrom(TDirectory::Class())) {
TDirectory *dir = (TDirectory*)idcur;
dir->Save();
}
}
}
cursav->cd();
}
//______________________________________________________________________________
void TDirectory::SaveSelf(Bool_t force)
{
//*-*-*-*-*-*-*-*-*-*Save Directory keys and header*-*-*-*-*-*-*-*-*-*-*-*
//*-* ==============================
// If the directory has been modified (fModified set), write the keys
// and the directory header. This function assumes the cd is correctly set.
//
// It is recommended to use this function in the following situation:
// Assume a process1 using a directory in Update mode
// -New objects or modified objects have been written to the directory
// -You do not want to close the file
// -You want your changes be visible from another process2 already connected
// to this directory in read mode
// -Call this function
// -In process2, use TDirectory::ReadKeys to refresh the directory
if (IsWritable() && (fModified || force)) {
TFree *f1 = (TFree*) fFile->GetListOfFree()->First();
if (f1) {
TDirectory *dirsav = gDirectory;
if (dirsav != this) cd();
WriteKeys(); //*-*- Write keys record
WriteDirHeader(); //*-*- Update directory record
if (dirsav && dirsav != this) dirsav->cd();
}
}
}
//______________________________________________________________________________
void TDirectory::SetBufferSize(Int_t bufsize)
{
// set the default buffer size when creating new TKeys
// see also TDirectory::GetBufferSize
fBufferSize = bufsize;
}
//______________________________________________________________________________
void TDirectory::SetWritable(Bool_t writable)
{
// Set the new value of fWritable recursively
TDirectory *cursav = gDirectory;
cd();
fWritable = writable;
// recursively set all sub-directories
if (fList) {
TObject *idcur;
TIter next(fList);
while ((idcur = next())) {
if (idcur->InheritsFrom(TDirectory::Class())) {
TDirectory *dir = (TDirectory*)idcur;
dir->SetWritable(writable);
}
}
}
cursav->cd();
}
//______________________________________________________________________________
Int_t TDirectory::Sizeof() const
{
//*-*-*-*-*-*-*Return the size in bytes of the directory header*-*-*-*-*-*-*
//*-* ================================================
//Int_t nbytes = sizeof(Version_t); 2
//nbytes += fDatimeC.Sizeof();
//nbytes += fDatimeM.Sizeof();
//nbytes += sizeof fNbytesKeys; 4
//nbytes += sizeof fNbytesName; 4
//nbytes += sizeof fSeekDir; 4 or 8
//nbytes += sizeof fSeekParent; 4 or 8
//nbytes += sizeof fSeekKeys; 4 or 8
//nbytes += fUUID.Sizeof();
Int_t nbytes = 22;
nbytes += fDatimeC.Sizeof();
nbytes += fDatimeM.Sizeof();
nbytes += fUUID.Sizeof();
//assume that the file may be above 2 Gbytes if file version is > 4
if (fFile && fFile->GetVersion() >= 40000) nbytes += 12;
return nbytes;
}
//_______________________________________________________________________
void TDirectory::Streamer(TBuffer &b)
{
//*-*-*-*-*-*-*-*-*Stream a class object*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =========================================
Version_t v,version;
if (b.IsReading()) {
Build();
if (fFile && fFile->IsWritable()) fWritable = kTRUE;
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 {
version = TDirectory::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 TDirectory::Write(const char *, Int_t opt, Int_t bufsiz)
{
// Write all objects in memory to disk.
// Loop on all objects in memory (including subdirectories).
// A new key is created in the KEYS linked list for each object.
// For allowed options see TObject::Write().
// The directory header info is rewritten on the directory header record.
if (!IsWritable()) return 0;
TDirectory *cursav = gDirectory;
cd();
// Loop on all objects (including subdirs)
TIter next(fList);
TObject *obj;
Int_t nbytes = 0;
while ((obj=next())) {
nbytes += obj->Write(0,opt,bufsiz);
}
SaveSelf(kTRUE); // force save itself
cursav->cd();
return nbytes;
}
//______________________________________________________________________________
Int_t TDirectory::Write(const char *n, Int_t opt, Int_t bufsize) const
{
// One can not save a const TDirectory object.
Error("Write const","A const TDirectory object should not be saved. We try to proceed anyway.");
return const_cast<TDirectory*>(this)->Write(n, opt, bufsize);
}
//____________________________________________________________________________________
Int_t TDirectory::WriteTObject(const TObject *obj, const char *name, Option_t *option)
{
// Write object obj to this directory
// The data structure corresponding to this object is serialized.
// The corresponding buffer is written to this directory
// with an associated key with name "name".
//
// Writing an object to a file involves the following steps:
//
// -Creation of a support TKey object in the directory.
// The TKey object creates a TBuffer object.
//
// -The TBuffer object is filled via the class::Streamer function.
//
// -If the file is compressed (default) a second buffer is created to
// hold the compressed buffer.
//
// -Reservation of the corresponding space in the file by looking
// in the TFree list of free blocks of the file.
//
// -The buffer is written to the file.
//
// By default, the buffersize will be taken from the average buffer size
// of all objects written to the current file so far.
// Use TDirectory::SetBufferSize to force a given buffer size.
//
// If a name is specified, it will be the name of the key.
// If name is not given, the name of the key will be the name as returned
// by obj->GetName().
//
// The option can be a combination of:
// "SingleKey", "Overwrite" or "WriteDelete"
// Using the "Overwrite" option a previous key with the same name is
// overwritten. The previous key is deleted before writing the new object.
// Using the "WriteDelete" option a previous key with the same name is
// deleted only after the new object has been written. This option
// is safer than kOverwrite but it is slower.
// The "SingleKey" option is only used by TCollection::Write() to write
// a container with a single key instead of each object in the container
// with its own key.
//
// An object is read from this directory via TDirectory::Get.
//
// The function returns the total number of bytes written to the directory.
// It returns 0 if the object cannot be written.
TDirectory::TContext ctxt(gDirectory, this);
if (!fFile->IsWritable()) {
if (!fFile->TestBit(TFile::kWriteError)) {
// Do not print the error if the file already had a SysError.
Error("WriteTObject","Directory %s is not writable", fFile->GetName());
}
return 0;
}
if (!obj) return 0;
TString opt = option;
opt.ToLower();
TKey *key, *oldkey=0;
Int_t bsize = GetBufferSize();
const char *oname;
if (name && *name)
oname = name;
else
oname = obj->GetName();
// Remove trailing blanks in object name
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")) {
//One must use GetKey. FindObject would return the lowest cycle of the key!
//key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
key = (TKey*)gDirectory->GetKey(oname);
if (key) {
key->Delete();
delete key;
}
}
if (opt.Contains("writedelete")) {
oldkey = (TKey*)gDirectory->GetKey(oname);
}
key = new TKey(obj, 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;
}
//______________________________________________________________________________
Int_t TDirectory::WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option)
{
// Write object from pointer of class classname in this directory
// obj may not derive from TObject
// see TDirectory::WriteObject for comments
//
// VERY IMPORTANT NOTE:
// The value passed as 'obj' needs to be from a pointer to the type described by classname
// For example with:
// TopClass *top;
// BottomClass *bottom;
// top = bottom;
// you can do:
// directory->WriteObjectAny(top,"top","name of object");
// directory->WriteObjectAny(bottom,"bottom","name of object");
// BUT YOU CAN NOT DO (it will fail in particular with multiple inheritance):
// directory->WriteObjectAny(top,"bottom","name of object");
//
// We STRONGLY recommend to use
// TopClass *top = ....;
// directory->WriteObject(top,"name of object")
TClass *cl = ROOT::GetROOT()->GetClass(classname);
if (!cl) {
Error("WriteObjectAny","Unknown class: %s",classname);
return 0;
}
return WriteObjectAny(obj,cl,name,option);
}
//______________________________________________________________________________
Int_t TDirectory::WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option)
{
// Write object of class with dictionary cl in this directory
// obj may not derive from TObject
// To get the TClass* cl pointer, one can use
// TClass *cl = gROOT->GetClass("classname");
// An alternative is to call the function WriteObjectAny above.
// see TDirectory::WriteObject for comments
TDirectory::TContext ctxt(gDirectory, this);
if (!fFile->IsWritable()) {
if (!fFile->TestBit(TFile::kWriteError)) {
// Do not print the error if the file already had a SysError.
Error("WriteObject","Directory %s is not writable", fFile->GetName());
}
return 0;
}
if (!obj || !cl) return 0;
TKey *key, *oldkey=0;
Int_t bsize = GetBufferSize();
TString opt = option;
opt.ToLower();
const char *oname;
if (name && *name)
oname = name;
else
oname = cl->GetName();
// Remove trailing blanks in object name
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")) {
//One must use GetKey. FindObject would return the lowest cycle of the key!
//key = (TKey*)gDirectory->GetListOfKeys()->FindObject(oname);
key = (TKey*)gDirectory->GetKey(oname);
if (key) {
key->Delete();
delete key;
}
}
if (opt.Contains("writedelete")) {
oldkey = (TKey*)gDirectory->GetKey(oname);
}
key = new TKey(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 TDirectory::WriteDirHeader()
{
//*-*-*-*-*-*-*-*-*-*-*Overwrite the Directory header record*-*-*-*-*-*-*-*-*
//*-* =====================================
Int_t nbytes = TDirectory::Sizeof(); //Warning ! TFile has a Sizeof()
char * header = new char[nbytes];
char * buffer = header;
fDatimeM.Set();
TDirectory::FillBuffer(buffer);
Long64_t pointer= fSeekDir + fNbytesName; // do not overwrite the name/title part
fModified = kFALSE;
gFile->Seek(pointer);
gFile->WriteBuffer(header, nbytes);
gFile->Flush();
delete [] header;
}
//______________________________________________________________________________
void TDirectory::WriteKeys()
{
//*-*-*-*-*-*-*-*-*-*-*-*Write KEYS linked list on the file *-*-*-*-*-*-*-*
//*-* ==================================
// The linked list of keys (fKeys) is written as a single data record
//
//*-* Delete the old keys structure if it exists
if (fSeekKeys != 0) {
gFile->MakeFree(fSeekKeys, fSeekKeys + fNbytesKeys -1);
}
//*-* Write new keys record
TIter next(fKeys);
TKey *key;
Int_t nkeys = fKeys->GetSize();
Int_t nbytes = sizeof nkeys; //*-* Compute size of all keys
if (gFile && gFile->GetEND() > TFile::kStartBigFile) nbytes += 8;
while ((key = (TKey*)next())) {
nbytes += key->Sizeof();
}
TKey *headerkey = new TKey(fName,fTitle,IsA(),nbytes);
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;
}
//______________________________________________________________________________
void TDirectory::EncodeNameCycle(char *buffer, const char *name, Short_t cycle)
{
// Encode the name and cycle into buffer like: "aap;2".
if (cycle == 9999)
strcpy(buffer, name);
else
sprintf(buffer, "%s;%d", name, cycle);
}
//______________________________________________________________________________
void TDirectory::DecodeNameCycle(const char *buffer, char *name, Short_t &cycle)
{
// Decode a namecycle "aap;2" into name "aap" and cycle "2".
cycle = 9999;
Int_t nch = buffer ? strlen(buffer) : 0;
for (Int_t i = 0; i < nch; i++) {
if (buffer[i] != ';')
name[i] = buffer[i];
else {
name[i] = 0;
if (i < nch-1 )
if (buffer[i+1] == '*') {
cycle = 10000;
return;
}
sscanf(buffer+i+1, "%hd", &cycle);
return;
}
}
name[nch] = 0;
}
//______________________________________________________________________________
void TDirectory::TContext::CdNull()
{
// Set the current directory to null.
// This is called from the TContext destructor. Since the destructor is
// inline, we do no want to have it use directly a global variable.
gDirectory = 0;
}
ROOT page - Class index - Class Hierarchy - Top of the page
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.