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

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