TTreeCloner.cxx

Go to the documentation of this file.
00001 // @(#)root/tree:$Id: TTreeCloner.cxx 37922 2011-01-31 22:26:42Z pcanal $
00002 // Author: Philippe Canal 07/11/2005
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TTreeCloner                                                          //
00015 //                                                                      //
00016 // Class implementing or helping  the various TTree cloning method      //
00017 //                                                                      //
00018 //////////////////////////////////////////////////////////////////////////
00019 
00020 #include "TBasket.h"
00021 #include "TBranch.h"
00022 #include "TBranchClones.h"
00023 #include "TBranchElement.h"
00024 #include "TStreamerInfo.h"
00025 #include "TBranchRef.h"
00026 #include "TError.h"
00027 #include "TProcessID.h"
00028 #include "TMath.h"
00029 #include "TTree.h"
00030 #include "TTreeCloner.h"
00031 #include "TFile.h"
00032 #include "TLeafB.h"
00033 #include "TLeafI.h"
00034 #include "TLeafL.h"
00035 
00036 #include <algorithm>
00037 
00038 //______________________________________________________________________________
00039 bool TTreeCloner::CompareSeek::operator()(UInt_t i1, UInt_t i2)
00040 {
00041    if (fObject->fBasketSeek[i1] ==  fObject->fBasketSeek[i2]) {
00042       if (fObject->fBasketEntry[i1] ==  fObject->fBasketEntry[i2]) {
00043          return i1 < i2;
00044       }
00045       return  fObject->fBasketEntry[i1] <  fObject->fBasketEntry[i2];
00046    }
00047    return fObject->fBasketSeek[i1] <  fObject->fBasketSeek[i2];
00048 }
00049 
00050 //______________________________________________________________________________
00051 bool TTreeCloner::CompareEntry::operator()(UInt_t i1, UInt_t i2)
00052 {
00053    if (fObject->fBasketEntry[i1] ==  fObject->fBasketEntry[i2]) {
00054       return i1 < i2;
00055    }
00056    return  fObject->fBasketEntry[i1] <  fObject->fBasketEntry[i2];
00057 }
00058 
00059 //______________________________________________________________________________
00060 TTreeCloner::TTreeCloner(TTree *from, TTree *to, Option_t *method, UInt_t options) :
00061    fWarningMsg(),
00062    fIsValid(kTRUE),
00063    fNeedConversion(kFALSE),
00064    fOptions(options),
00065    fFromTree(from),
00066    fToTree(to),
00067    fMethod(method),
00068    fFromBranches( from ? from->GetListOfLeaves()->GetEntries()+1 : 0),
00069    fToBranches( to ? to->GetListOfLeaves()->GetEntries()+1 : 0),
00070    fMaxBaskets(CollectBranches()),
00071    fBasketBranchNum(new UInt_t[fMaxBaskets]),
00072    fBasketNum(new UInt_t[fMaxBaskets]),
00073    fBasketSeek(new Long64_t[fMaxBaskets]),
00074    fBasketEntry(new Long64_t[fMaxBaskets]),
00075    fBasketIndex(new UInt_t[fMaxBaskets]),
00076    fCloneMethod(TTreeCloner::kDefault),
00077    fToStartEntries(0)
00078 {
00079    // Constructor.  This object would transfer the data from
00080    // 'from' to 'to' using the method indicated in method.
00081    //
00082    // The value of the parameter 'method' determines in which
00083    // order the branches' baskets are written to the output file.
00084    //
00085    // When a TTree is filled the data is stored in the individual
00086    // branches' basket.  Each basket is written individually to
00087    // the disk as soon as it is full.  In consequence the baskets
00088    // of branches that contain 'large' data chunk are written to
00089    // the disk more often.
00090    //
00091    // There is currently 3 supported sorting order:
00092    //    SortBasketsByOffset (the default)
00093    //    SortBasketsByBranch
00094    //    SortBasketsByEntry
00095    //
00096    // When using SortBasketsByOffset the baskets are written in
00097    // the output file in the same order as in the original file
00098    // (i.e. the basket are sorted on their offset in the original
00099    // file; Usually this also means that the baskets are sorted
00100    // on the index/number of the _last_ entry they contain)
00101    //
00102    // When using SortBasketsByBranch all the baskets of each
00103    // individual branches are stored contiguously.  This tends to
00104    // optimize reading speed when reading a small number (1->5) of
00105    // branches, since all their baskets will be clustered together
00106    // instead of being spread across the file.  However it might
00107    // decrease the performance when reading more branches (or the full
00108    // entry).
00109    //
00110    // When using SortBasketsByEntry the baskets with the lowest
00111    // starting entry are written first.  (i.e. the baskets are
00112    // sorted on the index/number of the first entry they contain).
00113    // This means that on the file the baskets will be in the order
00114    // in which they will be needed when reading the whole tree
00115    // sequentially.
00116    //
00117 
00118    TString opt(method);
00119    opt.ToLower();
00120    if (opt.Contains("sortbasketsbybranch")) {
00121       //::Info("TTreeCloner::TTreeCloner","use: kSortBasketsByBranch");
00122       fCloneMethod = TTreeCloner::kSortBasketsByBranch;
00123    } else if (opt.Contains("sortbasketsbyentry")) {
00124       //::Info("TTreeCloner::TTreeCloner","use: kSortBasketsByEntry");
00125       fCloneMethod = TTreeCloner::kSortBasketsByEntry;
00126    } else {
00127       //::Info("TTreeCloner::TTreeCloner","use: kSortBasketsByOffset");
00128       fCloneMethod = TTreeCloner::kSortBasketsByOffset;
00129    }
00130    if (fToTree) fToStartEntries = fToTree->GetEntries();
00131 }
00132 
00133 //______________________________________________________________________________
00134 Bool_t TTreeCloner::Exec()
00135 {
00136    // Execute the cloning.
00137 
00138    CopyStreamerInfos();
00139    CopyProcessIds();
00140    CloseOutWriteBaskets();
00141    CollectBaskets();
00142    SortBaskets();
00143    WriteBaskets();
00144    CopyMemoryBaskets();
00145 
00146    return kTRUE;
00147 }
00148 
00149 //______________________________________________________________________________
00150 TTreeCloner::~TTreeCloner()
00151 {
00152    // TTreeCloner destructor
00153 
00154    delete [] fBasketBranchNum;
00155    delete [] fBasketNum;
00156    delete [] fBasketSeek;
00157    delete [] fBasketEntry;
00158    delete [] fBasketIndex;
00159 }
00160 
00161 //______________________________________________________________________________
00162 void TTreeCloner::CloseOutWriteBaskets()
00163 {
00164    // Before we can start adding new basket, we need to flush to
00165    // disk the partially filled baskets (the WriteBasket)
00166 
00167    for(Int_t i=0; i<fToBranches.GetEntries(); ++i) {
00168       TBranch *to = (TBranch*)fToBranches.UncheckedAt(i);
00169       to->FlushOneBasket(to->GetWriteBasket());
00170    }
00171 }
00172 
00173 //______________________________________________________________________________
00174 UInt_t TTreeCloner::CollectBranches(TBranch *from, TBranch *to) {
00175    // Fill the array of branches, adding the branch 'from' and 'to',
00176    // and matching the sub-branches of the 'from' and 'to' branches.
00177    // Returns the total number of baskets in all the from branch and
00178    // it sub-branches.
00179 
00180    // Since this is called from the constructor, this can not be a virtual function
00181 
00182    UInt_t numBaskets = 0;
00183    if (from->InheritsFrom(TBranchClones::Class())) {
00184       TBranchClones *fromclones = (TBranchClones*) from;
00185       TBranchClones *toclones = (TBranchClones*) to;
00186       numBaskets += CollectBranches(fromclones->fBranchCount, toclones->fBranchCount);
00187 
00188    } else if (from->InheritsFrom(TBranchElement::Class())) {
00189       Int_t nb = from->GetListOfLeaves()->GetEntries();
00190       Int_t fnb = to->GetListOfLeaves()->GetEntries();
00191       if (nb != fnb && (nb == 0 || fnb == 0)) {
00192          // We might be in the case where one branch is split
00193          // while the other is not split.  We must reject this match.
00194          fWarningMsg.Form("The export branch and the import branch do not have the same split level. (The branch name is %s.)",
00195                           from->GetName());
00196          if (!(fOptions & kNoWarnings)) {
00197             Warning("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
00198          }
00199          fNeedConversion = kTRUE;
00200          fIsValid = kFALSE;
00201          return 0;
00202       }
00203       if (((TBranchElement*) from)->GetStreamerType() != ((TBranchElement*) to)->GetStreamerType()) {
00204          fWarningMsg.Form("The export branch and the import branch do not have the same streamer type. (The branch name is %s.)",
00205                           from->GetName());
00206          if (!(fOptions & kNoWarnings)) {
00207             Warning("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
00208          }
00209          fIsValid = kFALSE;
00210          return 0;
00211       }
00212       TBranchElement *fromelem = (TBranchElement*) from;
00213       TBranchElement *toelem = (TBranchElement*) to;
00214       if (fromelem->fMaximum > toelem->fMaximum) toelem->fMaximum = fromelem->fMaximum;
00215    } else {
00216 
00217       Int_t nb = from->GetListOfLeaves()->GetEntries();
00218       Int_t fnb = to->GetListOfLeaves()->GetEntries();
00219       if (nb != fnb) {
00220          fWarningMsg.Form("The export branch and the import branch (%s) do not have the same number of leaves (%d vs %d)",
00221                           from->GetName(), fnb, nb);
00222          if (!(fOptions & kNoWarnings)) {
00223             Error("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
00224          }
00225          fIsValid = kFALSE;
00226          return 0;
00227       }
00228       for (Int_t i=0;i<nb;i++)  {
00229 
00230          TLeaf *fromleaf_gen = (TLeaf*)from->GetListOfLeaves()->At(i);
00231          TLeaf *toleaf_gen = (TLeaf*)to->GetListOfLeaves()->At(i);
00232          if (toleaf_gen->IsA() != fromleaf_gen->IsA() ) {
00233             // The data type do not match, we can not do a fast merge.
00234             fWarningMsg.Form("The export leaf and the import leaf (%s.%s) do not have the data type (%s vs %s)",
00235                               from->GetName(),fromleaf_gen->GetName(),fromleaf_gen->GetTypeName(),toleaf_gen->GetTypeName());
00236             if (! (fOptions & kNoWarnings) ) {
00237                Warning("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
00238             }
00239             fIsValid = kFALSE;
00240             fNeedConversion = kTRUE;
00241             return 0;
00242          }
00243          if (fromleaf_gen->IsA()==TLeafI::Class()) {
00244             TLeafI *fromleaf = (TLeafI*)fromleaf_gen;
00245             TLeafI *toleaf   = (TLeafI*)toleaf_gen;
00246             if (fromleaf->GetMaximum() > toleaf->GetMaximum())
00247                toleaf->SetMaximum( fromleaf->GetMaximum() );
00248             if (fromleaf->GetMinimum() < toleaf->GetMinimum())
00249                toleaf->SetMinimum( fromleaf->GetMinimum() );
00250          } else if (fromleaf_gen->IsA()==TLeafL::Class()) {
00251             TLeafL *fromleaf = (TLeafL*)fromleaf_gen;
00252             TLeafL *toleaf   = (TLeafL*)toleaf_gen;
00253             if (fromleaf->GetMaximum() > toleaf->GetMaximum())
00254                toleaf->SetMaximum( fromleaf->GetMaximum() );
00255             if (fromleaf->GetMinimum() < toleaf->GetMinimum())
00256                toleaf->SetMinimum( fromleaf->GetMinimum() );
00257          } else if (fromleaf_gen->IsA()==TLeafB::Class()) {
00258             TLeafB *fromleaf = (TLeafB*)fromleaf_gen;
00259             TLeafB *toleaf   = (TLeafB*)toleaf_gen;
00260             if (fromleaf->GetMaximum() > toleaf->GetMaximum())
00261                toleaf->SetMaximum( fromleaf->GetMaximum() );
00262             if (fromleaf->GetMinimum() < toleaf->GetMinimum())
00263                toleaf->SetMinimum( fromleaf->GetMinimum() );
00264          }
00265       }
00266 
00267    }
00268 
00269    fFromBranches.AddLast(from);
00270    fToBranches.AddLast(to);
00271 
00272    numBaskets += from->GetWriteBasket();
00273    numBaskets += CollectBranches(from->GetListOfBranches(),to->GetListOfBranches());
00274 
00275    return numBaskets;
00276 }
00277 
00278 //______________________________________________________________________________
00279 UInt_t TTreeCloner::CollectBranches(TObjArray *from, TObjArray *to)
00280 {
00281    // Fill the array of branches, matching the branches of the 'from' and 'to' arrays.
00282    // Returns the total number of baskets in all the branches.
00283 
00284    // Since this is called from the constructor, this can not be a virtual function
00285 
00286    Int_t fnb = from->GetEntries();
00287    Int_t tnb = to->GetEntries();
00288    if (!fnb || !tnb) {
00289       return 0;
00290    }
00291 
00292    UInt_t numBasket = 0;
00293    Int_t fi = 0;
00294    Int_t ti = 0;
00295    while (ti < tnb) {
00296       TBranch* fb = (TBranch*) from->UncheckedAt(fi);
00297       TBranch* tb = (TBranch*) to->UncheckedAt(ti);
00298       Int_t firstfi = fi;
00299       while (strcmp(fb->GetName(), tb->GetName())) {
00300          ++fi;
00301          if (fi >= fnb) {
00302             // continue at the beginning
00303             fi = 0;
00304          }
00305          if (fi==firstfi) {
00306             // We tried all the branches and there is not match.
00307             fb = 0;
00308             break;
00309          }
00310          fb = (TBranch*) from->UncheckedAt(fi);
00311       }
00312       if (fb) {
00313          numBasket += CollectBranches(fb, tb);
00314          ++fi;
00315          if (fi >= fnb) {
00316            fi = 0;
00317          }
00318       } else {
00319          if (tb->GetMother()==tb) {
00320             // Top level branch.
00321             if (!(fOptions & kIgnoreMissingTopLevel)) {
00322                fWarningMsg.Form("One of the export top level branches (%s) is not present in the import TTree.",
00323                                 tb->GetName());
00324                if (!(fOptions & kNoWarnings)) {
00325                   Error("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
00326                }
00327                fIsValid = kFALSE;
00328             }
00329          } else {
00330             fWarningMsg.Form("One of the export sub-branches (%s) is not present in the import TTree.",
00331                              tb->GetName());
00332             if (!(fOptions & kNoWarnings)) {
00333                Error("TTreeCloner::CollectBranches", "%s", fWarningMsg.Data());
00334             }
00335             fIsValid = kFALSE;
00336          }
00337       }
00338       ++ti;
00339    }
00340    return numBasket;
00341 }
00342 
00343 //______________________________________________________________________________
00344 UInt_t TTreeCloner::CollectBranches()
00345 {
00346    // Fill the array of branches, matching the branches of the 'from' and 'to' TTrees
00347    // Returns the total number of baskets in all the branches.
00348 
00349    // Since this is called from the constructor, this can not be a virtual function
00350 
00351    if (!fFromTree || !fToTree) {
00352       return 0;
00353    }
00354    UInt_t numBasket = CollectBranches(fFromTree->GetListOfBranches(),
00355                                       fToTree->GetListOfBranches());
00356 
00357    if (fFromTree->GetBranchRef()) {
00358       fToTree->BranchRef();
00359       numBasket += CollectBranches(fFromTree->GetBranchRef(),fToTree->GetBranchRef());
00360    }
00361    return numBasket;
00362 }
00363 
00364 //______________________________________________________________________________
00365 void TTreeCloner::CollectBaskets()
00366 {
00367    // Collect the information about the on-file basket that need
00368    // to be copied.
00369 
00370    UInt_t len = fFromBranches.GetEntries();
00371 
00372    for(UInt_t i=0,bi=0; i<len; ++i) {
00373       TBranch *from = (TBranch*)fFromBranches.UncheckedAt(i);
00374       for(Int_t b=0; b<from->GetWriteBasket(); ++b,++bi) {
00375          fBasketBranchNum[bi] = i;
00376          fBasketNum[bi] = b;
00377          fBasketSeek[bi] = from->GetBasketSeek(b);
00378          //fprintf(stderr,"For %s %d %lld\n",from->GetName(),bi,fBasketSeek[bi]);
00379          fBasketEntry[bi] = from->GetBasketEntry()[b];
00380          fBasketIndex[bi] = bi;
00381       }
00382    }
00383 }
00384 
00385 //______________________________________________________________________________
00386 void TTreeCloner::CopyStreamerInfos()
00387 {
00388    // Make sure that all the needed TStreamerInfo are
00389    // present in the output file
00390 
00391    TFile *fromFile = fFromTree->GetDirectory()->GetFile();
00392    TFile *toFile = fToTree->GetDirectory()->GetFile();
00393    TList *l = fromFile->GetStreamerInfoList();
00394    TIter next(l);
00395    TStreamerInfo *oldInfo;
00396    while ( (oldInfo = (TStreamerInfo*)next()) ) {
00397       if (oldInfo->IsA() != TStreamerInfo::Class()) {
00398          continue;
00399       }
00400       TStreamerInfo *curInfo = 0;
00401       TClass *cl = TClass::GetClass(oldInfo->GetName());
00402 
00403       if ((cl->IsLoaded() && (cl->GetNew()!=0 || cl->HasDefaultConstructor()))
00404           || !cl->IsLoaded())  {
00405          // Insure that the TStreamerInfo is loaded
00406          curInfo = (TStreamerInfo*)cl->GetStreamerInfo(oldInfo->GetClassVersion());
00407          if (oldInfo->GetClassVersion()==1) {
00408             // We may have a Foreign class let's look using the
00409             // checksum:
00410             TStreamerInfo *matchInfo = (TStreamerInfo*)cl->FindStreamerInfo(oldInfo->GetCheckSum());
00411             if (matchInfo) {
00412                curInfo = matchInfo;
00413             }
00414          }
00415          curInfo->ForceWriteInfo(toFile);
00416       } else {
00417          // If there is no default constructor the GetStreamerInfo
00418          // will not work. It also means (hopefully) that an
00419          // inheriting class has a streamerInfo in the list (which
00420          // will induces the setting of this streamerInfo)
00421 
00422          oldInfo->ForceWriteInfo(toFile);
00423       }
00424    }
00425    delete l;
00426 }
00427 
00428 //______________________________________________________________________________
00429 void TTreeCloner::CopyMemoryBaskets()
00430 {
00431    // Transfer the basket from the input file to the output file
00432 
00433    TBasket *basket = 0;
00434    for(Int_t i=0; i<fToBranches.GetEntries(); ++i) {
00435       TBranch *from = (TBranch*)fFromBranches.UncheckedAt( i );
00436       TBranch *to   = (TBranch*)fToBranches.UncheckedAt( i );
00437 
00438       basket = from->GetListOfBaskets()->GetEntries() ? from->GetBasket(from->GetWriteBasket()) : 0;
00439       if (basket) {
00440          basket = (TBasket*)basket->Clone();
00441          basket->SetBranch(to);
00442          to->AddBasket(*basket, kFALSE, fToStartEntries+from->GetBasketEntry()[from->GetWriteBasket()]);
00443       } else {
00444          to->AddLastBasket(  fToStartEntries+from->GetBasketEntry()[from->GetWriteBasket()] );
00445       }
00446       // In older files, if the branch is a TBranchElement non-terminal 'object' branch, it's basket will contain 0
00447       // events, in newer file in the same case, the write basket will be missing.
00448       if (from->GetEntries()!=0 && from->GetWriteBasket()==0 && (basket==0 || basket->GetNevBuf()==0)) {
00449          to->SetEntries(to->GetEntries()+from->GetEntries());
00450       }
00451    }
00452 }
00453 
00454 //______________________________________________________________________________
00455 void TTreeCloner::CopyProcessIds()
00456 {
00457    // Make sure that all the needed TStreamerInfo are
00458    // present in the output file
00459 
00460    // NOTE: We actually need to merge the ProcessId somehow :(
00461 
00462    TFile *fromfile = fFromTree->GetDirectory()->GetFile();
00463    TFile *tofile = fToTree->GetDirectory()->GetFile();
00464 
00465    fPidOffset = tofile->GetNProcessIDs();
00466 
00467    TIter next(fromfile->GetListOfKeys());
00468    TKey *key;
00469    TDirectory::TContext cur(gDirectory,fromfile);
00470    while ((key = (TKey*)next())) {
00471       if (!strcmp(key->GetClassName(),"TProcessID")) {
00472          TProcessID *pid = (TProcessID*)key->ReadObjectAny(0);
00473 
00474          //UShort_t out = TProcessID::WriteProcessID(id,tofile);
00475          UShort_t out = 0;
00476          TObjArray *pids = tofile->GetListOfProcessIDs();
00477          Int_t npids = tofile->GetNProcessIDs();
00478          Bool_t wasIn = kFALSE;
00479          for (Int_t i=0;i<npids;i++) {
00480             if (pids->At(i) == pid) {out = (UShort_t)i; wasIn = kTRUE; break;}
00481          }
00482 
00483          if (!wasIn) {
00484             TDirectory *dirsav = gDirectory;
00485             tofile->cd();
00486             tofile->SetBit(TFile::kHasReferences);
00487             pids->AddAtAndExpand(pid,npids);
00488             pid->IncrementCount();
00489             char name[32];
00490             snprintf(name,32,"ProcessID%d",npids);
00491             pid->Write(name);
00492             tofile->IncrementProcessIDs();
00493             if (gDebug > 0) {
00494                Info("WriteProcessID", "name=%s, file=%s", name, tofile->GetName());
00495             }
00496             if (dirsav) dirsav->cd();
00497             out = (UShort_t)npids;
00498          }
00499          if (out<fPidOffset) {
00500             Error("CopyProcessIDs","Copied %s from %s might already exist!\n",
00501                   pid->GetName(),fromfile->GetName());
00502          }
00503       }
00504    }
00505 }
00506 
00507 //______________________________________________________________________________
00508 void TTreeCloner::SortBaskets()
00509 {
00510    // Sort the basket according to the user request.
00511 
00512    // Currently this sort __has to__ preserve the order
00513    // of basket for each individual branch.
00514 
00515    switch (fCloneMethod) {
00516       case kSortBasketsByBranch:
00517          // nothing to do, it is already sorted.
00518          break;
00519       case kSortBasketsByEntry: {
00520          for(UInt_t i = 0; i < fMaxBaskets; ++i) { fBasketIndex[i] = i; }
00521          std::sort(fBasketIndex, fBasketIndex+fMaxBaskets, CompareEntry( this) );
00522          break;
00523       }
00524       case kSortBasketsByOffset:
00525       default: {
00526          for(UInt_t i = 0; i < fMaxBaskets; ++i) { fBasketIndex[i] = i; }
00527          std::sort(fBasketIndex, fBasketIndex+fMaxBaskets, CompareSeek( this) );
00528          break;
00529       }
00530    }
00531 }
00532 
00533 //______________________________________________________________________________
00534 void TTreeCloner::WriteBaskets()
00535 {
00536    // Transfer the basket from the input file to the output file
00537 
00538    TBasket *basket = new TBasket();
00539    for(UInt_t j=0; j<fMaxBaskets; ++j) {
00540       TBranch *from = (TBranch*)fFromBranches.UncheckedAt( fBasketBranchNum[ fBasketIndex[j] ] );
00541       TBranch *to   = (TBranch*)fToBranches.UncheckedAt( fBasketBranchNum[ fBasketIndex[j] ] );
00542 
00543       TFile *tofile = to->GetFile(0);
00544       TFile *fromfile = from->GetFile(0);
00545 
00546       Int_t index = fBasketNum[ fBasketIndex[j] ];
00547 
00548       Long64_t pos = from->GetBasketSeek(index);
00549       if (pos!=0) {
00550          if (from->GetBasketBytes()[index] == 0) {
00551             from->GetBasketBytes()[index] = basket->ReadBasketBytes(pos, fromfile);
00552          }
00553          Int_t len = from->GetBasketBytes()[index];
00554 
00555          basket->LoadBasketBuffers(pos,len,fromfile);
00556          basket->IncrementPidOffset(fPidOffset);
00557          basket->CopyTo(tofile);
00558          to->AddBasket(*basket,kTRUE,fToStartEntries + from->GetBasketEntry()[index]);
00559       } else {
00560          TBasket *frombasket = from->GetBasket( index );
00561          if (frombasket->GetNevBuf()>0) {
00562             TBasket *tobasket = (TBasket*)frombasket->Clone();
00563             tobasket->SetBranch(to);
00564             to->AddBasket(*tobasket, kFALSE, fToStartEntries+from->GetBasketEntry()[index]);
00565             to->FlushOneBasket(to->GetWriteBasket());
00566          }
00567       }
00568    }
00569    delete basket;
00570 }

Generated on Tue Jul 5 15:34:12 2011 for ROOT_528-00b_version by  doxygen 1.5.1