00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
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;
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
00152 ((TDirectoryFile&)directory).Copy(*this);
00153 }
00154
00155
00156 TDirectoryFile::~TDirectoryFile()
00157 {
00158
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 )
00174 {
00175
00176
00177
00178
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
00195
00196
00197 fModified = kTRUE;
00198
00199 key->SetMotherDir(this);
00200
00201
00202 TKey *oldkey = (TKey*)fKeys->FindObject(key->GetName());
00203 if (!oldkey) {
00204 fKeys->Add(key);
00205 return 1;
00206 }
00207
00208
00209
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
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
00238 while ((obj = nextin())) {
00239 if (fKeys->FindObject(obj->GetName())) continue;
00240 b->Add(obj, obj->GetName());
00241 }
00242
00243
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
00271
00272
00273
00274
00275
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
00298
00299
00300
00301
00302
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
00313
00314 TDirectory::CleanTargets();
00315
00316
00317
00318 if (gFile == this) {
00319 gFile = 0;
00320 }
00321 }
00322
00323
00324 TObject *TDirectoryFile::CloneObject(const TObject *obj, Bool_t autoadd )
00325 {
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
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
00343
00344
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
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);
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
00366 buffer->SetReadMode();
00367 buffer->ResetMap();
00368 buffer->SetBufferOffset(0);
00369 buffer->MapObject(newobj);
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
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
00407
00408
00409
00410
00411
00412
00413
00414
00415
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
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) {
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
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
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
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
00504
00505 if (!fList || !fSeekDir) {
00506 return;
00507 }
00508
00509
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
00519
00520
00521
00522
00523 if (fast) fList->Delete();
00524 else fList->Delete("slow");
00525
00526
00527 if (fKeys) {
00528 fKeys->Delete("slow");
00529 }
00530
00531 CleanTargets();
00532 }
00533
00534
00535 void TDirectoryFile::Delete(const char *namecycle)
00536 {
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
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
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
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
00611
00612
00613
00614 }
00615
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
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
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();
00654 WriteDirHeader();
00655 f->WriteFree();
00656 f->WriteHeader();
00657 }
00658 }
00659 }
00660 }
00661
00662
00663 void TDirectoryFile::FillBuffer(char *&buffer)
00664 {
00665
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
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
00704
00705
00706
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();
00720 return key;
00721 }
00722 }
00723
00724 next.Reset();
00725 while ((key = (TKey *) next())) {
00726
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
00742
00743
00744
00745
00746
00747
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
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
00767 next.Reset();
00768 while ((key = (TKey *) next())) {
00769
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
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
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
00841
00842 TObject *idcur = fList->FindObject(namobj);
00843 if (idcur) {
00844 if (idcur==this && strlen(namobj)!=0) {
00845
00846
00847
00848 idcur = 0;
00849 } else if (cycle == 9999) {
00850 return idcur;
00851 } else {
00852 if (idcur->InheritsFrom(TCollection::Class()))
00853 idcur->Delete();
00854 delete idcur;
00855 idcur = 0;
00856 }
00857 }
00858
00859
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
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891 return GetObjectChecked(namecycle,(TClass*)0);
00892 }
00893
00894
00895 void *TDirectoryFile::GetObjectChecked(const char *namecycle, const char* classname)
00896 {
00897
00898
00899 return GetObjectChecked(namecycle,TClass::GetClass(classname));
00900 }
00901
00902
00903
00904 void *TDirectoryFile::GetObjectChecked(const char *namecycle, const TClass* expectedClass)
00905 {
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
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
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
00951
00952
00953 objcur = 0;
00954 } else if (cycle == 9999) {
00955
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();
00961 delete objcur;
00962 objcur = 0;
00963 }
00964 }
00965 }
00966
00967
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
00989
00990
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
01001
01002
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
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
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);
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();
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
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
01087
01088
01089
01090
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
01123
01124
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())) {
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();
01139 delete key;
01140 }
01141 }
01142 }
01143 TFile* f = GetFile();
01144 if (fModified && (f!=0)) {
01145 WriteKeys();
01146 WriteDirHeader();
01147 f->WriteFree();
01148 f->WriteHeader();
01149 }
01150 }
01151
01152
01153 void TDirectoryFile::ReadAll(Option_t* opt)
01154 {
01155
01156
01157
01158
01159
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
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
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
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
01222
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
01286
01287
01288
01289
01290
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
01302
01303
01304
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
01317
01318
01319 TDirectory::TContext ctxt(this);
01320
01321 SaveSelf();
01322
01323
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
01340
01341
01342
01343
01344
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
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
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();
01390 WriteDirHeader();
01391 if (dirsav && dirsav != this) dirsav->cd();
01392 }
01393 }
01394 }
01395
01396
01397 void TDirectoryFile::SetBufferSize(Int_t bufsize)
01398 {
01399
01400
01401
01402 fBufferSize = bufsize;
01403 }
01404
01405
01406 void TDirectoryFile::SetTRefAction(TObject *ref, TObject *parent)
01407 {
01408
01409
01410
01411
01412
01413
01414
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
01434
01435 TDirectory::TContext ctxt(this);
01436
01437 fWritable = writable;
01438
01439
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
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467 Int_t nbytes = 22;
01468
01469 nbytes += fDatimeC.Sizeof();
01470 nbytes += fDatimeM.Sizeof();
01471 nbytes += fUUID.Sizeof();
01472
01473 if (fFile && fFile->GetVersion() >= 40000) nbytes += 12;
01474 return nbytes;
01475 }
01476
01477
01478
01479 void TDirectoryFile::Streamer(TBuffer &b)
01480 {
01481
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;
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
01592
01593
01594
01595
01596
01597 if (!IsWritable()) return 0;
01598 TDirectory::TContext ctxt(this);
01599
01600
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);
01608
01609 return nbytes;
01610 }
01611
01612
01613 Int_t TDirectoryFile::Write(const char *n, Int_t opt, Int_t bufsize) const
01614 {
01615
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
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
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
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
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
01719
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
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
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
01796
01797
01798
01799
01800
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
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
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
01843
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
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();
01888 char * header = new char[nbytes];
01889 char * buffer = header;
01890 fDatimeM.Set();
01891 TDirectoryFile::FillBuffer(buffer);
01892 Long64_t pointer = fSeekDir + fNbytesName;
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
01904
01905
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
01917 if (fSeekKeys != 0) {
01918 f->MakeFree(fSeekKeys, fSeekKeys + fNbytesKeys -1);
01919 }
01920
01921 TIter next(fKeys);
01922 TKey *key;
01923 Int_t nkeys = fKeys->GetSize();
01924 Int_t nbytes = sizeof nkeys;
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 }