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

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