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

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