source: trunk/MagicSoft/Mars/mfileio/MWriteRootFile.cc@ 6292

Last change on this file since 6292 was 6245, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 29.4 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 6/2001 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2005
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MWriteRootFile
28//
29// This is a writer to store several containers to a root file.
30// The containers are added with AddContainer.
31// To understand how it works, see base class MWriteFile
32//
33// Warning: Look at the Warning in MTaskList.
34//
35// There is a special mode of operation which opens a new file for each new
36// file read by the reading task (opening the new file is initiated by
37// ReInit()) For more details se the corresponding constructor.
38//
39// Memory based trees
40// ------------------
41// It is possible to store the data into memory (TTrees) instead of
42// writing the data into a file. To do this either call the default
43// constructor or specify 'memory' as option in the constructor.
44//
45// Afterwards the tree can be found using gROOT->FindObject("treename")
46//
47// Currently(!) the tree is not deleted at all! Please make sure to
48// delete it if it is not used anymore - otherwise you could wast a LOT
49// of memory. Please consider that this behaviour might change in the
50// future.
51//
52// Such trees are usefull if you want to use more basic root-tools
53// like TMultiLayerPerceptron or TEventList.
54//
55// If you want to process such memory based Trees using Mars make sure,
56// that you don't need data from the RunHeader tree because you can
57// only use MReadTree but not MReadMarsFile with such a tree.
58//
59/////////////////////////////////////////////////////////////////////////////
60#include "MWriteRootFile.h"
61
62#include <fstream>
63
64#include <TFile.h>
65#include <TTree.h>
66#include <TRegexp.h>
67
68#include "MLog.h"
69#include "MLogManip.h"
70
71#include "MRead.h"
72#include "MParList.h"
73
74ClassImp(MRootFileBranch);
75ClassImp(MWriteRootFile);
76
77using namespace std;
78
79const TString MWriteRootFile::gsDefName = "MWriteRootFile";
80const TString MWriteRootFile::gsDefTitle = "Task which writes a root-output file";
81
82void MWriteRootFile::Init(const char *name, const char *title)
83{
84 fName = name ? name : gsDefName.Data();
85 fTitle = title ? title : gsDefTitle.Data();
86
87 //
88 // Set the Arrays the owner of its entries. This means, that the
89 // destructor of the arrays will delete all its entries.
90 //
91 fBranches.SetOwner();
92
93 //
94 // Believing the root user guide, TTree instances are owned by the
95 // directory (file) in which they are. This means we don't have to
96 // care about their destruction.
97 //
98 //fTrees.SetOwner();
99}
100
101// --------------------------------------------------------------------------
102//
103// Default constructor. It is there to support some root stuff.
104// Don't use it.
105//
106MWriteRootFile::MWriteRootFile() : fOut(NULL)
107{
108 Init();
109}
110
111// --------------------------------------------------------------------------
112//
113// Use this constructor to run in a special mode.
114//
115// In this mode for each input file a new output file is written. This
116// happens in ReInit.
117//
118// comp: Compression Level (see TFile, TBranch)
119// rule: Rule to create output file name (see GetNewFileName())
120// overwrite: Allow newly created file to overwrite old files ("RECREATE")
121// ftitle: File title stored in the file (see TFile)
122// name, title: Name and title of this object
123//
124MWriteRootFile::MWriteRootFile(const Int_t comp,
125 const char *rule,
126 const Bool_t overwrite,
127 const char *ftitle,
128 const char *name,
129 const char *title) : fSplitRule(rule)
130{
131 Init(name, title);
132
133 //
134 // Open a TFile in dummy mode! This is necessary to be able to create
135 // the trees and branches, which are then (in ReInit) moved to
136 // a valid file. (Stupid workaround - but does a good job)
137 //
138 fOut = new TFile("/dev/null", overwrite?"RECREATE":"NEW", ftitle, comp);
139}
140
141// --------------------------------------------------------------------------
142//
143// Specify the name of the root file. You can also give an option ("UPDATE"
144// and "RECREATE" would make sense only) as well as the file title and
145// compression factor. To a more detaild description of the options see
146// TFile.
147//
148// To create a memory based TTree use
149// fname = name of TTree
150// option = "memory"
151// Make sure you do not read from a tree with the same name!
152//
153MWriteRootFile::MWriteRootFile(const char *fname,
154 const Option_t *option,
155 const char *ftitle,
156 const Int_t comp,
157 const char *name,
158 const char *title) : fOut(NULL)
159{
160 Init(name, title);
161
162 TString opt(option);
163 opt.ToLower();
164
165 //
166 // Check if we are writing to memory
167 //
168 if (opt.Contains("memory", TString::kIgnoreCase))
169 {
170 fSplitRule = fname;
171 return;
172 }
173
174 //
175 // If no name is given we open the TFile in some kind of dummy mode...
176 //
177 if (!fname)
178 {
179 fOut = new TFile("/dev/null", "READ", ftitle, comp);
180 return;
181 }
182
183 TString str(fname);
184 if (!str.EndsWith(".root", TString::kIgnoreCase))
185 str += ".root";
186
187 //
188 // Open the rootfile
189 //
190 fOut = new TFile(str, opt, ftitle, comp);
191}
192
193// --------------------------------------------------------------------------
194//
195// Prints some statistics about the file to the screen. And closes the file
196// properly.
197//
198void MWriteRootFile::Close()
199{
200 //
201 // Print some statistics to the looging out.
202 //
203 Print();
204
205 if (fOut)
206 {
207 //
208 // If the file is still open (no error) write the keys. This is necessary
209 // for appearance of the all trees and branches.
210 //
211 if (IsFileOpen())
212 fOut->Write();
213
214 //
215 // Delete the file. This'll also close the file (if open)
216 //
217 delete fOut;
218 fOut = 0;
219 }
220
221 //
222 // Remark:
223 // - Trees are automatically deleted by the the file
224 // (unless file.SetDirectory(0) was called)
225 // - Branches are automatically deleted by the tree destructor
226 //
227
228 *fLog << inf << "Output File closed and object deleted." << endl;
229}
230
231// --------------------------------------------------------------------------
232//
233// call Close()
234//
235MWriteRootFile::~MWriteRootFile()
236{
237 Close();
238}
239
240// --------------------------------------------------------------------------
241//
242// Prints all trees with the actually number of written entries to log-out.
243//
244void MWriteRootFile::Print(Option_t *) const
245{
246 *fLog << all << underline << "File: " << GetFileName() << endl;
247
248 if (fTrees.GetEntries()==0)
249 {
250 *fLog << " No contents." << endl;
251 return;
252 }
253
254 TObject *obj;
255 TIter NextBranch(&fBranches);
256 while ((obj=NextBranch()))
257 {
258 MRootFileBranch *b = (MRootFileBranch*)obj;
259
260 if (!b->GetTree() || b->GetTree()->TestBit(kIsNewTree))
261 continue;
262
263 TBranch *branch = b->GetBranch();
264
265 TString name = b->GetTree()->GetName();
266 name += '.';
267 name += branch->GetName();
268
269 *fLog << " " << name.Strip(TString::kTrailing, '.') << ": \t" << (ULong_t)branch->GetEntries() << " entries." << endl;
270 }
271
272 TTree *t = NULL;
273 TIter NextTree(&fTrees);
274 while ((t=(TTree*)NextTree()))
275 if (t->TestBit(kIsNewTree))
276 *fLog << " " << t->GetName() << ": \t" << (ULong_t)t->GetEntries() << " entries." << endl;
277 *fLog << endl;
278}
279
280// --------------------------------------------------------------------------
281//
282// Add a new Container to list of containers which should be written to the
283// file. Give the name of the container which will identify the container
284// in the parameterlist. tname is the name of the tree to which the
285// container should be written (Remark: one tree can hold more than one
286// container). The default is the same name as the container name.
287// You can slso specify a title for the tree. This is only
288// used the first time this tree in 'mentioned'. As default the title
289// is the name of the tree.
290//
291void MWriteRootFile::AddContainer(const char *cname, const char *tname, Bool_t must)
292{
293 if (!fOut && !tname)
294 tname = fSplitRule;
295
296 TIter Next(&fBranches);
297 TObject *o=0;
298 while ((o=Next()))
299 if (TString(o->GetName())==TString(tname) && TString(o->GetTitle())==TString(cname))
300 {
301 *fLog << warn;
302 *fLog << "WARNING - Container '" << cname << "' in Tree '" << tname << "' already scheduled... ignored." << endl;
303 return;
304 }
305
306 //
307 // create a new entry in the list of branches to write and
308 // add the entry to the list.
309 //
310 MRootFileBranch *entry = new MRootFileBranch(AddSerialNumber(cname), tname, must);
311 fBranches.AddLast(entry);
312
313 if (tname && tname[0])
314 AddToBranchList(Form("%s.%s", (const char*)AddSerialNumber(cname), tname));
315}
316
317// --------------------------------------------------------------------------
318//
319// Add a new Container to list of containers which should be written to the
320// file. Give the pointer to the container. tname is the name of the tree to
321// which the container should be written (Remark: one tree can hold more than
322// one container). The default is the same name as the container name.
323// You can slso specify a title for the tree. This is only
324// used the first time this tree in 'mentioned'. As default the title
325// is the name of the tree.
326//
327void MWriteRootFile::AddContainer(MParContainer *cont, const char *tname,
328 Bool_t must)
329{
330 if (!fOut && !tname)
331 tname = fSplitRule;
332
333 TIter Next(&fBranches);
334 TObject *o=0;
335 while ((o=Next()))
336 if (TString(o->GetName())==TString(tname) &&
337 static_cast<MRootFileBranch*>(o)->GetContainer()==cont)
338 {
339 *fLog << warn;
340 *fLog << "WARNING - Container " << cont << " in Tree '" << tname << "' already scheduled... ignored." << endl;
341 return;
342 }
343
344 //
345 // create a new entry in the list of branches to write and
346 // add the entry to the list.
347 //
348 MRootFileBranch *entry = new MRootFileBranch(cont, tname, must);
349 fBranches.AddLast(entry);
350}
351
352// --------------------------------------------------------------------------
353//
354// Add a new Container to list of containers which should be written to the
355// file. Give the pointer to the container. tname is the name of the tree to
356// which the container should be written (Remark: one tree can hold more than
357// one container). The default is the same name as the container name.
358// You can slso specify a title for the tree. This is only
359// used the first time this tree in 'mentioned'. As default the title
360// is the name of the tree.
361//
362Bool_t MWriteRootFile::GetContainer(MParList *pList)
363{
364 //
365 // loop over all branches which are 'marked' as branches to get written.
366 //
367 MRootFileBranch *entry;
368
369 TIter Next(&fBranches);
370 while ((entry=(MRootFileBranch*)Next()))
371 {
372 //
373 // Get the pointer to the container. If the pointer is NULL it seems,
374 // that the user identified the container by name.
375 //
376 MParContainer *cont = entry->GetContainer();
377 if (!cont)
378 {
379 //
380 // Get the name and try to find a container with this name
381 // in the parameter list.
382 //
383 const char *cname = entry->GetContName();
384 cont = (MParContainer*)pList->FindObject(cname);
385 if (!cont)
386 {
387 //
388 // No corresponding container is found
389 //
390 if (entry->MustHave())
391 {
392 *fLog << err << "Cannot find parameter container '" << cname << "'." << endl;
393 return kFALSE;
394 }
395
396 *fLog << inf << "Unnecessary parameter container '" << cname << "' not found..." << endl;
397 delete fBranches.Remove(entry);
398 continue;
399 }
400
401 //
402 // The container is found. Put the pointer into the entry.
403 //
404 entry->SetContainer(cont);
405 }
406
407 //
408 // Get container name, tree name and tree title of this entry.
409 //
410 const char *cname = cont->GetName();
411 const char *tname = entry->GetName();
412 const TString ttitle(Form("Tree containing %s", cont->GetDescriptor().Data()));
413
414 //
415 // if the tree name is NULL this idetifies it to use the default:
416 // the container name.
417 //
418 if (tname[0] == '\0')
419 tname = cname;
420
421 //
422 // Check if the tree is already existing (part of the file or memory)
423 //
424 TTree *tree = fOut ? (TTree*)fOut->Get(tname) : dynamic_cast<TTree*>(gROOT->FindObject(tname));
425 if (!fOut && tree)
426 {
427 if (tree->GetCurrentFile())
428 {
429 *fLog << err;
430 *fLog << "ERROR - You are trying to write data into a memory stored root tree," << endl;
431 *fLog << " because you either called the default constructor or have" << endl;
432 *fLog << " instantiated MWriteRootFile using the write option 'memory'." << endl;
433 *fLog << " This tree '" << tname << "' is already existing in" << endl;
434 *fLog << " memory (gROOT->FindObject) and is already belonging to a" << endl;
435 *fLog << " file (" << tree->GetCurrentFile()->GetName() << ")." << endl;
436 *fLog << " This can - for example - happen if you are reading from a" << endl;
437 *fLog << " tree with the same name. The easiest solution in this case" << endl;
438 *fLog << " is to change the name of the tree you want to write to." << endl;
439 *fLog << endl;
440 return kFALSE;
441 }
442 *fLog << inf << "Tree '" << tname << "' found already in Memory... using." << endl;
443 }
444
445 if (!tree)
446 {
447 //
448 // if the tree doesn't exist create a new tree. Use the tree
449 // name as title if title is NULL.
450 // And add the tree to the list of trees
451 //
452 TDirectory *save = gDirectory;
453 if (fOut)
454 fOut->cd();
455 else
456 gROOT->cd();
457
458 tree = new TTree(tname, ttitle, fOut ? 99 : 1);
459 fTrees.AddLast(tree);
460
461 //
462 // If the tree does not already exist in the file mark this
463 // tree as a branch created by MWriteRootFile
464 //
465 tree->SetBit(kIsNewTree);
466
467 gDirectory = save;
468
469 *fLog << inf << "Tree " << tname << " created." << endl;
470 }
471
472 //
473 // In case the file is opened as 'UPDATE' the tree may still not
474 // be in the list. Because it neither was created previously,
475 // nor this time, so the corresponding entries is marked as a
476 // single branch to be filled. --> Add it to the list of trees.
477 //
478 if (!fTrees.FindObject(tree))
479 fTrees.AddLast(tree);
480
481 //
482 // Now we have a valid tree. Search the list of trees for this tree
483 // Add a pointer to the entry in the tree list to this branch-entry
484 //
485 entry->SetTree(tree);
486
487 TString branchname(cname);
488 branchname.Append(".");
489
490 //
491 // Try to get the branch from the file.
492 // If the branch already exists the user specified one branch twice.
493 //
494 TBranch *branch = tree->GetBranch(branchname);
495 if (branch)
496 {
497 *fLog << inf << "Branch '" << cname << "' already existing... updating." << endl;
498 branch->SetAddress(entry->GetAddress());
499
500 if (!fSplitRule.IsNull() && fOut)
501 {
502 *fLog << warn << endl;
503 *fLog << "WARNING: You are updating an existing branch. For this case" << endl;
504 *fLog << " file-splitting mode is not allowed... disabled!" << endl;
505 *fLog << endl;
506 fSplitRule = "";
507 }
508 }
509 else
510 {
511 //
512 // Create a new branch in the actual tree. The branch has the name
513 // container name. The type of the container is given by the
514 // ClassName entry in the container. The Address is the address of a
515 // pointer to the container (gotten from the branch entry). As
516 // Basket size we specify a (more or less) common default value.
517 // The containers should be written in Splitlevel=1
518 //
519 *fLog << inf << "Creating Branch " << cname << " of " << cont->ClassName();
520 *fLog << " in tree " << tree->GetName() << "... " << flush;
521
522 branch = tree->Branch(branchname, cont->ClassName(), entry->GetAddress());
523
524 //
525 // If the branch couldn't be created we have a problem.
526 //
527 if (!branch)
528 {
529 *fLog << endl;
530 *fLog << err << "Unable to create branch '" << cname << "'." << endl;
531 return kFALSE;
532 }
533
534 *fLog << "done." << endl;
535
536 if (!tree->TestBit(kIsNewTree) && !fSplitRule.IsNull())
537 {
538 *fLog << warn << endl;
539 *fLog << "WARNING: You have created a new branch in an existing tree." << endl;
540 *fLog << " For this case file-splitting mode is not allowed... disabled!" << endl;
541 *fLog << endl;
542 fSplitRule= "";
543 }
544 }
545
546 //
547 // Tell the entry also which branch belongs to it (this is necessary
548 // for branches belonging to already existing tree, UPDATE-mode)
549 //
550 entry->SetBranch(branch);
551 }
552
553 return kTRUE;
554}
555
556// --------------------------------------------------------------------------
557//
558// Checks all given containers (branch entries) for the write flag.
559// If the write flag is set the corresponding Tree is marked to get filled.
560// All Trees which are marked to be filled are filled with all their
561// branches.
562// In case of a file opened in 'UPDATE' mode, single branches can be
563// filled, too. WARNING - for the moment there is no check whether
564// you filled the correct number of events into the branch, so that
565// each of the other branches in the tree has the correct corresponding
566// number of new entries in the new branch!
567// Be carefull: If only one container (corresponding to a branch) of a tree
568// has the write flag, all containers in this tree are filled!
569//
570Bool_t MWriteRootFile::CheckAndWrite()
571{
572 TObject *obj;
573
574 //
575 // Loop over all branch entries
576 //
577 TIter NextBranch(&fBranches);
578 while ((obj=NextBranch()))
579 {
580 MRootFileBranch *b = (MRootFileBranch*)obj;
581
582 //
583 // Check for the Write flag
584 //
585 if (!b->GetContainer()->IsReadyToSave())
586 continue;
587
588 //
589 // If the write flag of the branch entry is set, set the write flag of
590 // the corresponding tree entry.
591 //
592 if (b->GetTree()->TestBit(kIsNewTree))
593 b->GetTree()->SetBit(kFillTree);
594 else
595 {
596 if (!b->GetBranch()->Fill())
597 {
598 *fLog << err << "ERROR - Zero bytes written to branch '" << b->GetBranch()->GetName() << "'... abort." << endl;
599 return kFALSE;
600 }
601 }
602 }
603
604 //
605 // Loop over all tree entries
606 //
607 const Int_t n = fTrees.GetEntriesFast();
608
609 for (int idx=0; idx<n; idx++)
610 {
611 TTree *t = (TTree*)fTrees[idx];
612
613 //
614 // Check the write flag of the tree
615 //
616 if (!t->TestBit(kFillTree))
617 continue;
618
619 //
620 // If the write flag is set, fill the tree (with the corresponding
621 // branches/containers), delete the write flag and increase the number
622 // of written/filled entries.
623 //
624 t->ResetBit(kFillTree);
625
626 if (!t->Fill())
627 {
628 *fLog << err << "ERROR - Zero bytes written to tree '" << t->GetName() << "'... abort." << endl;
629 return kFALSE;
630 }
631 }
632
633 //
634 // If we are writing into memory we don't split into seperate files
635 //
636 if (!fOut)
637 return kTRUE;
638
639 //
640 // For more information see TTree:ChangeFile()
641 //
642 TTree *t0 = (TTree*)fTrees[0];
643 if (!t0 || fOut==t0->GetCurrentFile())
644 return kTRUE;
645
646 *fLog << warn << endl;
647 *fLog << "WARNING - MWriteRootFile: Root's TTree/TFile has opened a new file" << endl;
648 *fLog << " automatically. You can change this behaviour using TTree::SetMaxTreeSize." << endl;
649 *fLog << " You won't be able to read splitted files correctly with MReadMarsFile if" << endl;
650 *fLog << " they have more than one entry in 'RunHeaders' or you try to read more than" << endl;
651 *fLog << " one of such sequences at once." << endl;
652 *fLog << endl;
653
654 return kTRUE;
655}
656
657// --------------------------------------------------------------------------
658//
659// Open a new file with the ame fname. Move all trees and branches from the
660// old file to the new file.
661//
662Bool_t MWriteRootFile::ChangeFile(const char *fname)
663{
664 //
665 // The following code is more or less a copy of TTree::ChangeFile
666 //
667 const Int_t compr = fOut->GetCompressionLevel();
668 const TString title = fOut->GetTitle();
669
670 *fLog << inf << "MWriteRootFile - Open new file " << fname << " (Title=" << title << ", Compression=" << compr << ")" << endl;
671
672 // Open new file with old setup
673 TFile *newfile = TFile::Open(fname, "RECREATE", title, compr);
674 if (!newfile)
675 {
676 *fLog << err << "ERROR - Cannot open new file " << fname << endl;
677 return kFALSE;
678 }
679
680 // Print statistics of old file
681 const TString n = GetFileName();
682 if (!n.IsNull() && n!=TString("/dev/null"))
683 Print();
684
685 if (fOut->IsOpen())
686 fOut->Write();
687
688 // Move all trees from the old file to the new file
689 TObject *obj=0;
690 while ((obj = fOut->GetList()->First()))
691 {
692 // Remove obj from old file (otherwise deleting
693 // the old file will delete the objs)
694 fOut->GetList()->Remove(obj);
695
696 // If this is not a tree do nothing.
697 if (!obj->InheritsFrom("TTree"))
698 continue;
699
700 // process all trees in the old file
701 TTree *t = (TTree*)obj;
702
703 // reset and move to new file (this is done implicitly for all branches)
704 t->Reset();
705 t->SetDirectory(newfile);
706 }
707
708 // Close/delete the old file (keys already written above)
709 delete fOut;
710
711 // Replace current with new file
712 fOut = newfile;
713
714 // Change current directory to new file
715 gFile = fOut;
716
717 return kTRUE;
718}
719
720// --------------------------------------------------------------------------
721//
722// A rule looks like:
723// "outputpath{s/source/destination}"
724//
725// outpath: the output path into which the files are written
726// {s/source/destination} a substitution rule for the filename
727// while source can be a regular expression everything which matches this
728// regular expression (see TRegexp) will be replaced by destination.
729// Warning: The algorithm is recursive you may create endless loops!
730//
731// Example:
732// inputfile: /data/MAGIC/Period016/rootdata/20040621_23210_D_Mkn421_E.root
733// rule: /outpath/{s/_D_/_Y_}
734// outfile: /outpath/20040621_23210_Y_Mkn421_E.root
735//
736// If you need more difficult rules please send me an eMail...
737//
738TString MWriteRootFile::GetNewFileName(const char *inname) const
739{
740 // Remove the path from the filename
741 TString fname(inname);
742 if (fname.Last('/')>=0)
743 fname.Remove(0, fname.Last('/')+1);
744
745 // Make a copy of the rule
746 TString rule(fSplitRule);
747
748 // [characte class], ^ do not, [^{}] do not match { and }, [^{}]+ match at least not one { or }
749 const TRegexp subst0("{s/[^{}/]+/[^{}/]+}");
750
751 TString path;
752 Bool_t first = kTRUE;
753
754 Ssiz_t idx=0;
755 while (1)
756 {
757 // Find a substitution exprsssion
758 Ssiz_t len = 0;
759 idx = subst0.Index(rule, &len);
760 if (idx<0)
761 break;
762
763 // If the first substitution expression is found in the rule
764 // determin the path from everything before
765 if (first)
766 {
767 path=rule(0, idx);
768 first = kFALSE;
769 }
770
771 // Extract a substitution expression
772 TString expr = rule(idx, len);
773 rule.Remove(idx, len);
774
775 expr.Remove(0,3);
776 expr.Remove(expr.Length()-1);
777
778 // In all cases this is well defined (see Regexp)
779 const Ssiz_t pos = expr.First('/');
780
781 // Split substitution rule into source and destination
782 const TString src = expr(0, pos);
783 const TString dest = expr(pos+1, expr.Length());
784
785 // Replace source by destination
786 const TRegexp regexp(src);
787 while (1)
788 {
789 //TString sub = fname(idx+dest.Length());
790 cout << "--------->" << fname << "<-----------" << endl;
791 idx = regexp.Index(fname, &len);
792 if (idx<0)
793 break;
794
795 fname.Replace(idx, len, dest);
796 }
797 }
798
799 // Check if we have a trailing '/'
800 if (!path.IsNull() && path[path.Length()-1]!='/')
801 path.Append("/");
802
803 // Create full qualified pathname
804 path += fname;
805 return path;
806}
807
808// --------------------------------------------------------------------------
809//
810// ReInit. If file splitting is not allowed call MWriteFile::ReInit.
811//
812// In other cases get MRead from the TaskList (splitting is switched of if
813// this is impossible).
814//
815// Convert the input- into a new output file-name.
816//
817// Open a new file, change all trees to the new file (calling ChangeFile()),
818// and close the old one.
819//
820// Call MWriteFile::ReInit()
821//
822Bool_t MWriteRootFile::ReInit(MParList *pList)
823{
824 if (fSplitRule.IsNull() || !fOut)
825 return MWriteFile::ReInit(pList);
826
827 MRead *read = (MRead*)pList->FindTask("MRead");
828 if (!read)
829 {
830 *fLog << warn;
831 *fLog << "WARNING: No Task 'MRead' found in the tasklist. This task is" << endl;
832 *fLog << " necessary to get the filename. Without a filename file" << endl;
833 *fLog << " file splitting is not allowed... disabled!" << endl;
834 *fLog << endl;
835 fSplitRule = "";
836 return kTRUE;
837 }
838
839 const TString fname = GetNewFileName(read->GetFileName());
840 if (!ChangeFile(fname))
841 return kFALSE;
842
843 return MWriteFile::ReInit(pList);
844}
845
846// --------------------------------------------------------------------------
847//
848// return open state of the root file. If the file is 'memory' kTRUE is
849// returned.
850//
851Bool_t MWriteRootFile::IsFileOpen() const
852{
853 if (!fOut)
854 return kTRUE;
855
856 const char *n = fOut->GetName();
857 return n==0 || *n==0 ? kTRUE : fOut->IsOpen();
858}
859
860// --------------------------------------------------------------------------
861//
862// return name of the root-file. If the file is "memory" "<memory>" is
863// returned.
864//
865const char *MWriteRootFile::GetFileName() const
866{
867 if (!fOut)
868 return "<memory>";
869
870 const char *n = fOut->GetName();
871 return n==0 || *n==0 ? "<dummy>" : n;
872}
873
874// --------------------------------------------------------------------------
875//
876// cd into file. See TFile::cd(). If the file is "memory" kTRUE is returned.
877//
878Bool_t MWriteRootFile::cd(const char *path)
879{
880 return fOut ? fOut->cd(path) : kTRUE;
881}
882
883// --------------------------------------------------------------------------
884//
885// Implementation of SavePrimitive. Used to write the call to a constructor
886// to a macro. In the original root implementation it is used to write
887// gui elements to a macro-file.
888//
889void MWriteRootFile::StreamPrimitive(ofstream &out) const
890{
891 out << " MWriteRootFile " << GetUniqueName();
892 if (fOut)
893 {
894 out << "(\"";
895 out << fOut->GetName() << "\", \"";
896 out << fOut->GetOption() << "\", \"";
897 out << fOut->GetTitle() << "\", ";
898 out << fOut->GetCompressionLevel();
899 out << ")";
900 }
901 out << ";" << endl;
902
903 if (fName!=gsDefName)
904 out << " " << GetUniqueName() << ".SetName(\"" << fName << "\");" << endl;
905 if (fTitle!=gsDefTitle)
906 out << " " << GetUniqueName() << ".SetTitle(\"" << fTitle << "\");" << endl;
907
908 MRootFileBranch *entry;
909 TIter Next(&fBranches);
910 while ((entry=(MRootFileBranch*)Next()))
911 {
912 out << " " << GetUniqueName() << ".AddContainer(";
913
914 if (entry->GetContainer())
915 {
916 entry->GetContainer()->SavePrimitive(out);
917 out << "&" << entry->GetContainer()->GetUniqueName();
918 }
919 else
920 out << "\"" << entry->GetContName() << "\"";
921
922 out << ", \"" << entry->GetName() << "\"";
923 if (!entry->MustHave())
924 out << ", kFALSE";
925
926 out <<");" << endl;
927 }
928}
Note: See TracBrowser for help on using the repository browser.