Logo ROOT   6.14/05
Reference Guide
TStreamerInfo.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id$
2 // Author: Rene Brun 12/10/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /**
13 \class TStreamerInfo TStreamerInfo.cxx
14 \ingroup IO
15 
16 Describes a persistent version of a class.
17 
18 A ROOT file contains the list of TStreamerInfo objects for all the
19 class versions written to this file.
20 When reading a file, all the TStreamerInfo objects are read back in
21 memory and registered to the TClass list of TStreamerInfo.
22 One can see the list and contents of the TStreamerInfo on a file
23 with, e.g.,
24 ~~~{.cpp}
25  TFile f("myfile.root");
26  f.ShowStreamerInfo();
27 ~~~
28 A TStreamerInfo is a list of TStreamerElement objects (one per data
29 member or base class).
30 When streaming an object, the system (TClass) loops on all the
31 TStreamerElement objects and calls the appropriate function for each
32 element type.
33 */
34 
35 #include "TStreamerInfo.h"
36 #include "TFile.h"
37 #include "TROOT.h"
38 #include "TClonesArray.h"
39 #include "TStreamerElement.h"
40 #include "TClass.h"
41 #include "TClassEdit.h"
42 #include "TDataMember.h"
43 #include "TMethodCall.h"
44 #include "TDataType.h"
45 #include "TRealData.h"
46 #include "TBaseClass.h"
47 #include "TBuffer.h"
48 #include "TArrayC.h"
49 #include "TArrayI.h"
50 #include "TArrayF.h"
51 #include "TArrayD.h"
52 #include "TArrayS.h"
53 #include "TArrayL.h"
54 #include "TError.h"
55 #include "TRef.h"
56 #include "TProcessID.h"
57 #include "TSystem.h"
58 
59 #include "TStreamer.h"
60 #include "TContainerConverters.h"
63 #include "TInterpreter.h"
64 
65 #include "TMemberInspector.h"
66 
67 #include "TMakeProject.h"
68 
69 #include "TSchemaRuleSet.h"
70 #include "TSchemaRule.h"
71 
72 #include "TVirtualMutex.h"
73 
74 #include "TStreamerInfoActions.h"
75 
76 #include <memory>
77 #include <array>
78 
79 std::atomic<Int_t> TStreamerInfo::fgCount{0};
80 
81 const Int_t kMaxLen = 1024;
82 
84 
85 static void R__TObjArray_InsertAt(TObjArray *arr, TObject *obj, Int_t at)
86 {
87  // Slide by one.
88  Int_t last = arr->GetLast();
89  arr->AddAtAndExpand(arr->At(last),last+1);
90  for(Int_t ind = last-1; ind >= at; --ind) {
91  arr->AddAt( arr->At(ind), ind+1);
92  };
93  arr->AddAt( obj, at);
94 }
95 
96 static void R__TObjArray_InsertAt(TObjArray *arr, std::vector<TStreamerArtificial*> &objs, Int_t at)
97 {
98  // Slide by enough.
99  Int_t offset = objs.size();
100  Int_t last = arr->GetLast();
101  arr->AddAtAndExpand(arr->At(last),last+offset);
102  for(Int_t ind = last-1; ind >= at; --ind) {
103  arr->AddAt( arr->At(ind), ind+offset);
104  };
105  for(size_t ins = 0; ins < objs.size(); ++ins) {
106  arr->AddAt(objs[ins], at+ins);
107  }
108 }
109 
110 static void R__TObjArray_InsertAfter(TObjArray *arr, TObject *newobj, TObject *oldobj)
111 {
112  // Slide by one.
113  Int_t last = arr->GetLast();
114  Int_t at = 0;
115  while (at<last && arr->At(at) != oldobj) {
116  ++at;
117  }
118  ++at; // we found the object, insert after it
119  R__TObjArray_InsertAt(arr, newobj, at);
120 }
121 
122 static void R__TObjArray_InsertBefore(TObjArray *arr, TObject *newobj, TObject *oldobj)
123 {
124  // Slide by one.
125  Int_t last = arr->GetLast();
126  Int_t at = 0;
127  while (at<last && arr->At(at) != oldobj) {
128  ++at;
129  }
130  R__TObjArray_InsertAt(arr, newobj, at);
131 }
132 
133 enum class EUniquePtrOffset : char
134  {
135  kNA = 0,
136  kZero = 1,
137  kNonZero = 2
138  };
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// Default ctor.
142 
144 {
145  fNumber = fgCount;
146  fClass = 0;
147  fElements = 0;
148  fComp = 0;
149  fCompFull = 0;
150  fCompOpt = 0;
151  fCheckSum = 0;
152  fNdata = 0;
153  fNfulldata= 0;
154  fNslots = 0;
155  fSize = 0;
156  fClassVersion = 0;
157  fOnFileClassVersion = 0;
158  fOldVersion = Class()->GetClassVersion();
159  fNVirtualInfoLoc = 0;
160  fVirtualInfoLoc = 0;
161  fLiveCount = 0;
162 
163  fReadObjectWise = 0;
164  fReadMemberWise = 0;
165  fReadMemberWiseVecPtr = 0;
166  fReadText = 0;
167  fWriteObjectWise = 0;
168  fWriteMemberWise = 0;
169  fWriteMemberWiseVecPtr = 0;
170  fWriteText = 0;
171 }
172 
173 ////////////////////////////////////////////////////////////////////////////////
174 /// Create a TStreamerInfo object.
175 
178 {
179  fgCount++;
180  fNumber = fgCount;
181  fClass = cl;
182  fElements = new TObjArray();
183  fComp = 0;
184  fCompFull = 0;
185  fCompOpt = 0;
186  fCheckSum = 0;
187  fNdata = 0;
188  fNfulldata= 0;
189  fNslots = 0;
190  fSize = 0;
193  fOldVersion = Class()->GetClassVersion();
194  fNVirtualInfoLoc = 0;
195  fVirtualInfoLoc = 0;
196  fLiveCount = 0;
197 
198  fReadObjectWise = 0;
199  fReadMemberWise = 0;
201  fReadText = 0;
202  fWriteObjectWise = 0;
203  fWriteMemberWise = 0;
205  fWriteText = 0;
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// TStreamerInfo dtor.
210 
212 {
213  delete [] fComp; fComp = 0;
214  delete [] fCompFull; fCompFull = 0;
215  delete [] fCompOpt; fCompOpt = 0;
216  delete [] fVirtualInfoLoc; fVirtualInfoLoc =0;
217 
218  delete fReadObjectWise;
219  delete fReadMemberWise;
220  delete fReadMemberWiseVecPtr;
221  delete fReadText;
222  delete fWriteObjectWise;
223  delete fWriteMemberWise;
224  delete fWriteMemberWiseVecPtr;
225  delete fWriteText;
226 
227  if (!fElements) return;
228  fElements->Delete();
229  delete fElements; fElements=0;
230 }
231 
232 ////////////////////////////////////////////////////////////////////////////////
233 /// Makes sure kBuildOldUsed set once Build or BuildOld finishes.
234 /// Makes sure kBuildRunning reset once Build finishes.
235 
236 namespace {
237  struct TPreventRecursiveBuildGuard {
238  TPreventRecursiveBuildGuard(TStreamerInfo* info): fInfo(info) {
239  fInfo->SetBit(TStreamerInfo::kBuildRunning);
240  fInfo->SetBit(TStreamerInfo::kBuildOldUsed);
241  }
242  ~TPreventRecursiveBuildGuard() {
243  fInfo->ResetBit(TStreamerInfo::kBuildOldUsed);
244  fInfo->ResetBit(TStreamerInfo::kBuildRunning);
245  }
246  TStreamerInfo* fInfo;
247  };
248 
249 }
250 
251 ////////////////////////////////////////////////////////////////////////////////
252 /// Build the I/O data structure for the current class version.
253 ///
254 /// A list of TStreamerElement derived classes is built by scanning
255 /// one by one the list of data members of the analyzed class.
257 {
258  // Did another thread already do the work?
259  if (fIsCompiled) return;
260 
262 
263  // Did another thread already do the work while we were waiting ..
264  if (fIsCompiled) return;
265 
266  // Has Build already been run?
267  if (fIsBuilt) return;
268 
269  // Are we recursing on ourself?
271 
272  // This is used to avoid unwanted recursive call to Build or BuildOld.
273  TPreventRecursiveBuildGuard buildGuard(this);
274 
275  if (fClass->GetCollectionProxy()) {
277  TString title;
278  if (proxy->GetValueClass()) {
279  title.Form("<%s%s> Used to call the proper TStreamerInfo case",proxy->GetValueClass()->GetName(),proxy->HasPointers() ? "*" : "");
280  } else {
281  title .Form("<%s%s> Used to call the proper TStreamerInfo case",TDataType::GetTypeName(proxy->GetType()),proxy->HasPointers() ? "*" : "");
282  }
283  TStreamerElement* element = new TStreamerSTL("This", title.Data(), 0, fClass->GetName(), *proxy, 0);
284  fElements->Add(element);
285  Compile();
287  fIsBuilt = kTRUE;
288  return;
289  }
290 
291  TStreamerElement::Class()->IgnoreTObjectStreamer();
292 
294 
296 
297  Bool_t needAllocClass = kFALSE;
298  Bool_t wasCompiled = fComp != 0;
299  ROOT::TSchemaRuleSet::TMatches rules;
300  if (fClass->GetSchemaRules()) {
302  }
303 
304  //
305  // Iterate over base classes.
306  //
307 
308  bool isCollection = fClass->GetCollectionProxy();
309  bool isString = !strcmp(fClass->GetName(), "string");
310 
311  TBaseClass* base = 0;
312  TIter nextb(fClass->GetListOfBases());
313  while ((base = (TBaseClass*)nextb())) {
314  TStreamerElement* element = 0;
315  Int_t offset = base->GetDelta();
316  if (offset == kMissing) {
317  continue;
318  }
319  if (offset == kNeedObjectForVirtualBaseClass) {
320  Error("Build()", "Cannot stream virtual base %s of class %s",
321  base->GetName(), fClass->GetName());
322  continue;
323  }
324  const char* bname = base->GetName();
325  const char* btitle = base->GetTitle();
326  // this case appears with STL collections as base class.
327  if (!strcmp(bname, "string")) {
328  element = new TStreamerSTLstring(bname, btitle, offset, bname, kFALSE);
329  } else if (base->IsSTLContainer()) {
330  TVirtualCollectionProxy *proxy = base->GetClassPointer()->GetCollectionProxy();
331  if (proxy) element = new TStreamerSTL(bname, btitle, offset, bname, *proxy, kFALSE);
332  else element = new TStreamerSTL(bname, btitle, offset, bname, 0, kFALSE);
333  if (fClass->IsLoaded() && ((TStreamerSTL*)element)->GetSTLtype() != ROOT::kSTLvector) {
334  if (!element->GetClassPointer()->IsLoaded()) {
335  Error("Build","The class \"%s\" is compiled and its base class \"%s\" is a collection and we do not have a dictionary for it, we will not be able to read or write this base class.",GetName(),bname);
336  delete element;
337  continue;
338  }
339  }
340  } else {
341  element = new TStreamerBase(bname, btitle, offset);
342  TClass* clm = element->GetClassPointer();
343  if (!clm) {
344  // We have no information about the class yet, except that since it
345  // is a base class, we know it is a class. So let's create it (in v5
346  // it would have been created as a side effect of the dictionary of
347  // for the derived class having a forward declaration of the base class).
348  clm = new TClass(bname,1,TClass::kForwardDeclared, true /*silent*/);
349  Warning("Build", "%s: base class %s has no streamer or dictionary it will not be saved", GetName(), clm->GetName());
350  element->Init(0);
351  } else {
352  // Now part of the TStreamerBase constructor.
353  // clm->GetStreamerInfo();
354  if ((clm == TObject::Class()) && fClass->CanIgnoreTObjectStreamer()) {
355  // -- An ignored TObject base class.
356  // Note: The TClass kIgnoreTObjectStreamer == BIT(15), but
357  // the TStreamerInfo kIgnoreTobjectStreamer == BIT(13) which
358  // is confusing.
360  // Flag the element to be ignored by setting its type to -1.
361  // This flag will be used later by Compile() to prevent this
362  // element from being inserted into the compiled info.
363  element->SetType(-1);
364  }
365  if (!clm->IsLoaded() && !(isCollection || isString)) {
366  // Don't complain about the base classes of collections nor of
367  // std::string.
368  Warning("Build", "%s: base class %s has no streamer or dictionary it will not be saved", GetName(), clm->GetName());
369  }
370  }
371  }
372  if (element) {
373  fElements->Add(element);
374  }
375  } // end of base class loop
376 
377  //
378  // Iterate over data members.
379  //
380 
381  Int_t dsize;
382  TDataMember* dm = 0;
383  std::string typeNameBuf;
384  std::string trueTypeNameBuf;
386  while ((dm = (TDataMember*) nextd())) {
387  if (fClass->GetClassVersion() == 0) {
388  continue;
389  }
390  if (!dm->IsPersistent()) {
391  continue;
392  }
393  TMemberStreamer* streamer = 0;
394  Int_t offset = GetDataMemberOffset(dm, streamer);
395  if (offset == kMissing) {
396  continue;
397  }
398  TStreamerElement* element = 0;
399  dsize = 0;
400 
401  // Save some useful variables
402  const char* dmName = dm->GetName();
403  const char* dmTitle = dm->GetTitle();
404  const char* dmType = dm->GetTypeName();
405  const char* dmFull = dm->GetTrueTypeName(); // Used to be GetFullTypeName ...
406  Bool_t dmIsPtr = dm->IsaPointer();
407  TDataType* dt(nullptr);
408  Int_t ndim = dm->GetArrayDim();
409  std::array<Int_t, 5> maxIndices; // 5 is the maximum supported in TStreamerElement::SetMaxIndex
410  Bool_t isStdArray(kFALSE);
411 
412  // Let's treat the unique_ptr case
413  bool nameChanged;
414  trueTypeNameBuf = typeNameBuf = TClassEdit::GetNameForIO(dmFull, TClassEdit::EModType::kNone, &nameChanged);
415  if (nameChanged) {
416  if (TClassEdit::IsUniquePtr(dmFull)) {
417  dmIsPtr = true;
418  }
419  while(typeNameBuf.back() == '*') typeNameBuf.pop_back();
420  dmFull = trueTypeNameBuf.c_str();
421  dmType = typeNameBuf.c_str();
422  }
423  if ((isStdArray = TClassEdit::IsStdArray(dmType))){ // We tackle the std array case
425  typeNameBuf,
426  maxIndices,
427  ndim);
428  trueTypeNameBuf = typeNameBuf;
429  while(typeNameBuf.back() == '*') typeNameBuf.pop_back();
430  dmFull = dmType = typeNameBuf.c_str();
431  dt = gROOT->GetType(dmType);
432  }
433 
434  TDataMember* dmCounter = 0;
435  if (dmIsPtr) {
436  //
437  // look for a pointer data member with a counter
438  // in the comment string, like so:
439  //
440  // int n;
441  // double* MyArray; //[n]
442  //
443  const char* lbracket = TVirtualStreamerInfo::GetElementCounterStart(dmTitle);
444  const char* rbracket = ::strchr(dmTitle, ']');
445  if (lbracket && rbracket) {
446  const char* counterName = dm->GetArrayIndex();
447  TRealData* rdCounter = (TRealData*) fClass->GetListOfRealData()->FindObject(counterName);
448  if (!rdCounter || rdCounter->TestBit(TRealData::kTransient)) {
449  Error("Build", "%s, discarding: %s %s, illegal %s\n", GetName(), dmFull, dmName, dmTitle);
450  continue;
451  }
452  dmCounter = rdCounter->GetDataMember();
453  TDataType* dtCounter = dmCounter->GetDataType();
454  Bool_t isInteger = dtCounter && ((dtCounter->GetType() == 3) || (dtCounter->GetType() == 13));
455  if (!dtCounter || !isInteger) {
456  Error("Build", "%s, discarding: %s %s, illegal [%s] (must be Int_t)\n", GetName(), dmFull, dmName, counterName);
457  continue;
458  }
459  TStreamerBasicType* bt = TStreamerInfo::GetElementCounter(counterName, dmCounter->GetClass());
460  if (!bt) {
461  if (dmCounter->GetClass()->Property() & kIsAbstract) {
462  continue;
463  }
464  Error("Build", "%s, discarding: %s %s, illegal [%s] must be placed before \n", GetName(), dmFull, dmName, counterName);
465  continue;
466  }
467  }
468  }
469  if (!dt && !isStdArray) dt = dm->GetDataType();
470  if (dt) {
471  // found a basic type
472  Int_t dtype = dt->GetType();
473  dsize = dt->Size();
474  if (!dmCounter && (strstr(dmFull, "char*") || strstr(dmFull, "Char_t*"))) {
475  dtype = kCharStar;
476  dsize = sizeof(char*);
477  }
478  if (dtype == kOther_t || dtype == kNoType_t) {
479  Error("Build", "%s, unknown type: %s %s", GetName(), dmFull, dmName);
480  continue;
481  } else if (dmIsPtr && (dtype != kCharStar)) {
482  if (dmCounter) {
483  // data member is pointer to an array of basic types
484  element = new TStreamerBasicPointer(dmName, dmTitle, offset, dtype, dm->GetArrayIndex(), dmCounter->GetClass()->GetName(), dmCounter->GetClass()->GetClassVersion(), dmFull);
485  } else {
486  if ((fName == "TString") || (fName == "TClass")) {
487  continue;
488  }
489  Error("Build", "%s, discarding: %s %s, no [dimension]\n", GetName(), dmFull, dmName);
490  continue;
491  }
492  } else {
493  // data member is a basic type
494  if ((fClass == TObject::Class()) && !strcmp(dmName, "fBits")) {
495  //printf("found fBits, changing dtype from %d to 15\n", dtype);
496  dtype = kBits;
497  }
498  // Here we treat data members such as int, float, double[4]
499  element = new TStreamerBasicType(dmName, dmTitle, offset, dtype, dmFull);
500  }
501  } else {
502  // try STL container or string
503  static const char* full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
504  if (!strcmp(dmType, "string") || !strcmp(dmType, "std::string") || !strcmp(dmType, full_string_name)) {
505  element = new TStreamerSTLstring(dmName, dmTitle, offset, dmFull, dmIsPtr);
506  } else if (dm->IsSTLContainer()) {
507  TVirtualCollectionProxy *proxy = TClass::GetClass(dmType /* the underlying type */)->GetCollectionProxy();
508  if (proxy) element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, *proxy, dmIsPtr);
509  else element = new TStreamerSTL(dmName, dmTitle, offset, dmFull, dmFull, dmIsPtr);
510  bool hasCustomAlloc = proxy ? proxy->GetProperties() & TVirtualCollectionProxy::kCustomAlloc : kFALSE;
511  if (((TStreamerSTL*)element)->GetSTLtype() != ROOT::kSTLvector || hasCustomAlloc) {
512  auto printErrorMsg = [&](const char* category)
513  {
514  Error("Build","The class \"%s\" is %s and for its data member \"%s\" we do not have a dictionary for the collection \"%s\". Because of this, we will not be able to read or write this data member.",GetName(), category, dmName, dmType);
515  };
516  if (fClass->IsLoaded()) {
517  if (!element->GetClassPointer()->IsLoaded()) {
518  printErrorMsg("compiled");
519  delete element;
520  continue;
521  }
522  } else if (fClass->GetState() == TClass::kInterpreted) {
524  printErrorMsg("interpreted");
525  delete element;
526  continue;
527  }
528  }
529  }
530  } else {
531  TClass* clm = TClass::GetClass(dmType);
532  if (!clm) {
533  Error("Build", "%s, unknown type: %s %s\n", GetName(), dmFull, dmName);
534  continue;
535  }
536  if (isStdArray) {
537  // We do not want to rebuild the streamerinfo of an std::array<T,N> asking the dm->GetUnitSize(), but rather of T only.
538 
539  dsize = clm->Size();
540  }
541  if (dmIsPtr) {
542  // a pointer to a class
543  if (dmCounter) {
544  element = new TStreamerLoop(dmName, dmTitle, offset, dm->GetArrayIndex(), dmCounter->GetClass()->GetName(), dmCounter->GetClass()->GetClassVersion(), dmFull);
545  } else {
546  if (clm->IsTObject()) {
547  element = new TStreamerObjectPointer(dmName, dmTitle, offset, dmFull);
548  } else {
549  element = new TStreamerObjectAnyPointer(dmName, dmTitle, offset, dmFull);
550  if (!streamer && !clm->GetStreamer() && !clm->IsLoaded()) {
551  Error("Build", "%s: %s has no streamer or dictionary, data member %s will not be saved", GetName(), dmFull, dmName);
552  }
553  }
554  }
555  } else if (clm->IsTObject()) {
556  element = new TStreamerObject(dmName, dmTitle, offset, dmFull);
557  } else if ((clm == TString::Class()) && !dmIsPtr) {
558  element = new TStreamerString(dmName, dmTitle, offset);
559  } else {
560  element = new TStreamerObjectAny(dmName, dmTitle, offset, dmFull);
561  if (!streamer && !clm->GetStreamer() && !clm->IsLoaded()) {
562  Warning("Build", "%s: %s has no streamer or dictionary, data member \"%s\" will not be saved", GetName(), dmFull, dmName);
563  }
564  }
565  }
566  }
567  if (!element) {
568  // If we didn't make an element, there is nothing to do.
569  continue;
570  }
571  if (!dsize) {
572  dsize = dm->GetUnitSize();
573  }
574  for (Int_t i = 0; i < ndim; ++i) {
575  auto maxIndex = 0;
576  if (isStdArray) maxIndex = maxIndices[i];
577  else maxIndex = dm->GetMaxIndex(i);
578  element->SetMaxIndex(i, maxIndex);
579  }
580  element->SetArrayDim(ndim);
581  // If the datamember was a int[4] this is 4, if double[3][2] 3*2=6
582  Int_t narr = element->GetArrayLength();
583  if (!narr) {
584  narr = 1;
585  }
586  element->SetSize(dsize*narr);
587  element->SetStreamer(streamer);
588  if (!streamer) {
589  Int_t k = element->GetType();
590  if (k == kStreamer) {
591  //if ((k == kSTL) || (k == kSTL + kOffsetL) || (k == kStreamer) || (k == kStreamLoop))
592  element->SetType(-1);
593  }
594  }
595 
596  if ( !wasCompiled && (rules && rules.HasRuleWithSource( element->GetName(), kTRUE )) ) {
597  needAllocClass = kTRUE;
598 
599  // If this is optimized to re-use TStreamerElement(s) in case of variable renaming,
600  // then we must revisit the code in TBranchElement::InitInfo that recalculate the
601  // fID (i.e. the index of the TStreamerElement to be used for streaming).
602 
603  TStreamerElement *cached = element;
604  // Now that we are caching the unconverted element, we do not assign it to the real type even if we could have!
605  if (element->GetNewType()>0 /* intentionally not including base class for now */
606  && rules && !rules.HasRuleWithTarget( element->GetName(), kTRUE ) )
607  {
608  TStreamerElement *copy = (TStreamerElement*)element->Clone();
609  fElements->Add(copy);
611  cached = copy;
612 
613  // Warning("BuildOld","%s::%s is not set from the version %d of %s (You must add a rule for it)\n",GetName(), element->GetName(), GetClassVersion(), GetName() );
614  } else {
615  // If the element is just cached and not repeat, we need to inject an element
616  // to insure the writing.
617  TStreamerElement *writecopy = (TStreamerElement*)element->Clone();
618  fElements->Add(element);
619  writecopy->SetBit(TStreamerElement::kWrite);
620  writecopy->SetNewType( writecopy->GetType() );
621  // Put the write element after the read element (that does caching).
622  element = writecopy;
623  }
625  cached->SetNewType( cached->GetType() );
626  }
627 
628  fElements->Add(element);
629  } // end of member loop
630 
631  // Now add artificial TStreamerElement (i.e. rules that creates new members or set transient members).
633 
634  if (needAllocClass) {
636  if (!infoalloc) {
637  Error("Build","Could you create a TStreamerInfo for %s\n",TString::Format("%s@@%d",GetName(),GetClassVersion()).Data());
638  } else {
639  // Tell clone we should rerun BuildOld
640  infoalloc->SetBit(kBuildOldUsed,false);
641  infoalloc->BuildCheck();
642  infoalloc->BuildOld();
643  TClass *allocClass = infoalloc->GetClass();
644 
645  {
646  TIter next(fElements);
647  TStreamerElement* element;
648  while ((element = (TStreamerElement*) next())) {
649  if (element->TestBit(TStreamerElement::kRepeat) && element->IsaPointer()) {
650  TStreamerElement *other = (TStreamerElement*) infoalloc->GetElements()->FindObject(element->GetName());
651  if (other) {
653  }
654  }
655  }
656  infoalloc->GetElements()->Compress();
657  }
658  {
659  TIter next(fElements);
660  TStreamerElement* element;
661  while ((element = (TStreamerElement*) next())) {
662  if (element->TestBit(TStreamerElement::kCache)) {
663  element->SetOffset(infoalloc->GetOffset(element->GetName()));
664  }
665  }
666  }
667 
668  TStreamerElement *el = new TStreamerArtificial("@@alloc","", 0, TStreamerInfo::kCacheNew, allocClass->GetName());
670 
671  el = new TStreamerArtificial("@@dealloc","", 0, TStreamerInfo::kCacheDelete, allocClass->GetName());
672  fElements->Add( el );
673  }
674  }
675 
676  //
677  // Make a more compact version.
678  //
679  Compile();
680  fIsBuilt = kTRUE;
681 }
682 
683 ////////////////////////////////////////////////////////////////////////////////
684 /// Check if built and consistent with the class dictionary.
685 /// This method is called by TFile::ReadStreamerInfo.
686 
688 {
690 
692  if (!fClass) {
693  // fClassVersion should have been a Version_t and/or Version_t
694  // should have been an Int_t. Changing the on-file format
695  // of the StreamerInfo is 'hard' (for forward compatibility), so
696  // leave it as is for now.
699 
700  // Case of a custom collection (the user provided a CollectionProxy
701  // for a class that is not an STL collection).
702  if (GetElements()->GetEntries() == 1) {
703  TObject *element = GetElements()->UncheckedAt(0);
704  Bool_t isstl = element && strcmp("This",element->GetName())==0;
705  if (isstl) {
706  if (element->GetTitle()[0] == '<') {
707  // We know the content.
708  TString content = element->GetTitle();
709  Int_t level = 1;
710  for(Int_t c = 1; c < content.Length(); ++c) {
711  if (content[c] == '<') ++level;
712  else if (content[c] == '>') --level;
713  if (level == 0) {
714  content.Remove(c+1);
715  break;
716  }
717  }
718  content.Prepend("vector");
719  TClass *clequiv = TClass::GetClass(content);
720  TVirtualCollectionProxy *proxy = clequiv->GetCollectionProxy();
721  if (gDebug > 1)
722  Info("BuildCheck",
723  "Update the collection proxy of the class \"%s\" \n"
724  "\tto be similar to \"%s\".",
725  GetName(),content.Data());
726  fClass->CopyCollectionProxy( *proxy );
727  } else {
728  Warning("BuildCheck", "\n\
729  The class %s had a collection proxy when written but it is not an STL\n \
730  collection and we did not record the type of the content of the collection.\n \
731  We will claim the content is a bool (i.e. no data will be read).",
732  GetName());
733  }
734  }
735  }
736 
737  } else {
740  // We have a collection that is indeed an STL collection,
741  // we know we don't need its streamerInfo.
743  return;
744  }
745  }
746  const TObjArray *array = fClass->GetStreamerInfos();
747  TStreamerInfo* info = 0;
748 
749  if (fClass->TestBit(TClass::kIsEmulation) && array->GetEntries()==0) {
750  // We have an emulated class that has no TStreamerInfo, this
751  // means it was created to insert a (default) rule. Consequently
752  // the error message about the missing dictionary was not printed.
753  // For consistency, let's print it now!
754 
755  ::Warning("TClass::TClass", "no dictionary for class %s is available", GetName());
756  }
757 
758  // Case of a custom collection (the user provided a CollectionProxy
759  // for a class that is not an STL collection).
760  if (GetElements()->GetEntries() == 1) {
761  TObject *element = GetElements()->UncheckedAt(0);
762  Bool_t isstl = element && strcmp("This",element->GetName())==0;
763  if (isstl && !fClass->GetCollectionProxy()) {
764  if (element->GetTitle()[0] == '<') {
765  // We know the content.
766  TString content = element->GetTitle();
767  Int_t level = 1;
768  for(Int_t c = 1; c < content.Length(); ++c) {
769  if (content[c] == '<') ++level;
770  else if (content[c] == '>') --level;
771  if (level == 0) {
772  content.Remove(c+1);
773  break;
774  }
775  }
776  content.Prepend("vector");
777  TClass *clequiv = TClass::GetClass(content);
778  TVirtualCollectionProxy *proxy = clequiv->GetCollectionProxy();
779  if (gDebug > 1)
780  Info("BuildCheck",
781  "Update the collection proxy of the class \"%s\" \n"
782  "\tto be similar to \"%s\".",
783  GetName(),content.Data());
784  fClass->CopyCollectionProxy( *proxy );
785  } else {
786  Warning("BuildCheck", "\n\
787  The class %s had a collection proxy when written but it is not an STL\n \
788  collection and we did not record the type of the content of the collection.\n \
789  We will claim the content is a bool (i.e. no data will be read).",
790  GetName());
791  }
793  return;
794  }
795  }
796 
797  // If the user has not specified a class version (this _used to_
798  // always be the case when the class is Foreign) or if the user
799  // has specified a version to be explicitly 1. [We can not
800  // distinguish the two cases using the information in the "on
801  // file" StreamerInfo.]
802 
803  Bool_t searchOnChecksum = kFALSE;
804  if (fClass->IsLoaded() && fClass->GetClassVersion() >= 2) {
805  // We know for sure that the user specified the version.
806 
807  if (fOnFileClassVersion >= 2) {
808  // The class version was specified when the object was
809  // written
810 
811  searchOnChecksum = kFALSE;
812 
813  } else {
814  // The class version was not specified when the object was
815  // written OR it was specified to be 1.
816 
817  searchOnChecksum = kTRUE;
818  }
819  } else if (fClass->IsLoaded() && !fClass->IsForeign()) {
820  // We are in the case where the class has a Streamer function.
821  // and fClass->GetClassVersion is 1, we still assume that the
822  // Class Version is specified (to be one).
823 
824  searchOnChecksum = kFALSE;
825 
826  } else if (fClass->IsLoaded() /* implied: && fClass->IsForeign() */ ) {
827  // We are in the case of a Foreign class with no specified
828  // class version.
829 
830  searchOnChecksum = kTRUE;
831 
832  }
833  else {
834  // We are in the case of an 'emulated' class.
835 
836  if (fOnFileClassVersion >= 2) {
837  // The class version was specified when the object was
838  // written
839 
840  searchOnChecksum = kFALSE;
841 
842  } else {
843  // The class version was not specified when the object was
844  // written OR it was specified to be 1.
845 
846  searchOnChecksum = kTRUE;
847 
848  TStreamerInfo* v1 = (TStreamerInfo*) array->At(1);
849  if (v1) {
850  if (fCheckSum != v1->GetCheckSum()) {
851  fClassVersion = array->GetLast() + 1;
852  }
853  }
854  }
855  }
856 
857  if (!searchOnChecksum) {
858  if (fClassVersion < (array->GetEntriesFast() - 1)) {
859  info = (TStreamerInfo*) array->At(fClassVersion);
860  }
861  } else {
862  Int_t ninfos = array->GetEntriesFast() - 1;
863  for (Int_t i = -1; i < ninfos; ++i) {
864  info = (TStreamerInfo*) array->UncheckedAt(i);
865  if (!info) {
866  continue;
867  }
868  if (fCheckSum == info->GetCheckSum() && (info->GetOnFileClassVersion()==1 || info->GetOnFileClassVersion()==0)) {
869  // We must match on the same checksum, an existing TStreamerInfo
870  // for one of the 'unversioned' class layout (i.e. version was 1).
871  fClassVersion = i;
872  break;
873  }
874  info = 0;
875  }
876  if (info==0) {
877  // Find an empty slot.
878  ninfos = array->GetEntriesFast() - 1;
879  Int_t slot = 1; // Start of Class version 1.
880  while ((slot < ninfos) && (array->UncheckedAt(slot) != 0)) {
881  ++slot;
882  }
883  fClassVersion = slot;
884  }
885  }
886 
887  // NOTE: Should we check if the already existing info is the same as
888  // the current one? Yes
889  // In case a class (eg Event.h) has a TClonesArray of Tracks, it could be
890  // that the old info does not have the class name (Track) in the data
891  // member title. Set old title to new title
892  if (info) {
893  // We found an existing TStreamerInfo for our ClassVersion
894  Bool_t match = kTRUE;
895  Bool_t done = kFALSE;
896  Bool_t oldIsNonVersioned = kFALSE;
897  if (fClassVersion!=0 && !fClass->TestBit(TClass::kWarned) && (fClassVersion == info->GetClassVersion()) && (fCheckSum != info->GetCheckSum())) {
898  // The TStreamerInfo's checksum is different from the checksum for the compile class.
899 
900  match = kFALSE;
901  oldIsNonVersioned = info->fOnFileClassVersion==1 && info->fClassVersion != 1;
902 
904  // In the case where the read-in TStreamerInfo does not
905  // match in the 'current' in memory TStreamerInfo for
906  // a non foreign class (we can not get here if this is
907  // a foreign class so we do not need to test it),
908  // we need to add this one more test since the CINT behaviour
909  // with enums changed over time, so verify the checksum ignoring
910  // members of type enum. We also used to not count the //[xyz] comment
911  // in the checksum, so test for that too.
913  &&(info->GetCheckSum() == fClass->GetCheckSum() || fClass->MatchLegacyCheckSum(info->GetCheckSum()))
914  )
915  {
916  match = kTRUE;
917  }
918  if (fOldVersion <= 2) {
919  // Names of STL base classes was modified in vers==3. Allocators removed
920  // (We could be more specific (see test for the same case below)
921  match = kTRUE;
922  }
923  if (!match && CompareContent(0,info,kFALSE,kFALSE,file)) {
924  match = kTRUE;
925  }
926 #ifdef TEST_FOR_BACKWARD_COMPATIBILITY_ABSTRACT_CLASSES
927  if (!match && file->GetVersion() < 51800 && fClass && (fClass->Property() & kIsAbstract)
928  && fClass->GetListOfDataMembers()->GetEntries() != 0)
929  {
930  // In some instances of old files (v5.17 and less), some StreamerInfo for
931  // an abstract class where not written correctly, and add no
932  // data member listed. If in addition one of the data member
933  // was declared using a typedef _and_ the current class definition
934  // uses a different typedef, we are unable to recalculate the
935  // checksum as it was, because the information is missing from
936  // the StreamerInfo, and for the same reason CompareContent can
937  // not know whether this is okay or not ...
938  //
939  // Since this is such an unlikely scenario, let's complain
940  // about it anyway (The class layout *may* have changed, we
941  // don't know).
942 
943  // if (this has only base classes) {
944  // match = kTRUE;
945  // }
946  }
947 #endif
948  } else {
949  // The on-file TStreamerInfo's checksum differs from the checksum of a TStreamerInfo on another file.
950 
951  match = kFALSE;
952  oldIsNonVersioned = info->fOnFileClassVersion==1 && info->fClassVersion != 1;
953 
954  // In the case where the read-in TStreamerInfo does not
955  // match in the 'current' in memory TStreamerInfo for
956  // a non foreign class (we can not get here if this is
957  // a foreign class so we do not need to test it),
958  // we need to add this one more test since the CINT behaviour
959  // with enums changed over time, so verify the checksum ignoring
960  // members of type enum. We also used to not count the //[xyz] comment
961  // in the checksum, so test for that too.
965  || MatchLegacyCheckSum(info->GetCheckSum())
967  {
968  match = kTRUE;
969  }
970  if (fOldVersion <= 2) {
971  // Names of STL base classes was modified in vers==3. Allocators removed
972  // (We could be more specific (see test for the same case below)
973  match = kTRUE;
974  }
975  if (!match && CompareContent(0,info,kFALSE,kFALSE,file)) {
976  match = kTRUE;
977  }
978  }
979  }
980  if (info->IsBuilt()) {
982  fNumber = info->GetNumber();
983  Int_t nel = fElements->GetEntriesFast();
984  TObjArray* elems = info->GetElements();
985  TStreamerElement* e1 = 0;
986  TStreamerElement* e2 = 0;
987  for (Int_t i = 0; i < nel; ++i) {
989  e2 = (TStreamerElement*) elems->At(i);
990  if (!e1 || !e2) {
991  continue;
992  }
993  if (strlen(e1->GetTitle()) != strlen(e2->GetTitle())) {
994  e2->SetTitle(e1->GetTitle());
995  }
996  }
997 
998  done = kTRUE;
999  } else {
1001  info = 0;
1002  }
1003  TString origin;
1004  if (!match && !fClass->TestBit(TClass::kWarned)) {
1005  if (oldIsNonVersioned) {
1006  if (file) {
1007  Warning("BuildCheck", "\n\
1008  The class %s transitioned from not having a specified class version\n\
1009  to having a specified class version (the current class version is %d).\n\
1010  However too many different non-versioned layouts of the class have been\n\
1011  loaded so far. This prevent the proper reading of objects written with\n\
1012  the class layout version %d, in particular from the file:\n\
1013  %s.\n\
1014  To work around this issue, load fewer 'old' files in the same ROOT session.",
1016  } else {
1017  Warning("BuildCheck", "\n\
1018  The class %s transitioned from not having a specified class version\n\
1019  to having a specified class version (the current class version is %d).\n\
1020  However too many different non-versioned layouts of the class have been\n\
1021  loaded so far. This prevent the proper reading of objects written with\n\
1022  the class layout version %d.\n\
1023  To work around this issue, load fewer 'old' files in the same ROOT session.",
1025  }
1026  } else {
1027  if (file) {
1028  if (done) {
1029  Warning("BuildCheck", "\n\
1030  The StreamerInfo for version %d of class %s read from the file %s\n\
1031  has a different checksum than the previously loaded StreamerInfo.\n\
1032  Reading objects of type %s from the file %s \n\
1033  (and potentially other files) might not work correctly.\n\
1034  Most likely the version number of the class was not properly\n\
1035  updated [See ClassDef(%s,%d)].",
1036  fClassVersion, GetName(), file->GetName(), GetName(), file->GetName(), GetName(), fClassVersion);
1037  } else {
1038  Warning("BuildCheck", "\n\
1039  The StreamerInfo from %s does not match existing one (%s:%d)\n\
1040  The existing one has not been used yet and will be discarded.\n\
1041  Reading the file %s will work properly, however writing object of\n\
1042  type %s will not work properly. Most likely the version number\n\
1043  of the class was not properly updated [See ClassDef(%s,%d)].",
1044  file->GetName(), GetName(), fClassVersion,file->GetName(),GetName(), GetName(), fClassVersion);
1045  }
1046  } else {
1047  if (done) {
1048  Warning("BuildCheck", "\n\
1049  The StreamerInfo for version %d of class %s\n\
1050  has a different checksum than the previously loaded StreamerInfo.\n\
1051  Reading objects of type %s\n\
1052  (and potentially other files) might not work correctly.\n\
1053  Most likely the version number of the class was not properly\n\
1054  updated [See ClassDef(%s,%d)].",
1056  } else {
1057  Warning("BuildCheck", "\n\
1058  The StreamerInfo from %s does not match existing one (%s:%d)\n\
1059  The existing one has not been used yet and will be discarded.\n\
1060  Reading should work properly, however writing object of\n\
1061  type %s will not work properly. Most likely the version number\n\
1062  of the class was not properly updated [See ClassDef(%s,%d)].",
1064  }
1065  }
1066  }
1067  CompareContent(0,info,kTRUE,kTRUE,file);
1069  }
1070  if (done) {
1071  return;
1072  }
1073  }
1074  // The slot was free, however it might still be reserved for the current
1075  // loaded version of the class
1076  if (fClass->IsLoaded()
1078  && (fClassVersion != 0) // We don't care about transient classes
1080  && (fCheckSum != fClass->GetCheckSum())) {
1081 
1082  // If the old TStreamerInfo matches the in-memory one when we either
1083  // - ignore the members of type enum
1084  // or
1085  // - ignore the comments annotation (//[xyz])
1086  // we can accept the old TStreamerInfo.
1087 
1089 
1091  if (warn) {
1092  warn = !CompareContent(fClass,0,kFALSE,kFALSE,file);
1093  }
1094 #ifdef TEST_FOR_BACKWARD_COMPATIBILITY_ABSTRACT_CLASSES
1095  if (warn && file->GetVersion() < 51800 && fClass && (fClass->Property() & kIsAbstract)
1096  && fClass->GetListOfDataMembers()->GetEntries() != 0)
1097  {
1098  // In some instances of old files (v5.17 and less), some StreamerInfo for
1099  // an abstract class where not written correctly, and add no
1100  // data member listed. If in addition one of the data member
1101  // was declared using a typedef _and_ the current class definition
1102  // uses a different typedef, we are unable to recalculate the
1103  // checksum as it was, because the information is missing from
1104  // the StreamerInfo, and for the same reason CompareContent can
1105  // not know whether this is okay or not ...
1106  //
1107  // Since this is such an unlikely scenario, let's complain
1108  // about it anyway (The class layout *may* have changed, we
1109  // don't know).
1110 
1111  // if (this has only base classes) {
1112  // warn = kFALSE;
1113  // }
1114  }
1115 #endif // TEST_FOR_BACKWARD_COMPATIBILITY
1116  if (warn && (fOldVersion <= 2)) {
1117  // Names of STL base classes was modified in vers==3. Allocators removed
1118  //
1119  TIter nextBC(fClass->GetListOfBases());
1120  TBaseClass* bc = 0;
1121  while ((bc = (TBaseClass*) nextBC())) {
1122  if (bc->GetClassPointer()->GetCollectionType()) {
1123  warn = kFALSE;
1124  }
1125  }
1126  }
1127  if (warn) {
1128  if (file) {
1129  Warning("BuildCheck", "\n\
1130  The StreamerInfo of class %s read from file %s\n\
1131  has the same version (=%d) as the active class but a different checksum.\n\
1132  You should update the version to ClassDef(%s,%d).\n\
1133  Do not try to write objects with the current class definition,\n\
1134  the files will not be readable.\n", GetName(), file->GetName(), fClassVersion, GetName(), fClassVersion + 1);
1135  } else {
1136  Warning("BuildCheck", "\n\
1137  The StreamerInfo of class %s \n\
1138  has the same version (=%d) as the active class but a different checksum.\n\
1139  You should update the version to ClassDef(%s,%d).\n\
1140  Do not try to write objects with the current class definition,\n\
1141  the files will not be readable.\n", GetName(), fClassVersion, GetName(), fClassVersion + 1);
1142  }
1143  CompareContent(fClass,0,kTRUE,kTRUE,file);
1145  }
1146  } else {
1147  if (!fClass->IsVersioned()) {
1148  Fatal("BuildCheck", "\n\
1149  The StreamerInfo of unversioned class %s \n\
1150  has the same version (=%d) as the active class but an old checksum.\n\
1151  This should not happen. An assert will follow.\n", GetName(), fClassVersion);
1152  }
1153  }
1154  }
1155  if (!fClass->IsLoaded() && this->fOnFileClassVersion>1)
1156  {
1157  ROOT::ResetClassVersion(fClass,(const char*)-1, this->fClassVersion);
1158  }
1159  }
1160  // FIXME: This code can never execute because Build() calls
1161  // TStreamerElement::Class()->IgnoreTObjectStreamer()
1162  // so our bits are never saved to the file.
1165  }
1166  if ((fClassVersion < -1) || (fClassVersion > 65000)) {
1167  printf("ERROR reading TStreamerInfo: %s fClassVersion=%d\n", GetName(), fClassVersion);
1168  SetBit(kCanDelete);
1169  fNumber = -1;
1170  return;
1171  }
1172 
1175  && GetCheckSum() != fClass->GetCheckSum()
1177  // We got here, thus we are a perfect alias for the current streamerInfo,
1178  // but we might had odd v5 style name spelling, so let's prefer the
1179  // current one.
1180  SetBit(kCanDelete);
1181  return;
1182  }
1183 
1185  ++fgCount;
1186  fNumber = fgCount;
1187 
1188  // Since we just read this streamerInfo from file, it has already been built.
1189  fIsBuilt = kTRUE;
1190 
1191  //add to the global list of StreamerInfo
1192  TObjArray* infos = (TObjArray*) gROOT->GetListOfStreamerInfo();
1193  infos->AddAtAndExpand(this, fNumber);
1194 }
1195 
1196 ////////////////////////////////////////////////////////////////////////////////
1197 /// Create an Emulation TStreamerInfo object.
1198 
1200 {
1202 
1203  TString duName;
1204  R__ASSERT(file);
1205  Int_t fv = file->GetVersion()%100000;
1206  R__ASSERT(fv < 30000);
1207  fClassVersion = -1;
1208  fCheckSum = 2001;
1209  TObjArray *elements = GetElements();
1210  Int_t ndata = elements ? elements->GetEntries() : 0;
1211  for (Int_t i=0;i < ndata;i++) {
1212  TStreamerElement *element = (TStreamerElement*)elements->UncheckedAt(i);
1213  if (!element) break;
1214  int ty = element->GetType();
1215  if (ty < kChar || ty >kULong+kOffsetL) continue;
1216  if (ty == kLong) element->SetType(kInt);
1217  if (ty == kULong) element->SetType(kUInt);
1218  if (ty == kLong + kOffsetL) element->SetType(kInt + kOffsetL);
1219  if (ty == kULong + kOffsetL) element->SetType(kUInt + kOffsetL);
1220  if (ty <= kULong) continue;
1221  duName = element->GetName();
1222  duName.Append("QWERTY");
1223  TStreamerBasicType *bt = new TStreamerBasicType(duName, "", 0, kInt,"Int_t");
1224  {for (int j=ndata-1;j>=i;j--) {elements->AddAtAndExpand(elements->At(j),j+1);}}
1225  elements->AddAt(bt,i);
1226  ndata++;
1227  i++;
1228  }
1229  BuildOld();
1230 }
1231 
1232 ////////////////////////////////////////////////////////////////////////////////
1233 /// Check if we can build this for foreign class - do we have some rules
1234 /// to do that.
1235 
1236 Bool_t TStreamerInfo::BuildFor( const TClass *in_memory_cl )
1237 {
1239 
1240  if( !in_memory_cl || !in_memory_cl->GetSchemaRules() ) {
1241  return kFALSE;
1242  }
1243 
1244  auto rules = in_memory_cl->GetSchemaRules()->FindRules( GetName(), fOnFileClassVersion, fCheckSum );
1245 
1246  if( rules.empty() && !in_memory_cl->GetCollectionType() ) {
1247  Warning( "BuildFor", "The build of %s streamer info for %s has been requested, but no matching conversion rules were specified", GetName(), in_memory_cl->GetName() );
1248  return kFALSE;
1249  }
1250 
1251  fClass = const_cast<TClass*>(in_memory_cl);
1252 
1253  return kTRUE;
1254 }
1255 
1256 
1257 namespace {
1258 ////////////////////////////////////////////////////////////////////////////////
1259 /// Helper function for BuildOld
1260  Bool_t ClassWasMovedToNamespace(TClass *oldClass, TClass *newClass)
1261  {
1262  // Returns true if oldClass is the same as newClass but newClass is in a
1263  // namespace (and oldClass was not in a namespace).
1264 
1265  if (oldClass == 0 || newClass == 0) return kFALSE;
1266 
1267  UInt_t newlen = strlen(newClass->GetName());
1268  UInt_t oldlen = strlen(oldClass->GetName());
1269 
1270  const char *oldname = oldClass->GetName();
1271  for (UInt_t i = oldlen, done = false, nest = 0; (i>0) && !done ; --i) {
1272  switch (oldClass->GetName()[i-1]) {
1273  case '>' : ++nest; break;
1274  case '<' : if (nest==0) return kFALSE; // the name is not well formed, give up.
1275  --nest; break;
1276  case ':' : if (nest == 0) oldname= &(oldClass->GetName()[i]); done = kTRUE; break;
1277  }
1278  }
1279  oldlen = strlen(oldname);
1280  if (!(strlen(newClass->GetName()) > strlen(oldClass->GetName()))) {
1281  return kFALSE;
1282  }
1283 
1284  const char* newEnd = & (newClass->GetName()[newlen-oldlen]);
1285 
1286  if (0 != strcmp(newEnd, oldname)) {
1287  return kFALSE;
1288  }
1289 
1290  Int_t oldv = oldClass->GetStreamerInfo()->GetClassVersion();
1291 
1292  if (newClass->GetStreamerInfos() && oldv < newClass->GetStreamerInfos()->GetSize() && newClass->GetStreamerInfos()->At(oldv) && strcmp(newClass->GetStreamerInfos()->At(oldv)->GetName(), oldClass->GetName()) != 0) {
1293  // The new class has already a TStreamerInfo for the the same version as
1294  // the old class and this was not the result of an import. So we do not
1295  // have a match
1296  return kFALSE;
1297  }
1298  return kTRUE;
1299  }
1300 
1301 ////////////////////////////////////////////////////////////////////////////////
1302 /// Import the streamerInfo from oldClass to newClass.
1303 ///
1304 /// In case of conflict, returns the version number of the StreamerInfo
1305 /// with the conflict.
1306 /// Return 0 in case of success
1307  Int_t ImportStreamerInfo(TClass *oldClass, TClass *newClass) {
1308 
1309  TIter next(oldClass->GetStreamerInfos());
1310  TStreamerInfo *info;
1311  while ((info = (TStreamerInfo*)next())) {
1312  info = (TStreamerInfo*)info->Clone();
1313  if (!info) {
1314  Error("ImportStreamerInfo","Unable to clone the StreamerInfo for %s.",(*next)->GetName());
1315  } else {
1316  info->SetClass(newClass);
1317  Int_t oldv = info->GetClassVersion();
1318  if (oldv > newClass->GetStreamerInfos()->GetSize() || newClass->GetStreamerInfos()->At(oldv) == 0) {
1319  // All is good.
1320  newClass->RegisterStreamerInfo(info);
1321  } else {
1322  // We verify that we are consistent and that
1323  // newcl->GetStreamerInfos()->UncheckedAt(info->GetClassVersion)
1324  // is already the same as info.
1325  if (strcmp(newClass->GetStreamerInfos()->At(oldv)->GetName(),
1326  oldClass->GetName()) != 0) {
1327  // The existing StreamerInfo does not already come from OldClass.
1328  // This is a real problem!
1329  return oldv;
1330  }
1331  }
1332  }
1333  }
1334  return 0;
1335  }
1336 
1337  Bool_t ContainerMatchTClonesArray(TClass *newClass)
1338  {
1339  // Return true if newClass is a likely valid conversion from
1340  // a TClonesArray
1341 
1342  return newClass->GetCollectionProxy()
1343  && newClass->GetCollectionProxy()->GetValueClass()
1344  && !newClass->GetCollectionProxy()->HasPointers();
1345  }
1346 
1347  Bool_t CollectionMatch(const TClass *oldClass, const TClass* newClass)
1348  {
1349  // Return true if oldClass and newClass points to 2 compatible collection.
1350  // i.e. they contains the exact same type.
1351 
1352  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1353  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1354 
1355  TClass *oldContent = oldProxy->GetValueClass();
1356  TClass *newContent = newProxy->GetValueClass();
1357 
1358  Bool_t contentMatch = kFALSE;
1359  if (oldContent) {
1360  if (oldContent == newContent) {
1361  contentMatch = kTRUE;
1362  } else if (newContent) {
1363  TString oldFlatContent( TMakeProject::UpdateAssociativeToVector(oldContent->GetName()) );
1364  TString newFlatContent( TMakeProject::UpdateAssociativeToVector(newContent->GetName()) );
1365  if (oldFlatContent == newFlatContent) {
1366  contentMatch = kTRUE;
1367  }
1368  } else {
1369  contentMatch = kFALSE;
1370  }
1371  } else {
1372  contentMatch = (newContent==0);
1373  }
1374 
1375  if (contentMatch) {
1376  if ((oldContent==0 && oldProxy->GetType() == newProxy->GetType())
1377  ||(oldContent && oldProxy->HasPointers() == newProxy->HasPointers())) {
1378  // We have compatibles collections (they have the same content)!
1379  return kTRUE;
1380  }
1381  }
1382  return kFALSE;
1383  }
1384 
1385  Bool_t CollectionMatchFloat16(const TClass *oldClass, const TClass* newClass)
1386  {
1387  // Return true if oldClass and newClass points to 2 compatible collection.
1388  // i.e. they contains the exact same type.
1389 
1390  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1391  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1392 
1393  if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
1394  && (oldProxy->GetType() == kFloat_t || oldProxy->GetType() == kFloat16_t)
1395  && (newProxy->GetType() == kFloat_t || newProxy->GetType() == kFloat16_t )) {
1396  // We have compatibles collections (they have the same content)!
1397  return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1398  }
1399  return kFALSE;
1400  }
1401 
1402  Bool_t CollectionMatchDouble32(const TClass *oldClass, const TClass* newClass)
1403  {
1404  // Return true if oldClass and newClass points to 2 compatible collection.
1405  // i.e. they contains the exact same type.
1406 
1407  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1408  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1409 
1410  if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
1411  && (oldProxy->GetType() == kDouble_t || oldProxy->GetType() == kDouble32_t)
1412  && (newProxy->GetType() == kDouble_t || newProxy->GetType() == kDouble32_t )) {
1413  // We have compatibles collections (they have the same content)!
1414  return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1415  }
1416  return kFALSE;
1417  }
1418 
1419  Bool_t CollectionMatchLong64(const TClass *oldClass, const TClass* newClass)
1420  {
1421  // Return true if oldClass and newClass points to 2 compatible collection.
1422  // i.e. they contains the exact same type.
1423 
1424  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1425  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1426 
1427  if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
1428  && (oldProxy->GetType() == kLong_t || oldProxy->GetType() == kLong64_t)
1429  && (newProxy->GetType() == kLong_t || newProxy->GetType() == kLong64_t )) {
1430  // We have compatibles collections (they have the same content)!
1431  return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1432  }
1433  return kFALSE;
1434  }
1435 
1436  Bool_t CollectionMatchULong64(const TClass *oldClass, const TClass* newClass)
1437  {
1438  // Return true if oldClass and newClass points to 2 compatible collection.
1439  // i.e. they contains the exact same type.
1440 
1441  TVirtualCollectionProxy *oldProxy = oldClass->GetCollectionProxy();
1442  TVirtualCollectionProxy *newProxy = newClass->GetCollectionProxy();
1443 
1444  if (oldProxy->GetValueClass() == 0 && newProxy->GetValueClass() == 0
1445  && (oldProxy->GetType() == kULong_t || oldProxy->GetType() == kULong64_t)
1446  && (newProxy->GetType() == kULong_t || newProxy->GetType() == kULong64_t )) {
1447  // We have compatibles collections (they have the same content)!
1448  return (oldClass->GetCollectionType() == newClass->GetCollectionType());
1449  }
1450  return kFALSE;
1451  }
1452 
1453  TClass *FindAlternate(TClass *context, const std::string &i_name, std::string& newName)
1454  {
1455  // Return a class whose has the name as oldClass and can be found
1456  // within the scope of the class 'context'.
1457 
1458  // First strip any 'const ' prefix or trailing '*'.
1459  std::string name(i_name);
1460  newName.clear();
1461  if (name.compare(0,6,"const ")==0) {
1462  newName = "const ";
1463  name.erase(0,6);
1464  }
1465  std::string suffix;
1466  UInt_t nstars = 0;
1467  while(name[name.length()-nstars-1]=='*') {
1468  ++nstars;
1469  suffix.append("*");
1470  }
1471  if (nstars) {
1472  name.erase(name.length()-nstars,nstars);
1473  }
1474 
1475  std::string alternate(context->GetName());
1476  alternate.append("::");
1477  alternate.append(name);
1478 
1479  TClass *altcl = TClass::GetClass(alternate.c_str(),/*load=*/ false,true);
1480  if (altcl) {
1481  newName.append(altcl->GetName());
1482  newName.append(suffix);
1483  return altcl;
1484  }
1485 
1486  size_t ctxt_cursor = strlen(context->GetName());
1487  for (size_t level = 0; ctxt_cursor != 0; --ctxt_cursor) {
1488  switch (context->GetName()[ctxt_cursor]) {
1489  case '<': --level; break;
1490  case '>': ++level; break;
1491  case ':': if (level == 0) {
1492  // we encountered a scope not within a template
1493  // parameter.
1494  alternate.clear();
1495  alternate.append(context->GetName(),ctxt_cursor+1);
1496  alternate.append(name);
1497  altcl = TClass::GetClass(alternate.c_str(),/*load=*/ false,true);
1498  if (altcl) {
1499  newName.append(altcl->GetName());
1500  newName.append(suffix);
1501  return altcl;
1502  }
1503  }
1504  }
1505  }
1506  newName.clear();
1507  return 0;
1508  }
1509 
1510  TClass *FixCollectionV5(TClass *context, TClass *oldClass, TClass *newClass)
1511  {
1512  assert(oldClass->GetCollectionProxy() && newClass->GetCollectionProxy());
1513 
1514  TVirtualCollectionProxy *old = oldClass->GetCollectionProxy();
1515  TVirtualCollectionProxy *current = newClass->GetCollectionProxy();
1516  Int_t stlkind = old->GetCollectionType();
1517 
1518  if (stlkind == ROOT::kSTLmap || stlkind == ROOT::kSTLmultimap) {
1519 
1520  if (current->GetValueClass() == nullptr) {
1521  // This should really never happen (the content of map should always
1522  // be a pair and thus have a TClass ... so let's just give up ...
1523  // It actually happens in the case where one of the member is an
1524  // enum that is part of dictionary payload that is not yet
1525  // autoloaded.
1526  return nullptr;
1527  }
1528  TVirtualStreamerInfo *info = current->GetValueClass()->GetStreamerInfo();
1529  if (info->GetElements()->GetEntries() != 2) {
1530  return oldClass;
1531  }
1532  TStreamerElement *f = (TStreamerElement*) info->GetElements()->At(0);
1533  TStreamerElement *s = (TStreamerElement*) info->GetElements()->At(1);
1534 
1535  info = old->GetValueClass()->GetStreamerInfo();
1536  assert(info->GetElements()->GetEntries() == 2);
1537  TStreamerElement *of = (TStreamerElement*) info->GetElements()->At(0);
1538  TStreamerElement *os = (TStreamerElement*) info->GetElements()->At(1);
1539 
1540  TClass *firstNewCl = f ? f->GetClass() : 0;
1541  TClass *secondNewCl = s ? s->GetClass() : 0;
1542 
1543  TClass *firstOldCl = of ? of->GetClass() : 0;
1544  TClass *secondOldCl = os ? os->GetClass() : 0;
1545 
1546  if ((firstNewCl && !firstOldCl) || (secondNewCl && !secondOldCl))
1547  {
1548  std::vector<std::string> inside;
1549  int nestedLoc;
1550  TClassEdit::GetSplit( oldClass->GetName(), inside, nestedLoc, TClassEdit::kLong64 );
1551 
1552  TClass *firstAltCl = firstOldCl;
1553  TClass *secondAltCl = secondOldCl;
1554  std::string firstNewName;
1555  std::string secondNewName;
1556  if (firstNewCl && !firstOldCl) {
1557  firstAltCl = FindAlternate(context, inside[1], firstNewName);
1558  }
1559  if (secondNewCl && !secondOldCl) {
1560  secondAltCl = FindAlternate(context, inside[2], secondNewName);
1561  }
1562  if ((firstNewCl && firstAltCl != firstOldCl) ||
1563  (secondNewCl && secondAltCl != secondOldCl) ) {
1564 
1565  // Need to produce new name.
1566  std::string alternate = inside[0];
1567  alternate.append("<");
1568  alternate.append(firstAltCl ? firstNewName : inside[1]);
1569  alternate.append(",");
1570  alternate.append(secondAltCl? secondNewName : inside[2]);
1571  // We are intentionally dropping any further arguments,
1572  // they would be using the wrong typename and would also be
1573  // somewhat superflous since this is for the old layout.
1574  if (alternate[alternate.length()-1]=='>') {
1575  alternate.append(" ");
1576  }
1577  alternate.append(">");
1578  return TClass::GetClass(alternate.c_str(),true,true);
1579  }
1580  }
1581 
1582  } else if (current->GetValueClass() && !old->GetValueClass()
1583  && old->GetType() == kInt_t) {
1584 
1585  // The old CollectionProxy claims it contains int (or enums) while
1586  // the new one claims to contain a class. It is likely that we have
1587  // in the collection name a class (typedef) name that is missing its
1588  // scope. Let's try to check.
1589 
1590  std::vector<std::string> inside;
1591  int nestedLoc;
1592  TClassEdit::GetSplit( oldClass->GetName(), inside, nestedLoc, TClassEdit::kLong64 );
1593 
1594  // Now let's if we can find this missing type.
1595  std::string newName;
1596  TClass *altcl = FindAlternate(context, inside[1], newName);
1597 
1598  if (altcl) {
1599  std::string alternate = inside[0];
1600  alternate.append("<");
1601  alternate.append(newName);
1602  // We are intentionally dropping any further arguments,
1603  // they would be using the wrong typename and would also be
1604  // somewhat superflous since this is for the old layout.
1605  if (alternate[alternate.length()-1]=='>') {
1606  alternate.append(" ");
1607  }
1608  alternate.append(">");
1609  return TClass::GetClass(alternate.c_str(),true,true);
1610  }
1611  }
1612  return 0;
1613  }
1614 
1615  // Makes sure kBuildOldUsed set once BuildOld finishes
1616  struct TBuildOldGuard {
1617  TBuildOldGuard(TStreamerInfo* info): fInfo(info) {
1618  fInfo->SetBit(TStreamerInfo::kBuildRunning);
1619  }
1620  ~TBuildOldGuard() {
1621  fInfo->ResetBit(TStreamerInfo::kBuildRunning);
1622  fInfo->SetBit(TStreamerInfo::kBuildOldUsed);
1623  }
1624  TStreamerInfo* fInfo;
1625  };
1626 }
1627 
1628 ////////////////////////////////////////////////////////////////////////////////
1629 /// rebuild the TStreamerInfo structure
1630 
1632 {
1634 
1635  if ( TestBit(kBuildOldUsed) ) return;
1636 
1637  // Are we recursing on ourself?
1639 
1640  // This is used to avoid unwanted recursive call to Build and make sure
1641  // that we record the execution of BuildOld.
1642  TBuildOldGuard buildOldGuard(this);
1643 
1644  if (gDebug > 0) {
1645  printf("\n====>Rebuilding TStreamerInfo for class: %s, version: %d\n", GetName(), fClassVersion);
1646  }
1647 
1648  Bool_t wasCompiled = IsCompiled();
1649 
1650  if (fClass->GetClassVersion() == fClassVersion) {
1652  {
1653  // Handle emulated classes and STL containers specially.
1654  // in this case BuildRealData would call BuildOld for this same
1655  // TStreamerInfo to be able to build the real data on it.
1656  } else {
1657  fClass->BuildRealData();
1658  }
1659  }
1660  else {
1661  // This is to support the following case
1662  // Shared library: Event v2
1663  // calling cl->GetStreamerInfo(1)->BuildOld(); (or equivalent)
1664  // which calls cl->BuildReadData()
1665  // which set fRealData to some value
1666  // then call Event()
1667  // which call cl->GetStreamerInfo()
1668  // which call cl->BuildRealData();
1669  // which returns immediately (upon seeing fRealData!=0)
1670  // then the main StreamerInfo build using the partial content of fRealData
1671  // then BuildRealData returns
1672  // then GetStreamerInfo() returns
1673  // then Event() returns
1674  // then fRealData is finished being populated
1675  // then this function continue,
1676  // then it uses the main streamerInfo
1677  // .... which is incomplete.
1678  //
1679  // Instead we force the creation of the main streamerInfo object
1680  // before the creation of fRealData.
1682  }
1683 
1684  TIter next(fElements);
1685  TStreamerElement* element;
1686  Int_t offset = 0;
1687  TMemberStreamer* streamer = 0;
1688 
1689  constexpr size_t kSizeOfPtr = sizeof(void*);
1690 
1691  int nBaze = 0;
1692 
1693  if ((fElements->GetEntries() == 1) && !strcmp(fElements->At(0)->GetName(), "This")) {
1694  if (fClass->GetCollectionProxy()) {
1695  element = (TStreamerElement*)next();
1696  element->SetNewType( element->GetType() );
1697  element->SetNewClass( fClass );
1698  } else if (((TStreamerElement*)fElements->At(0))->GetType() == TStreamerInfo::kSTL &&
1699  strcmp( ((TStreamerElement*)fElements->At(0))->GetTypeName(),GetName()) != 0) {
1700  // We have a collection that was proxied but does not have a collection proxy,
1701  // let's put one in place just for fun ... humm however we have no clue what is the value
1702  // type ....
1703 
1704  // For now wild guess ....
1705 
1706  }
1707  }
1708 
1709  TClass *allocClass = 0;
1710  TStreamerInfo *infoalloc = 0;
1711 
1712  //---------------------------------------------------------------------------
1713  // Get schema rules for this class
1714  /////////////////////////////////////////////////////////////////////////////
1715 
1716  ROOT::TSchemaRuleSet::TMatches rules;
1717  const ROOT::TSchemaRuleSet* ruleSet = fClass->GetSchemaRules();
1718 
1719  if (ruleSet) rules = ruleSet->FindRules( GetName(), fOnFileClassVersion, fCheckSum );
1720 
1722  Int_t virtualInfoLocAlloc = 0;
1723  fNVirtualInfoLoc = 0;
1724  delete [] fVirtualInfoLoc;
1725  fVirtualInfoLoc = 0;
1726 
1727  while ((element = (TStreamerElement*) next())) {
1728  if (element->IsA()==TStreamerArtificial::Class()
1729  || element->TestBit(TStreamerElement::kCache) )
1730  {
1731  // Prevent BuildOld from modifying existing ArtificialElement (We need to review when and why BuildOld
1732  // needs to be re-run; it might be needed if the 'current' class change (for example from being an onfile
1733  // version to being a version loaded from a shared library) and we thus may have to remove the artifical
1734  // element at the beginning of BuildOld)
1735 
1736  continue;
1737  };
1738 
1739  element->SetNewType(element->GetType());
1740  if (element->IsBase()) {
1741  //---------------------------------------------------------------------
1742  // Dealing with nonSTL bases
1743  ///////////////////////////////////////////////////////////////////////
1744 
1745  if (element->IsA() == TStreamerBase::Class()) {
1746  TStreamerBase* base = (TStreamerBase*) element;
1747 #if defined(PROPER_IMPLEMEMANTION_OF_BASE_CLASS_RENAMING)
1748  TClass* baseclass = fClass->GetBaseClass( base->GetName() );
1749 #else
1750  // Currently the base class renaming does not work, so we use the old
1751  // version of the code which essentially disable the next if(!baseclass ..
1752  // statement.
1753  TClass* baseclass = base->GetClassPointer();
1754 #endif
1755 
1756  //------------------------------------------------------------------
1757  // We do not have this base class - check if we're renaming
1758  ////////////////////////////////////////////////////////////////////
1759 
1760  if( !baseclass && !fClass->TestBit( TClass::kIsEmulation ) ) {
1761  const ROOT::TSchemaRule* rule = (rules ? rules.GetRuleWithSource( base->GetName() ) : 0);
1762 
1763  //---------------------------------------------------------------
1764  // No renaming, sorry
1765  /////////////////////////////////////////////////////////////////
1766 
1767  if( !rule ) {
1768  Error("BuildOld", "Could not find base class: %s for %s and could not find any matching rename rule\n", base->GetName(), GetName());
1769  continue;
1770  }
1771 
1772  //----------------------------------------------------------------
1773  // Find a new target class
1774  /////////////////////////////////////////////////////////////////
1775 
1776  const TObjArray* targets = rule->GetTarget();
1777  if( !targets ) {
1778  Error("BuildOld", "Could not find base class: %s for %s, renaming rule was found but is malformed\n", base->GetName(), GetName());
1779  }
1780  TString newBaseClass = ((TObjString*)targets->At(0))->GetString();
1781  baseclass = TClass::GetClass( newBaseClass );
1782  base->SetNewBaseClass( baseclass );
1783  }
1784  //-------------------------------------------------------------------
1785  // No base class in emulated mode
1786  ////////////////////////////////////////////////////////////////////
1787 
1788  else if( !baseclass ) {
1789  baseclass = base->GetClassPointer();
1790  if (!baseclass) {
1791  Warning("BuildOld", "Missing base class: %s skipped", base->GetName());
1792  // FIXME: Why is the version number 1 here? Answer: because we don't know any better at this point
1793  baseclass = new TClass(element->GetName(), 1, 0, 0, -1, -1);
1794  element->Update(0, baseclass);
1795  }
1796  }
1797  baseclass->BuildRealData();
1798 
1799  // Calculate the offset using the 'real' base class name (as opposed to the
1800  // '@@emulated' in the case of the emulation of an abstract base class.
1801  Int_t baseOffset = fClass->GetBaseClassOffset(baseclass);
1802 
1803  // Deal with potential schema evolution (renaming) of the base class.
1804  if (baseOffset < 0) {
1805 
1806  // See if this base element can be converted into one of
1807  // the existing base class.
1808  TList* listOfBases = fClass->GetListOfBases();
1809  if (listOfBases) {
1810  TBaseClass* bc = 0;
1811  TIter nextBC(fClass->GetListOfBases());
1812  while ((bc = (TBaseClass*) nextBC())) {
1813  TClass *in_memory_bcl = bc->GetClassPointer();
1814  if (in_memory_bcl && in_memory_bcl->GetSchemaRules()) {
1815  auto baserule = in_memory_bcl->GetSchemaRules()->FindRules( base->GetName(), base->GetBaseVersion(), base->GetBaseCheckSum() );
1816  if (!baserule.empty()) {
1817  base->SetNewBaseClass(in_memory_bcl);
1818  baseOffset = bc->GetDelta();
1819 
1820  }
1821  }
1822  }
1823  }
1824  }
1825  // We need to initialize the element now, as we need the
1826  // correct StreamerInfo next.
1827  element->Init(this);
1828 
1829  // Force the StreamerInfo "Compilation" of the base classes first. This is necessary in
1830  // case the base class contains a member used as an array dimension in the derived classes.
1831  TStreamerInfo* infobase;
1832  if (fClass->TestBit(TClass::kIsEmulation) && (baseclass->Property() & kIsAbstract)) {
1833  Int_t version = base->GetBaseVersion();
1834  if (version >= 0 || base->GetBaseCheckSum() == 0) {
1835  infobase = (TStreamerInfo*)baseclass->GetStreamerInfoAbstractEmulated(version);
1836  } else {
1837  infobase = (TStreamerInfo*)baseclass->FindStreamerInfoAbstractEmulated(base->GetBaseCheckSum());
1838  }
1839  if (infobase) baseclass = infobase->GetClass();
1840  }
1841  else {
1842  infobase = (TStreamerInfo*)base->GetBaseStreamerInfo();
1843  }
1844 
1845  if (infobase && infobase->fComp == 0) {
1846  infobase->BuildOld();
1847  }
1848 
1849  if (infobase && shouldHaveInfoLoc && baseclass->TestBit(TClass::kIsEmulation) ) {
1850  if ( (fNVirtualInfoLoc + infobase->fNVirtualInfoLoc) > virtualInfoLocAlloc ) {
1851  ULong_t *store = fVirtualInfoLoc;
1852  virtualInfoLocAlloc = 16 * ( (fNVirtualInfoLoc + infobase->fNVirtualInfoLoc) / 16 + 1);
1853  fVirtualInfoLoc = new ULong_t[virtualInfoLocAlloc];
1854  if (store) {
1855  memcpy(fVirtualInfoLoc, store, sizeof(ULong_t)*fNVirtualInfoLoc);
1856  delete [] store;
1857  }
1858  }
1859  for (int nloc = 0; nloc < infobase->fNVirtualInfoLoc; ++nloc) {
1860  fVirtualInfoLoc[ fNVirtualInfoLoc + nloc ] = baseOffset + infobase->fVirtualInfoLoc[nloc];
1861  }
1862  fNVirtualInfoLoc += infobase->fNVirtualInfoLoc;
1863  }
1864 
1865 
1866  {
1867  if (baseOffset < 0) {
1868  element->SetNewType(-1);
1869  }
1870  }
1871  element->SetOffset(baseOffset);
1872  offset += baseclass->Size();
1873 
1874  continue;
1875  } else {
1876  // Not a base elem but still base, string or STL as a base
1877  nBaze++;
1878  TList* listOfBases = fClass->GetListOfBases();
1879  Int_t baseOffset = -1;
1880  Int_t asize = 0;
1881  if (listOfBases) {
1882  // Do a search for the classname and some of its alternatives spelling.
1883 
1884  TBaseClass* bc = 0;
1885  TIter nextBC(fClass->GetListOfBases());
1886  while ((bc = (TBaseClass*) nextBC())) {
1887  if (strchr(bc->GetName(), '<') || !strcmp(bc->GetName(),"string")) {
1890  if (bcName == elName) {
1891  break;
1892  }
1893  }
1894  }
1895 
1896  if (!bc) {
1897  // Error("BuildOld", "Could not find STL base class: %s for %s\n", element->GetName(), GetName());
1898  offset = kMissing;
1899  element->SetOffset(kMissing);
1900  element->SetNewType(-1);
1901  continue;
1902  } else if (bc->GetClassPointer()->GetCollectionProxy()
1903  && !bc->GetClassPointer()->IsLoaded()
1905  Error("BuildOld","The class \"%s\" is compiled and its base class \"%s\" is a collection and we do not have a dictionary for it, we will not be able to read or write this base class.",GetName(),bc->GetName());
1906  offset = kMissing;
1907  element->SetOffset(kMissing);
1908  element->SetNewType(-1);
1909  continue;
1910  }
1911  baseOffset = bc->GetDelta();
1912  asize = bc->GetClassPointer()->Size();
1913 
1914  } else if (fClass->TestBit( TClass::kIsEmulation )) {
1915  // Do a search for the classname and some of its alternatives spelling.
1916 
1918  if (newInfo == this) {
1919  baseOffset = offset;
1920  asize = element->GetSize();
1921  } else if (newInfo) {
1922  TIter newElems( newInfo->GetElements() );
1923  TStreamerElement *newElement;
1924  while( (newElement = (TStreamerElement*)newElems()) ) {
1925  const char *newElName = newElement->GetName();
1926  if (newElement->IsBase() && (strchr(newElName,'<') || !strcmp(newElName,"string")) ) {
1927  TString bcName(TClassEdit::ShortType(newElName, TClassEdit::kDropStlDefault).c_str());
1929  if (bcName == elName) {
1930  break;
1931  }
1932  }
1933  }
1934  if (!newElement) {
1935  Error("BuildOld", "Could not find STL base class: %s for %s\n", element->GetName(), GetName());
1936  continue;
1937  }
1938  baseOffset = newElement->GetOffset();
1939  asize = newElement->GetSize();
1940  }
1941  }
1942  if (baseOffset == -1) {
1943  TClass* cb = element->GetClassPointer();
1944  if (!cb) {
1945  element->SetNewType(-1);
1946  continue;
1947  }
1948  asize = cb->Size();
1949  baseOffset = fClass->GetBaseClassOffset(cb);
1950  }
1951 
1952  // we know how to read but do we know where to read?
1953  if (baseOffset < 0) {
1954  element->SetNewType(-1);
1955  continue;
1956  }
1957  element->SetOffset(baseOffset);
1958  offset += asize;
1959  element->Init(this);
1960  continue;
1961  } // if element is of type TStreamerBase or not.
1962  } // if (element->IsBase())
1963 
1964  // If we get here, this means that we looked at all the base classes.
1965  if (shouldHaveInfoLoc && fNVirtualInfoLoc==0) {
1966  fNVirtualInfoLoc = 1;
1967  fVirtualInfoLoc = new ULong_t[1]; // To allow for a single delete statement.
1968  fVirtualInfoLoc[0] = offset;
1969  offset += sizeof(TStreamerInfo*);
1970  }
1971 
1972  TDataMember* dm = 0;
1973 
1974  std::string typeNameBuf;
1975  const char* dmType = nullptr;
1976  Bool_t dmIsPtr = false;
1977  Bool_t isUniquePtr = false;
1978  TDataType* dt(nullptr);
1979  Int_t ndim = 0 ; //dm->GetArrayDim();
1980  std::array<Int_t, 5> maxIndices; // 5 is the maximum supported in TStreamerElement::SetMaxIndex
1981  Bool_t isStdArray(kFALSE);
1982 
1983  // First set the offset and sizes.
1984  if (fClass->GetState() <= TClass::kEmulated) {
1985  // Note the initilization in this case are
1986  // delayed until __after__ the schema evolution
1987  // section, just in case the info has changed.
1988 
1989  // We are in the emulated case
1990  streamer = 0;
1991  element->Init(this);
1992  } else {
1993  // The class is known to Cling (and thus is not emulated)
1994  // and we need to use the real offsets.
1995  // However we may not have a 'proper' TClass for it
1996  // (in which case IsLoaded will be false and GetImplFileLine will be -1)
1997 
1998  // First look for the data member in the current class
1999  dm = (TDataMember*) fClass->GetListOfDataMembers()->FindObject(element->GetName());
2000  if (dm && dm->IsPersistent()) {
2001  fClass->BuildRealData();
2002  streamer = 0;
2003  offset = GetDataMemberOffset(dm, streamer);
2004  element->SetOffset(offset);
2005  element->Init(this);
2006 
2007  // Treat unique pointers and std arrays
2008  dmType = dm->GetTypeName();
2009  dmIsPtr = dm->IsaPointer();
2010  Bool_t nameChanged;
2011  typeNameBuf = TClassEdit::GetNameForIO(dmType, TClassEdit::EModType::kNone, &nameChanged);
2012  if (nameChanged) {
2013  isUniquePtr = dmIsPtr = TClassEdit::IsUniquePtr(dmType);
2014  dmType = typeNameBuf.c_str();
2015  }
2016  if ((isStdArray = TClassEdit::IsStdArray(dmType))){ // We tackle the std array case
2018  typeNameBuf,
2019  maxIndices,
2020  ndim);
2021  dmType = typeNameBuf.c_str();
2022  dt = gROOT->GetType(dmType);
2023  }
2024 
2025  // We have a loaded class, let's make sure that if we have a collection
2026  // it is also loaded.
2027  TString dmClassName = TClassEdit::ShortType(dmType,TClassEdit::kDropStlDefault).c_str();
2028  dmClassName = dmClassName.Strip(TString::kTrailing, '*');
2029  if (dmClassName.Index("const ")==0) dmClassName.Remove(0,6);
2030  TClass *elemDm = ! (dt || dm->IsBasic()) ? TClass::GetClass(dmClassName.Data()) : 0;
2031  if (elemDm && elemDm->GetCollectionProxy()
2032  && !elemDm->IsLoaded()
2034  Error("BuildOld","The class \"%s\" is compiled and for its data member \"%s\", we do not have a dictionary for the collection \"%s\", we will not be able to read or write this data member.",GetName(),dm->GetName(),elemDm->GetName());
2035  offset = kMissing;
2036  element->SetOffset(kMissing);
2037  element->SetNewType(-1);
2038  }
2039  element->SetStreamer(streamer);
2040  int narr = element->GetArrayLength();
2041  if (!narr) {
2042  narr = 1;
2043  }
2044  int dsize = dm->GetUnitSize();
2045  element->SetSize(dsize*narr);
2046  } else {
2047  // We did not find it, let's look for it in the base classes via TRealData
2048  TRealData* rd = fClass->GetRealData(element->GetName());
2049  if (rd && rd->GetDataMember()) {
2050  element->SetOffset(rd->GetThisOffset());
2051  element->Init(this);
2052  dm = rd->GetDataMember();
2053  dmType = dm->GetTypeName();
2054  dmIsPtr = dm->IsaPointer();
2055  int narr = element->GetArrayLength();
2056  if (!narr) {
2057  narr = 1;
2058  }
2059  int dsize = dm->GetUnitSize();
2060  element->SetSize(dsize*narr);
2061  }
2062  }
2063  } // Class corresponding to StreamerInfo is emulated or not.
2064 
2065  // Now let's deal with Schema evolution
2066  Int_t newType = -1;
2067  TClassRef newClass;
2068 
2069  if (dm && dm->IsPersistent()) {
2070  auto theType = isStdArray ? dt : dm->GetDataType();
2071  if (theType) {
2072  Bool_t isArray = isStdArray || element->GetArrayLength() >= 1;
2073  Bool_t hasCount = element->HasCounter();
2074  // data member is a basic type
2075  if ((fClass == TObject::Class()) && !strcmp(dm->GetName(), "fBits")) {
2076  //printf("found fBits, changing dtype from %d to 15\n", dtype);
2077  newType = kBits;
2078  } else {
2079  // All the values of EDataType have the same semantic in EReadWrite
2080  newType = (EReadWrite)theType->GetType();
2081  }
2082  if ((newType == ::kChar_t) && dmIsPtr && !isArray && !hasCount) {
2083  newType = ::kCharStar;
2084  } else if (dmIsPtr) {
2085  newType += kOffsetP;
2086  } else if (isArray) {
2087  newType += kOffsetL;
2088  }
2089  }
2090  if (newType == -1) {
2091  newClass = TClass::GetClass(dmType);
2092  }
2093  } else {
2094  // Either the class is not loaded or the data member is gone
2095  if (!fClass->IsLoaded()) {
2097  if (newInfo && (newInfo != this)) {
2098  TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
2099  newClass = newElems ? newElems->GetClassPointer() : 0;
2100  if (newClass == 0) {
2101  newType = newElems ? newElems->GetType() : -1;
2102  if (!(newType < kObject)) {
2103  // sanity check.
2104  newType = -1;
2105  }
2106  }
2107  } else {
2108  newClass = element->GetClassPointer();
2109  if (newClass.GetClass() == 0) {
2110  newType = element->GetType();
2111  if (!(newType < kObject)) {
2112  // sanity check.
2113  newType = -1;
2114  }
2115  }
2116  }
2117  }
2118  }
2119 
2120  if (newType > 0) {
2121  // Case of a numerical type
2122  if (element->GetType() >= TStreamerInfo::kObject) {
2123  // Old type was not a numerical type.
2124  element->SetNewType(-2);
2125  } else if (element->GetType() != newType) {
2126  element->SetNewType(newType);
2127  if (gDebug > 0) {
2128  // coverity[mixed_enums] - All the values of EDataType have the same semantic in EReadWrite
2129  Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
2130  }
2131  }
2132  } else if (newClass.GetClass()) {
2133  // Sometime BuildOld is called again.
2134  // In that case we might already have fix up the streamer element.
2135  // So we need to go back to the original information!
2136  newClass.Reset();
2138  if (oldClass == newClass.GetClass()) {
2139  // Nothing to do, also in the unique_ptr case :)
2140  } else if (ClassWasMovedToNamespace(oldClass, newClass.GetClass())) {
2141  Int_t oldv;
2142  if (0 != (oldv = ImportStreamerInfo(oldClass, newClass.GetClass()))) {
2143  Warning("BuildOld", "Can not properly load the TStreamerInfo from %s into %s due to a conflict for the class version %d", oldClass->GetName(), newClass->GetName(), oldv);
2144  } else {
2145  element->SetTypeName(newClass->GetName());
2146  if (gDebug > 0) {
2147  Warning("BuildOld", "element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2148  }
2149  }
2150  } else if (oldClass == TClonesArray::Class()) {
2151  if (ContainerMatchTClonesArray(newClass.GetClass())) {
2152  Int_t elemType = element->GetType();
2153  Bool_t isPrealloc = (elemType == kObjectp) || (elemType == kAnyp) || (elemType == (kObjectp + kOffsetL)) || (elemType == (kAnyp + kOffsetL));
2154  element->Update(oldClass, newClass.GetClass());
2155  TVirtualCollectionProxy *cp = newClass->GetCollectionProxy();
2156  TConvertClonesArrayToProxy *ms = new TConvertClonesArrayToProxy(cp, element->IsaPointer(), isPrealloc);
2157  element->SetStreamer(ms);
2158 
2159  // When the type is kObject, the TObject::Streamer is used instead
2160  // of the TStreamerElement's streamer. So let force the usage
2161  // of our streamer
2162  if (element->GetType() == kObject) {
2163  element->SetNewType(kAny);
2164  element->SetType(kAny);
2165  }
2166  if (gDebug > 0) {
2167  Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2168  }
2169  } else {
2170  element->SetNewType(-2);
2171  }
2172  } else if (oldClass && oldClass->GetCollectionProxy() && newClass->GetCollectionProxy()) {
2173  {
2174  TClass *oldFixedClass = FixCollectionV5(GetClass(),oldClass,newClass);
2175  if (oldFixedClass && oldFixedClass != oldClass) {
2176  element->Update(oldClass,oldFixedClass);
2177  oldClass = oldFixedClass;
2178  }
2179  }
2180  if (CollectionMatch(oldClass, newClass)) {
2181  Int_t oldkind = oldClass->GetCollectionType();
2182  Int_t newkind = newClass->GetCollectionType();
2183 
2184  if ( (oldkind==ROOT::kSTLmap || oldkind==ROOT::kSTLmultimap) &&
2185  (newkind!=ROOT::kSTLmap && newkind!=ROOT::kSTLmultimap) ) {
2186 
2187  Int_t elemType = element->GetType();
2188  Bool_t isPrealloc = (elemType == kObjectp) || (elemType == kAnyp) || (elemType == (kObjectp + kOffsetL)) || (elemType == (kAnyp + kOffsetL));
2189 
2190  TClassStreamer *streamer2 = newClass->GetStreamer();
2191  if (streamer2) {
2192  TConvertMapToProxy *ms = new TConvertMapToProxy(streamer2, element->IsaPointer(), isPrealloc);
2193  if (ms && ms->IsValid()) {
2194  element->SetStreamer(ms);
2195  switch( element->GetType() ) {
2196  //case TStreamerInfo::kSTLvarp: // Variable size array of STL containers.
2197  case TStreamerInfo::kSTLp: // Pointer to container with no virtual table (stl) and no comment
2198  case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL: // array of pointers to container with no virtual table (stl) and no comment
2199  element->SetNewType(-2);
2200  break;
2201  case TStreamerInfo::kSTL: // container with no virtual table (stl) and no comment
2202  case TStreamerInfo::kSTL + TStreamerInfo::kOffsetL: // array of containers with no virtual table (stl) and no comment
2203  break;
2204  }
2205  } else {
2206  delete ms;
2207  }
2208  }
2209  element->Update(oldClass, newClass.GetClass());
2210 
2211  } else if ( (newkind==ROOT::kSTLmap || newkind==ROOT::kSTLmultimap) &&
2212  (oldkind!=ROOT::kSTLmap && oldkind!=ROOT::kSTLmultimap) ) {
2213  element->SetNewType(-2);
2214  } else {
2215  element->Update(oldClass, newClass.GetClass());
2216  }
2217  // Is this needed ? : element->SetSTLtype(newelement->GetSTLtype());
2218  if (gDebug > 0) {
2219  Warning("BuildOld","element: %s::%s %s has new type %s", GetName(), element->GetTypeName(), element->GetName(), newClass->GetName());
2220  }
2221  } else if (CollectionMatchFloat16(oldClass,newClass)) {
2222  // Actually nothing to do, since both are the same collection of double in memory.
2223  } else if (CollectionMatchDouble32(oldClass,newClass)) {
2224  // Actually nothing to do, since both are the same collection of double in memory.
2225  } else if (CollectionMatchLong64(oldClass,newClass)) {
2226  // Not much to do since both are the same collection of 8 bits entities on file.
2227  element->Update(oldClass, newClass.GetClass());
2228  } else if (CollectionMatchULong64(oldClass,newClass)) {
2229  // Not much to do since both are the same collection of 8 bits unsigned entities on file
2230  element->Update(oldClass, newClass.GetClass());
2231  } else if (newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() )) {
2232  //------------------------------------------------------------------------
2233  // We can convert one type to another (at least for some of the versions).
2234  /////////////////////////////////////////////////////////////////
2235 
2236  element->SetNewClass( newClass );
2237  } else {
2238  element->SetNewType(-2);
2239  }
2240 
2241  } else if(oldClass &&
2242  newClass.GetClass() &&
2243  newClass->GetSchemaRules() &&
2244  newClass->GetSchemaRules()->HasRuleWithSourceClass( oldClass->GetName() ) ) {
2245  //------------------------------------------------------------------------
2246  // We can convert one type to another (at least for some of the versions).
2247  ////////////////////////////////////////////////////////////////////
2248 
2249  element->SetNewClass( newClass );
2250  } else {
2251  element->SetNewType(-2);
2252  }
2253  // Humm we still need to make sure we have the same 'type' (pointer, embedded object, array, etc..)
2254  Bool_t cannotConvert = kFALSE;
2255  if (element->GetNewType() != -2) {
2256  if (dm) {
2257  if (dmIsPtr) {
2258  if (isUniquePtr || strncmp(dm->GetTitle(),"->",2)==0) {
2259  // We are fine, nothing to do.
2260  if (newClass->IsTObject()) {
2261  newType = kObjectp;
2262  } else if (newClass->GetCollectionProxy()) {
2263  newType = kSTLp;
2264  } else {
2265  newType = kAnyp;
2266  }
2267  } else {
2268  if (TClass::GetClass(dm->GetTypeName())->IsTObject()) {
2269  newType = kObjectP;
2270  } else if (newClass->GetCollectionProxy()) {
2271  newType = kSTLp;
2272  } else {
2273  newType = kAnyP;
2274  }
2275  }
2276  } else {
2277  if (newClass->GetCollectionProxy()) {
2278  newType = kSTL;
2279  } else if (newClass == TString::Class()) {
2280  newType = kTString;
2281  } else if (newClass == TObject::Class()) {
2282  newType = kTObject;
2283  } else if (newClass == TNamed::Class()) {
2284  newType = kTNamed;
2285  } else if (newClass->IsTObject()) {
2286  newType = kObject;
2287  } else {
2288  newType = kAny;
2289  }
2290  }
2291  if ((!dmIsPtr || newType==kSTLp) && (isStdArray ? ndim : dm->GetArrayDim()) > 0) {
2292  newType += kOffsetL;
2293  }
2294  } else if (!fClass->IsLoaded()) {
2296  if (newInfo && (newInfo != this)) {
2297  TStreamerElement* newElems = (TStreamerElement*) newInfo->GetElements()->FindObject(element->GetName());
2298  if (newElems) {
2299  newType = newElems->GetType();
2300  }
2301  } else {
2302  newType = element->GetType();
2303  }
2304  }
2305  if (element->GetType() == kSTL
2306  || ((element->GetType() == kObject || element->GetType() == kAny || element->GetType() == kObjectp || element->GetType() == kAnyp)
2307  && oldClass == TClonesArray::Class()))
2308  {
2309  cannotConvert = (newType != kSTL && newType != kObject && newType != kAny && newType != kSTLp && newType != kObjectp && newType != kAnyp);
2310 
2311  } else if (element->GetType() == kSTLp || ((element->GetType() == kObjectP || element->GetType() == kAnyP) && oldClass == TClonesArray::Class()) )
2312  {
2313  cannotConvert = (newType != kSTL && newType != kObject && newType != kAny && newType != kSTLp && newType != kObjectP && newType != kAnyP);
2314 
2315  } else if (element->GetType() == kSTL + kOffsetL
2316  || ((element->GetType() == kObject + kOffsetL|| element->GetType() == kAny + kOffsetL|| element->GetType() == kObjectp+ kOffsetL || element->GetType() == kAnyp+ kOffsetL)
2317  && oldClass == TClonesArray::Class()))
2318  {
2319  cannotConvert = (newType != kSTL + kOffsetL && newType != kObject+ kOffsetL && newType != kAny+ kOffsetL && newType != kSTLp+ kOffsetL && newType != kObjectp+ kOffsetL && newType != kAnyp+ kOffsetL);
2320 
2321  } else if (element->GetType() == kSTLp + kOffsetL || ((element->GetType() == kObjectP+ kOffsetL || element->GetType() == kAnyP+ kOffsetL) && oldClass == TClonesArray::Class()) )
2322  {
2323  cannotConvert = (newType != kSTL+ kOffsetL && newType != kObject+ kOffsetL && newType != kAny+ kOffsetL && newType != kSTLp + kOffsetL&& newType != kObjectP+ kOffsetL && newType != kAnyP+ kOffsetL);
2324 
2325  } else if ((element->GetType() == kObjectp || element->GetType() == kAnyp
2326  || element->GetType() == kObject || element->GetType() == kAny
2327  || element->GetType() == kTObject || element->GetType() == kTNamed || element->GetType() == kTString )) {
2328  // We had Type* ... ; //-> or Type ...;
2329  // this is completely compatible with the same and with a embedded object.
2330  if (newType != -1) {
2331  if (newType == kObjectp || newType == kAnyp
2332  || newType == kObject || newType == kAny
2333  || newType == kTObject || newType == kTNamed || newType == kTString) {
2334  // We are fine, no transformation to make
2335  element->SetNewType(newType);
2336  } else {
2337  // We do not support this yet.
2338  cannotConvert = kTRUE;
2339  }
2340  } else {
2341  // We have no clue
2342  printf("%s We have no clue\n", dm->GetName());
2343  cannotConvert = kTRUE;
2344  }
2345  } else if (element->GetType() == kObjectP || element->GetType() == kAnyP) {
2346  if (newType != -1) {
2347  if (newType == kObjectP || newType == kAnyP ) {
2348  // nothing to do}
2349  } else {
2350  cannotConvert = kTRUE;
2351  }
2352  } else {
2353  // We have no clue
2354  cannotConvert = kTRUE;
2355  }
2356  }
2357  }
2358  if (cannotConvert) {
2359  element->SetNewType(-2);
2360  if (gDebug > 0) {
2361  // coverity[mixed_enums] - All the values of EDataType have the same semantic in EReadWrite
2362  Info("BuildOld", "element: %s %s::%s has new type: %s/%d", element->GetTypeName(), GetName(), element->GetName(), dm ? dm->GetFullTypeName() : TDataType::GetTypeName((EDataType)newType), newType);
2363  }
2364  }
2365  } else {
2366  element->SetNewType(-1);
2367  offset = kMissing;
2368  element->SetOffset(kMissing);
2369  }
2370 
2371  if (offset != kMissing && fClass->GetState() <= TClass::kEmulated) {
2372  // Note the initialization in this case are
2373  // delayed until __after__ the schema evolution
2374  // section, just in case the info has changed.
2375 
2376  // The class is NOT known to Cling, i.e. is emulated,
2377  // and we need to use the calculated offset.
2378 
2379  Int_t asize;
2380  if (element->GetType() == TStreamerInfo::kSTL &&
2381  strcmp(element->GetName(),"This") == 0 &&
2382  strcmp(element->GetTypeName(),GetName()) == 0 &&
2383  !fClass->GetCollectionProxy()) {
2384  // Humm .. we are missing the collection Proxy
2385  // for a proxied (custom) collection ... avoid
2386  // an infinite recursion and take a wild guess
2387  asize = sizeof(std::vector<int>);
2388  } else {
2389  // Regular case
2390  asize = element->GetSize();
2391  }
2392  // align the non-basic data types (required on alpha and IRIX!!)
2393  if ((offset % kSizeOfPtr) != 0) {
2394  offset = offset - (offset % kSizeOfPtr) + kSizeOfPtr;
2395  }
2396  element->SetOffset(offset);
2397  offset += asize;
2398  }
2399 
2400  if (!wasCompiled && rules) {
2401  if (rules.HasRuleWithSource( element->GetName(), kTRUE ) ) {
2402 
2403  if (allocClass == 0) {
2404  infoalloc = (TStreamerInfo *)Clone(TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()));
2405  if (!infoalloc) {
2406  Error("BuildOld","Unable to create the StreamerInfo for %s.",TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()).Data());
2407  } else {
2408  infoalloc->SetBit(kBuildOldUsed,false);
2409  infoalloc->BuildCheck();
2410  infoalloc->BuildOld();
2411  allocClass = infoalloc->GetClass();
2412  }
2413  }
2414 
2415  // Now that we are caching the unconverted element, we do not assign it to the real type even if we could have!
2416  if (element->GetNewType()>0 /* intentionally not including base class for now */
2417  && !rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2418 
2419  TStreamerElement *copy = (TStreamerElement*)element->Clone();
2420  R__TObjArray_InsertBefore( fElements, copy, element );
2421  next(); // move the cursor passed the insert object.
2423  element = copy;
2424 
2425  // Warning("BuildOld","%s::%s is not set from the version %d of %s (You must add a rule for it)\n",GetName(), element->GetName(), GetClassVersion(), GetName() );
2426  } else {
2427  // If the element is just cached and not repeat, we need to inject an element
2428  // to insure the writing.
2429  TStreamerElement *writecopy = (TStreamerElement*)element->Clone();
2430  R__TObjArray_InsertAfter( fElements, writecopy, element );
2431  next(); // move the cursor passed the insert object.
2432  writecopy->SetBit(TStreamerElement::kWrite);
2433  writecopy->SetNewType( writecopy->GetType() );
2434  writecopy->SetBit(TStreamerElement::kCache);
2435  writecopy->SetOffset(infoalloc ? infoalloc->GetOffset(element->GetName()) : 0);
2436  }
2437  element->SetBit(TStreamerElement::kCache);
2438  element->SetNewType( element->GetType() );
2439  element->SetOffset(infoalloc ? infoalloc->GetOffset(element->GetName()) : 0);
2440  } else if (rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2441  // The data member exist in the onfile StreamerInfo and there is a rule
2442  // that has the same member 'only' has a target ... so this means we are
2443  // asked to ignore the input data ...
2444  if (element->GetType() == kCounter) {
2445  // If the element is a counter, we will need its value to read
2446  // other data member, so let's do so (by not disabling it) even
2447  // if the value will be over-written by a rule.
2448  } else {
2449  element->SetOffset(kMissing);
2450  }
2451  }
2452  } else if (rules && rules.HasRuleWithTarget( element->GetName(), kTRUE ) ) {
2453  // The data member exist in the onfile StreamerInfo and there is a rule
2454  // that has the same member 'only' has a target ... so this means we are
2455  // asked to ignore the input data ...
2456  if (element->GetType() == kCounter) {
2457  // If the element is a counter, we will need its value to read
2458  // other data member, so let's do so (by not disabling it) even
2459  // if the value will be over-written by a rule.
2460  } else {
2461  element->SetOffset(kMissing);
2462  }
2463  }
2464 
2465  if (element->GetNewType() == -2) {
2466  Warning("BuildOld", "Cannot convert %s::%s from type: %s to type: %s, skip element", GetName(), element->GetName(), element->GetTypeName(), newClass ? newClass->GetName() : (dm ? dm->GetFullTypeName() : "unknown") );
2467  }
2468  }
2469 
2470  // If we get here, this means that there no data member after the last base class
2471  // (or no base class at all).
2472  if (shouldHaveInfoLoc && fNVirtualInfoLoc==0) {
2473  fNVirtualInfoLoc = 1;
2474  fVirtualInfoLoc = new ULong_t[1]; // To allow for a single delete statement.
2475  fVirtualInfoLoc[0] = offset;
2476  offset += sizeof(TStreamerInfo*);
2477  }
2478 
2479  // change order , move "bazes" to the end. Workaround old bug
2480  if ((fOldVersion <= 2) && nBaze) {
2481  SetBit(kRecovered);
2482  TObjArray& arr = *fElements;
2483  TObjArray tai(nBaze);
2484  int narr = arr.GetLast() + 1;
2485  int iel;
2486  int jel = 0;
2487  int kel = 0;
2488  for (iel = 0; iel < narr; ++iel) {
2489  element = (TStreamerElement*) arr[iel];
2490  if (element->IsBase() && (element->IsA() != TStreamerBase::Class())) {
2491  tai[kel++] = element;
2492  } else {
2493  arr[jel++] = element;
2494  }
2495  }
2496  for (kel = 0; jel < narr;) {
2497  arr[jel++] = tai[kel++];
2498  }
2499  }
2500 
2501  // Now add artificial TStreamerElement (i.e. rules that creates new members or set transient members).
2502  if (!wasCompiled) InsertArtificialElements(rules);
2503 
2504  if (!wasCompiled && allocClass) {
2505 
2506  TStreamerElement *el = new TStreamerArtificial("@@alloc","", 0, TStreamerInfo::kCacheNew, allocClass->GetName());
2507  R__TObjArray_InsertAt( fElements, el, 0 );
2508 
2509  el = new TStreamerArtificial("@@dealloc","", 0, TStreamerInfo::kCacheDelete, allocClass->GetName());
2510  fElements->Add( el );
2511  }
2512 
2513  Compile();
2514 }
2515 
2516 ////////////////////////////////////////////////////////////////////////////////
2517 /// If opt contains 'built', reset this StreamerInfo as if Build or BuildOld
2518 /// was never called on it (useful to force their re-running).
2519 
2521 {
2522  TString opt = option;
2523  opt.ToLower();
2524 
2525  if (opt.Contains("build")) {
2527 
2528  delete [] fComp; fComp = 0;
2529  delete [] fCompFull; fCompFull= 0;
2530  delete [] fCompOpt; fCompOpt = 0;
2531  fNdata = 0;
2532  fNfulldata = 0;
2533  fNslots= 0;
2534  fSize = 0;
2535  ResetIsCompiled();
2537 
2541  if (fReadText) fReadText->fActions.clear();
2545  if (fWriteText) fWriteText->fActions.clear();
2546  }
2547 }
2548 
2549 namespace {
2550  // TMemberInfo
2551  // Local helper class to be able to compare data member represented by
2552  // 2 distinct TStreamerInfos
2553  class TMemberInfo {
2554  public:
2555  TClass *fParent;
2556  TString fName;
2557  TString fClassName;
2558  TString fComment;
2559  Int_t fDataType;
2560 
2561  TMemberInfo(TClass *parent) : fParent(parent) {};
2562 
2563  void SetDataType(Int_t datatype) {
2564  fDataType = datatype;
2565  }
2566 
2567  void SetName(const char *name) {
2568  fName = name;
2569  }
2570  void SetClassName(const char *name) {
2572  }
2573  void SetComment(const char *title) {
2574  const char *left = strstr(title,"[");
2575  if (left) {
2576  const char *right = strstr(left,"]");
2577  if (right) {
2578  ++left;
2579  fComment.Append(left,right-left);
2580  }
2581  }
2582  }
2583  void Clear() {
2584  fName.Clear();
2585  fClassName.Clear();
2586  fComment.Clear();
2587  }
2588  /* Hide this not yet used implementation to suppress warnings message
2589  from icc 11
2590  Bool_t operator==(const TMemberInfo &other) {
2591  return fName==other.fName
2592  && fClassName == other.fClassName
2593  && fComment == other.fComment;
2594  }
2595  */
2596  Bool_t operator!=(const TMemberInfo &other) {
2597  if (fName != other.fName) return kTRUE;
2598  if (fDataType < TStreamerInfo::kObject) {
2599  // For simple type, let compare the data type
2600  if (fDataType != other.fDataType) {
2601  if ( (fDataType == 4 && other.fDataType == 16)
2602  || (fDataType == 16 && other.fDataType == 4) ) {
2603  // long and 'long long' have the same file format
2604  } else if ( (fDataType == 14 && other.fDataType == 17)
2605  || (fDataType == 17 && other.fDataType == 14) ) {
2606  // unsigned long and 'unsigned long long' have the same file format
2607  } else if ( (fDataType == 3 && other.fDataType == 6)
2608  ||(fDataType == 6 && other.fDataType == 3) ){
2609  // Int_t and kCounter. As the switch from Int_t (3) to
2610  // kCounter (6) might be triggered by a derived class using
2611  // the field as an array size, the class itself has no
2612  // control on what the field type really use.
2613  } else {
2614  return kTRUE;
2615  }
2616  }
2617  } else if (fClassName != other.fClassName) {
2618  if ( (fClassName == "long" && (other.fClassName == "long long" || other.fClassName == "Long64_t"))
2619  || ( (fClassName == "long long" || fClassName == "Long64_t") && other.fClassName == "long") ) {
2620  // This is okay both have the same on file format.
2621  } else if ( (fClassName == "unsigned long" && (other.fClassName == "unsigned long long" || other.fClassName == "ULong64_t"))
2622  || ( (fClassName == "unsigned long long" || fClassName == "ULong64_t") && other.fClassName == "unsigned long") ) {
2623  // This is okay both have the same on file format.
2624  } else if (TClassEdit::IsSTLCont(fClassName)) {
2626  TString othername = TClassEdit::ShortType( other.fClassName, TClassEdit::kDropStlDefault );
2627  if (name != othername) {
2628  TClass *cl = TClass::GetClass(name);
2629  TClass *otherCl = TClass::GetClass(othername);
2630  if (!CollectionMatch(cl,otherCl)) {
2631  TClass *oldFixedClass = FixCollectionV5(fParent,cl,otherCl);
2632  if (!oldFixedClass || !CollectionMatch(oldFixedClass,otherCl)) {
2633  return kTRUE;
2634  }
2635  }
2636  }
2637  } else {
2638  return kTRUE;
2639  }
2640  }
2641  return fComment != other.fComment;
2642  }
2643  };
2644 }
2645 
2646 ////////////////////////////////////////////////////////////////////////////////
2647 /// Emulated a call ShowMembers() on the obj of this class type, passing insp and parent.
2648 
2649 void TStreamerInfo::CallShowMembers(const void* obj, TMemberInspector &insp, Bool_t isTransient) const
2650 {
2651  TIter next(fElements);
2652  TStreamerElement* element = (TStreamerElement*) next();
2653 
2654  TString elementName;
2655 
2656  for (; element; element = (TStreamerElement*) next()) {
2657 
2658  // Skip elements which have not been allocated memory.
2659  if (element->GetOffset() == kMissing) {
2660  continue;
2661  }
2662 
2663  char* eaddr = ((char*)obj) + element->GetOffset();
2664 
2665  if (element->IsBase()) {
2666  // Nothing to do this round.
2667  } else if (element->IsaPointer()) {
2668  elementName.Form("*%s",element->GetFullName());
2669  insp.Inspect(fClass, insp.GetParent(), elementName.Data(), eaddr, isTransient);
2670  } else {
2671  insp.Inspect(fClass, insp.GetParent(), element->GetFullName(), eaddr, isTransient);
2672  Int_t etype = element->GetType();
2673  switch(etype) {
2674  case kObject:
2675  case kAny:
2676  case kTObject:
2677  case kTString:
2678  case kTNamed:
2679  case kSTL:
2680  {
2681  TClass *ecl = element->GetClassPointer();
2682  if (ecl && (fClass!=ecl /* This happens 'artificially for stl container see the use of "This" */)) {
2683  insp.InspectMember(ecl, eaddr, TString(element->GetName()) + ".", isTransient);
2684  }
2685  break;
2686  }
2687  } // switch(etype)
2688  } // if IsaPointer()
2689  } // Loop over elements
2690 
2691  // And now do the base classes
2692  next.Reset();
2693  element = (TStreamerElement*) next();
2694  for (; element; element = (TStreamerElement*) next()) {
2695  if (element->IsBase()) {
2696  // Skip elements which have not been allocated memory.
2697  if (element->GetOffset() == kMissing) {
2698  continue;
2699  }
2700 
2701  char* eaddr = ((char*)obj) + element->GetOffset();
2702 
2703  TClass *ecl = element->GetClassPointer();
2704  if (ecl) {
2705  ecl->CallShowMembers(eaddr, insp, isTransient);
2706  }
2707  } // If is a abse
2708  } // Loop over elements
2709 }
2710 
2711 ////////////////////////////////////////////////////////////////////////////////
2712 /// Make a clone of an object using the Streamer facility.
2713 /// If newname is specified, this will be the name of the new object.
2714 
2715 TObject *TStreamerInfo::Clone(const char *newname) const
2716 {
2717  TStreamerInfo *newinfo = (TStreamerInfo*)TNamed::Clone(newname);
2718  if (newname && newname[0] && fName != newname) {
2719  TObjArray *newelems = newinfo->GetElements();
2720  Int_t ndata = newelems->GetEntries();
2721  for(Int_t i = 0; i < ndata; ++i) {
2722  TObject *element = newelems->UncheckedAt(i);
2723  if (element->IsA() == TStreamerLoop::Class()) {
2724  TStreamerLoop *eloop = (TStreamerLoop*)element;
2725  if (fName == eloop->GetCountClass()) {
2726  eloop->SetCountClass(newname);
2727  eloop->Init();
2728  }
2729  } else if (element->IsA() == TStreamerBasicPointer::Class()) {
2730  TStreamerBasicPointer *eptr = (TStreamerBasicPointer*)element;
2731  if (fName == eptr->GetCountClass()) {
2732  eptr->SetCountClass(newname);
2733  eptr->Init();
2734  }
2735  }
2736  }
2737  }
2738  return newinfo;
2739 }
2740 
2741 ////////////////////////////////////////////////////////////////////////////////
2742 /// Return True if the current StreamerInfo in cl or info is equivalent to this TStreamerInfo.
2743 ///
2744 /// In this context 'Equivalent' means the same number of persistent data member which the same actual C++ type and
2745 /// the same name.
2746 /// If 'warn' is true, Warning message are printed to explicit the differences.
2747 /// If 'complete' is false, stop at the first error, otherwise continue until all members have been checked.
2748 
2750 {
2751  Bool_t result = kTRUE;
2752  R__ASSERT( (cl==0 || info==0) && (cl!=0 || info!=0) /* must compare to only one thing! */);
2753 
2754  TString name;
2755  TString type;
2756  TStreamerElement *el;
2757  TStreamerElement *infoel = 0;
2758 
2759  TIter next(GetElements());
2760  TIter infonext((TList*)0);
2761  TIter basenext((TList*)0);
2762  TIter membernext((TList*)0);
2763  if (info) {
2764  infonext = info->GetElements();
2765  }
2766  if (cl) {
2767  TList *tlb = cl->GetListOfBases();
2768  if (tlb) { // Loop over bases
2769  basenext = tlb;
2770  }
2771  tlb = cl->GetListOfDataMembers();
2772  if (tlb) {
2773  membernext = tlb;
2774  }
2775  }
2776 
2777  // First let's compare base classes
2778  Bool_t done = kFALSE;
2779  TString localClass;
2780  TString otherClass;
2781  while(!done) {
2782  localClass.Clear();
2783  otherClass.Clear();
2784  el = (TStreamerElement*)next();
2785  if (el && el->IsBase()) {
2786  localClass = el->GetName();
2787  } else {
2788  el = 0;
2789  }
2790  if (cl) {
2791  TBaseClass *tbc = (TBaseClass*)basenext();
2792  if (tbc) {
2793  otherClass = tbc->GetName();
2794  } else if (el==0) {
2795  done = kTRUE;
2796  break;
2797  }
2798  } else {
2799  infoel = (TStreamerElement*)infonext();
2800  if (infoel && infoel->IsBase()) {
2801  otherClass = infoel->GetName();
2802  } else if (el==0) {
2803  done = kTRUE;
2804  break;
2805  }
2806  }
2807  if (TClassEdit::IsSTLCont(localClass)) {
2808  localClass = TClassEdit::ShortType( localClass, TClassEdit::kDropStlDefault );
2809  otherClass = TClassEdit::ShortType( otherClass, TClassEdit::kDropStlDefault );
2810  }
2811  // Need to normalize the name
2812  if (localClass != otherClass) {
2813  if (warn) {
2814  if (el==0) {
2815  Warning("CompareContent",
2816  "The in-memory layout version %d for class '%s' has a base class (%s) that the on-file layout version %d does not have.",
2817  GetClassVersion(), GetName(), otherClass.Data(), GetClassVersion());
2818  } else if (otherClass.Length()==0) {
2819  Warning("CompareContent",
2820  "The on-file layout version %d for class '%s' has a base class (%s) that the in-memory layout version %d does not have",
2821  GetClassVersion(), GetName(), localClass.Data(), GetClassVersion());
2822  } else {
2823  Warning("CompareContent",
2824  "One base class of the on-file layout version %d and of the in memory layout version %d for '%s' is different: '%s' vs '%s'",
2825  GetClassVersion(), GetClassVersion(), GetName(), localClass.Data(), otherClass.Data());
2826  }
2827  }
2828  if (!complete) return kFALSE;
2829  result = result && kFALSE;
2830  }
2831  if (cl) {
2832  TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
2833  if (!localBase) continue;
2834  // We already have localBaseClass == otherBaseClass
2835  TClass *otherBaseClass = localBase->GetClassPointer();
2836  if (!otherBaseClass) continue;
2837  if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBaseClass->GetClassVersion()) {
2838  TString msg;
2839  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2840  " has the same version (=%d) as the active class but a different checksum.\n"
2841  " You should update the version to ClassDef(%s,%d).\n"
2842  " The objects on this file might not be readable because:\n"
2843  " The in-memory layout version %d for class '%s' has a base class (%s) with version %d but the on-file layout version %d recorded the version number %d for this base class (%s).",
2844  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2845  GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetClassVersion(),
2846  GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
2847  TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
2848  otherBase->SetErrorMessage(msg);
2849 
2850  } else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBaseClass->GetCheckSum()) {
2851  TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
2852  if (!localBaseInfo) {
2853  // We are likely in the situation where the base class comes after the derived
2854  // class in the TFile's list of StreamerInfo, so it has not yet been loaded,
2855  // let's see if it is there.
2856  const TList *list = file->GetStreamerInfoCache();
2857  localBaseInfo = list ? (TStreamerInfo*)list->FindObject(localBase->GetName()) : 0;
2858  }
2859  if (!localBaseInfo) {
2860  TString msg;
2861  msg.Form(" The StreamerInfo of the base class %s (of class %s) read from %s%s\n"
2862  " refers to a checksum (%x) that can not be found neither in memory nor in the file.\n",
2863  otherBaseClass->GetName(), localClass.Data(),
2864  file ? "file " : "", file ? file->GetName() : "",
2865  localBase->GetBaseCheckSum()
2866  );
2867  TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
2868  otherBase->SetErrorMessage(msg);
2869  continue;
2870  }
2871  if (localBaseInfo->CompareContent(otherBaseClass,0,kFALSE,kFALSE,file) ) {
2872  // They are equivalent, no problem.
2873  continue;
2874  }
2875  TString msg;
2876  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2877  " has the same version (=%d) as the active class but a different checksum.\n"
2878  " You should update the version to ClassDef(%s,%d).\n"
2879  " The objects on this file might not be readable because:\n"
2880  " The in-memory layout version %d for class '%s' has a base class (%s) with checksum %x but the on-file layout version %d recorded the checksum value %x for this base class (%s).",
2881  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2882  GetClassVersion(), GetName(), otherClass.Data(), otherBaseClass->GetCheckSum(),
2883  GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
2884  TStreamerBase *otherBase = (TStreamerBase*)cl->GetStreamerInfo()->GetElements()->FindObject(otherClass);
2885  otherBase->SetErrorMessage(msg);
2886  }
2887  } else {
2888  TStreamerBase *localBase = dynamic_cast<TStreamerBase*>(el);
2889  TStreamerBase *otherBase = dynamic_cast<TStreamerBase*>(infoel);
2890  if (!localBase || !otherBase) continue;
2891 
2892  // We already have localBaseClass == otherBaseClass
2893  TClass *otherBaseClass = localBase->GetClassPointer();
2894  if (otherBaseClass->IsVersioned() && localBase->GetBaseVersion() != otherBase->GetBaseVersion()) {
2895  TString msg;
2896  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2897  " has the same version (=%d) as the active class but a different checksum.\n"
2898  " You should update the version to ClassDef(%s,%d).\n"
2899  " The objects on this file might not be readable because:\n"
2900  " The in-memory layout version %d for class '%s' has a base class (%s) with version %d but the on-file layout version %d recorded the version number %d for this base class (%s).",
2901  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2902  GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseVersion(),
2903  GetClassVersion(), localBase->GetBaseVersion(), localClass.Data());
2904  otherBase->SetErrorMessage(msg);
2905 
2906  } else if (!otherBaseClass->IsVersioned() && localBase->GetBaseCheckSum() != otherBase->GetBaseCheckSum())
2907  {
2908  TVirtualStreamerInfo *localBaseInfo = otherBaseClass->FindStreamerInfo(localBase->GetBaseCheckSum());
2909  TVirtualStreamerInfo *otherBaseInfo = otherBaseClass->FindStreamerInfo(otherBase->GetBaseCheckSum());
2910  if (localBaseInfo == otherBaseInfo ||
2911  localBaseInfo->CompareContent(0,otherBaseInfo,kFALSE,kFALSE,file) ) {
2912  // They are equivalent, no problem.
2913  continue;
2914  }
2915  TString msg;
2916  msg.Form(" The StreamerInfo of class %s read from %s%s\n"
2917  " has the same version (=%d) as the active class but a different checksum.\n"
2918  " You should update the version to ClassDef(%s,%d).\n"
2919  " The objects on this file might not be readable because:\n"
2920  " The in-memory layout version %d for class '%s' has a base class (%s) with checksum %x but the on-file layout version %d recorded the checksum value %x for this base class (%s).",
2921  GetName(), file ? "file " : "", file ? file->GetName() : "", fClassVersion, GetName(), fClassVersion + 1,
2922  GetClassVersion(), GetName(), otherClass.Data(), otherBase->GetBaseCheckSum(),
2923  GetClassVersion(), localBase->GetBaseCheckSum(), localClass.Data());
2924  otherBase->SetErrorMessage(msg);
2925  }
2926  }
2927  }
2928  if (!result && !complete) {
2929  return result;
2930  }
2931  // Next the datamembers
2932  done = kFALSE;
2933  next.Reset();
2934  infonext.Reset();
2935 
2936  TMemberInfo local(GetClass());
2937  TMemberInfo other(cl ? cl : info->GetClass());
2938  UInt_t idx = 0;
2939  while(!done) {
2940  local.Clear();
2941  other.Clear();
2942  el = (TStreamerElement*)next();
2943  while (el && (el->IsBase() || el->IsA() == TStreamerArtificial::Class())) {
2944  el = (TStreamerElement*)next();
2945  ++idx;
2946  }
2947  if (el) {
2948  local.SetName( el->GetName() );
2949  local.SetClassName( el->GetTypeName() );
2950  local.SetComment( el->GetTitle() );
2951  local.SetDataType( el->GetType() );
2952  }
2953  if (cl) {
2954  TDataMember *tdm = (TDataMember*)membernext();
2955  while(tdm && ( (!tdm->IsPersistent()) || (tdm->Property()&kIsStatic) || (el && local.fName != tdm->GetName()) )) {
2956  tdm = (TDataMember*)membernext();
2957  }
2958  if (tdm) {
2959  other.SetName( tdm->GetName() );
2960  other.SetClassName( tdm->GetTrueTypeName() );
2961  other.SetComment( tdm->GetTitle() );
2962  if (tdm->GetDataType()) {
2963  // Need to update the type for arrays.
2964  if (tdm->IsaPointer()) {
2965  if (tdm->GetDataType()->GetType() == TVirtualStreamerInfo::kChar && !tdm->GetArrayDim() && tdm->GetArrayIndex()[0]==0) {
2966  other.SetDataType( TVirtualStreamerInfo::kCharStar );
2967  } else {
2968  other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetP);
2969  }
2970  } else {
2971  if (tdm->GetArrayDim()) {
2972  other.SetDataType( tdm->GetDataType()->GetType() + TVirtualStreamerInfo::kOffsetL);
2973  } else {
2974  other.SetDataType( tdm->GetDataType()->GetType() );
2975  }
2976  }
2977  }
2978  } else if (el==0) {
2979  done = kTRUE;
2980  break;
2981  }
2982  } else {
2983  infoel = (TStreamerElement*)infonext();
2984  while (infoel && (infoel->IsBase() || infoel->IsA() == TStreamerArtificial::Class())) {
2985  infoel = (TStreamerElement*)infonext();
2986  }
2987  if (infoel) {
2988  other.SetName( infoel->GetName() );
2989  other.SetClassName( infoel->GetTypeName() );
2990  other.SetComment( infoel->GetTitle() );
2991  other.SetDataType( infoel->GetType() );
2992  } else if (el==0) {
2993  done = kTRUE;
2994  break;
2995  }
2996  }
2997  if (local!=other) {
2998  if (warn) {
2999  if (!el) {
3000  Warning("CompareContent","The following data member of\nthe in-memory layout version %d of class '%s' is missing from \nthe on-file layout version %d:\n"
3001  " %s %s; //%s"
3003  ,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
3004 
3005  } else if (other.fName.Length()==0) {
3006  Warning("CompareContent","The following data member of\nthe in-memory layout version %d of class '%s' is missing from \nthe on-file layout version %d:\n"
3007  " %s %s; //%s"
3009  ,local.fClassName.Data(),local.fName.Data(),local.fComment.Data());
3010  } else {
3011  Warning("CompareContent","The following data member of\nthe on-file layout version %d of class '%s' differs from \nthe in-memory layout version %d:\n"
3012  " %s %s; //%s\n"
3013  "vs\n"
3014  " %s %s; //%s"
3016  ,local.fClassName.Data(),local.fName.Data(),local.fComment.Data()
3017  ,other.fClassName.Data(),other.fName.Data(),other.fComment.Data());
3018  }
3019  }
3020  result = result && kFALSE;
3021  if (!complete) return result;
3022  }
3023  ++idx;
3024  }
3025  return result;
3026 }
3027 
3028 
3029 ////////////////////////////////////////////////////////////////////////////////
3030 /// Compute total size of all persistent elements of the class
3031 
3033 {
3035  //faster and more precise to use last element offset +size
3036  //on 64 bit machines, offset may be forced to be a multiple of 8 bytes
3037  fSize = element ? element->GetOffset() + element->GetSize() : 0;
3038  if (fNVirtualInfoLoc > 0 && (fVirtualInfoLoc[0]+sizeof(TStreamerInfo*)) >= (ULong_t)fSize) {
3039  fSize = fVirtualInfoLoc[0] + sizeof(TStreamerInfo*);
3040  }
3041 
3042  // On some platform and in some case of layout non-basic data types needs
3043  // to be aligned. So let's be on the safe side and align on the size of
3044  // the pointers. (Question: is that the right thing on x32 ABI ?)
3045  constexpr size_t kSizeOfPtr = sizeof(void*);
3046  if ((fSize % kSizeOfPtr) != 0) {
3047  fSize = fSize - (fSize % kSizeOfPtr) + kSizeOfPtr;
3048  }
3049 }
3050 
3051 ////////////////////////////////////////////////////////////////////////////////
3052 /// Recursively mark streamer infos for writing to a file.
3053 ///
3054 /// Will force this TStreamerInfo to the file and also
3055 /// all the dependencies.
3056 /// If argument force > 0 the loop on class dependencies is forced.
3057 /// This function is called when streaming a class that contains
3058 /// a null pointer. In this case, the TStreamerInfo for the class
3059 /// with the null pointer must be written to the file and also all
3060 /// the TStreamerInfo of all the classes referenced by the class.
3061 /// We must be given a file to write to.
3062 
3064 {
3065  if (!file) {
3066  return;
3067  }
3068  // Get the given file's list of streamer infos marked for writing.
3069  TArrayC* cindex = file->GetClassIndex();
3070  //the test below testing fArray[fNumber]>1 is to avoid a recursivity
3071  //problem in some cases like:
3072  // class aProblemChild: public TNamed {
3073  // aProblemChild *canBeNull;
3074  // };
3075  if ( // -- Done if already marked, and we are not forcing, or forcing is blocked.
3076  (cindex->fArray[fNumber] && !force) || // Streamer info is already marked, and not forcing, or
3077  (cindex->fArray[fNumber] > 1) // == 2 means ignore forcing to prevent infinite recursion.
3078  ) {
3079  return;
3080  }
3081  // We do not want to write streamer info to the file
3082  // for std::string.
3083  static TClassRef string_classref("string");
3084  if (fClass == string_classref) { // We are std::string.
3085  return;
3086  }
3087  // We do not want to write streamer info to the file
3088  // for STL containers.
3089  if (fClass==0) {
3090  // Build or BuildCheck has not been called yet.
3091  // Let's use another means of checking.
3092  if (fElements && fElements->GetEntries()==1 && strcmp("This",fElements->UncheckedAt(0)->GetName())==0) {
3093  // We are an STL collection.
3094  return;
3095  }
3096  } else if (fClass->GetCollectionProxy()) { // We are an STL collection.
3097  return;
3098  }
3099  // Mark ourselves for output, and block
3100  // forcing to prevent infinite recursion.
3101  cindex->fArray[fNumber] = 2;
3102  // Signal the file that the marked streamer info list has changed.
3103  cindex->fArray[0] = 1;
3104  // Recursively mark the streamer infos for
3105  // all of our elements.
3106  TIter next(fElements);
3107  TStreamerElement* element = (TStreamerElement*) next();
3108  for (; element; element = (TStreamerElement*) next()) {
3109  if (element->IsTransient()) continue;
3110  TClass* cl = element->GetClassPointer();
3111  if (cl) {
3112  TVirtualStreamerInfo* si = 0;
3113  if (cl->Property() & kIsAbstract) {
3114  // If the class of the element is abstract, register the
3115  // TStreamerInfo only if it has already been built.
3116  // Otherwise call cl->GetStreamerInfo() would generate an
3117  // incorrect StreamerInfo.
3118  si = cl->GetCurrentStreamerInfo();
3119  } else {
3120  si = cl->GetStreamerInfo();
3121  }
3122  if (si) {
3123  si->ForceWriteInfo(file, force);
3124  }
3125  }
3126  }
3127 }
3128 
3129 ////////////////////////////////////////////////////////////////////////////////
3130 /// Assuming that obj points to (the part of) an object that is of the
3131 /// type described by this streamerInfo, return the actual type of the
3132 /// object (i.e. the type described by this streamerInfo is a base class
3133 /// of the actual type of the object.
3134 /// This routine should only be called if the class described by this
3135 /// StreamerInfo is 'emulated'.
3136 
3137 TClass *TStreamerInfo::GetActualClass(const void *obj) const
3138 {
3139  R__ASSERT(!fClass->IsLoaded());
3140 
3141  if (fNVirtualInfoLoc != 0) {
3142  TStreamerInfo *allocator = *(TStreamerInfo**)( (const char*)obj + fVirtualInfoLoc[0] );
3143  if (allocator) return allocator->GetClass();
3144  }
3145  return (TClass*)fClass;
3146 }
3147 
3148 ////////////////////////////////////////////////////////////////////////////////
3149 /// Return true if the checksum passed as argument is one of the checksum
3150 /// value produced by the older checksum calculation algorithm.
3151 
3153 {
3154  for(UInt_t i = 1; i < TClass::kLatestCheckSum; ++i) {
3155  if ( checksum == GetCheckSum( (TClass::ECheckSum) i) ) return kTRUE;
3156  }
3157  return kFALSE;
3158 }
3159 
3160 ////////////////////////////////////////////////////////////////////////////////
3161 /// Recalculate the checksum of this TStreamerInfo based on its code.
3162 ///
3163 /// The class ckecksum is used by the automatic schema evolution algorithm
3164 /// to uniquely identify a class version.
3165 /// The check sum is built from the names/types of base classes and
3166 /// data members.
3167 /// The valid range of code is determined by ECheckSum.
3168 /// - kNoEnum: data members of type enum are not counted in the checksum
3169 /// - kNoRange: return the checksum of data members and base classes, not including the ranges and array size found in comments.
3170 /// - kWithTypeDef: use the sugared type name in the calculation.
3171 ///
3172 /// This is needed for backward compatibility.
3173 /// ### WARNING
3174 /// This function must be kept in sync with TClass::GetCheckSum.
3175 /// They are both used to handle backward compatibility and should both return the same values.
3176 /// TStreamerInfo uses the information in TStreamerElement while TClass uses the information
3177 /// from TClass::GetListOfBases and TClass::GetListOfDataMembers.
3178 /// Original algorithm from Victor Perevovchikov (perev@bnl.gov).
3179 
3181 {
3182  // kCurrentCheckSum (0) should be kept for backward compatibility, to be
3183  // able to use the inequality checks, we need to set the code to the largest
3184  // value.
3186 
3187  UInt_t id = 0;
3188 
3189  int il;
3190  TString name = GetName();
3191  TString type;
3192  il = name.Length();
3193  for (int i=0; i<il; i++) id = id*3+name[i];
3194 
3195  TIter next(GetElements());
3196  TStreamerElement *el;
3197  while ( (el=(TStreamerElement*)next()) && !fClass->GetCollectionProxy()) { // loop over bases if not a proxied collection
3198  if (el->IsBase()) {
3199  name = el->GetName();
3200  il = name.Length();
3201  for (int i=0; i<il; i++) id = id*3+name[i];
3202  if (code > TClass::kNoBaseCheckSum && el->IsA() == TStreamerBase::Class()) {
3203  TStreamerBase *base = (TStreamerBase*)el;
3204  id = id*3 + base->GetBaseCheckSum();
3205  }
3206  }
3207  } /* End of Base Loop */
3208 
3209  next.Reset();
3210  while ( (el=(TStreamerElement*)next()) ) {
3211  if (el->IsBase()) continue;
3212 
3213  // humm can we tell if a TStreamerElement is an enum?
3214  // Maybe something like:
3215  Bool_t isenum = kFALSE;
3216  if ( el->GetType()==3 && gROOT->GetType(el->GetTypeName())==0) {
3217  // If the type is not an enum but a typedef to int then
3218  // el->GetTypeName() should be return 'int'
3219  isenum = kTRUE;
3220  }
3221  if ( (code > TClass::kNoEnum) && isenum) id = id*3 + 1;
3222 
3223  name = el->GetName(); il = name.Length();
3224 
3225  int i;
3226  for (i=0; i<il; i++) id = id*3+name[i];
3227 
3228  if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3229  // With TClass::kReflexV5 we do not want the Long64 in the name
3230  // nor any typedef.
3232 
3233  } else if (code <= TClass::kWithTypeDef) {
3234  // humm ... In the streamerInfo we only have the desugared/normalized
3235  // names, so we are unable to calculate the name with typedefs ...
3236  // except for the case of the ROOT typedef (Int_t, etc.) which are
3237  // kept by TClassEdit::ResolveTypedef(typeName) but not by TCling's
3238  // normalization ...
3239  //
3240  type = el->GetTypeName();
3241  } else {
3243  }
3244  if (TClassEdit::IsSTLCont(type)) {
3246  }
3247  if (code == TClass::kReflex || code == TClass::kReflexNoComment) {
3248  type.ReplaceAll("ULong64_t","unsigned long long");
3249  type.ReplaceAll("Long64_t","long long");
3250  type.ReplaceAll("signed char","char");
3251  type.ReplaceAll("<signed char","<char");
3252  type.ReplaceAll(",signed char",",char");
3253  if (type=="signed char") type = "char";
3254  }
3255 
3256  il = type.Length();
3257  for (i=0; i<il; i++) id = id*3+type[i];
3258 
3259  int dim = el->GetArrayDim();
3260  if (dim) {
3261  for (i=0;i<dim;i++) id = id*3+el->GetMaxIndex(i);
3262  }
3263 
3264 
3265  if (code > TClass::kNoRange) {
3266  const char *left;
3267  if (code > TClass::kNoRangeCheck)
3269  else
3270  left = strstr(el->GetTitle(),"[");
3271  if (left) {
3272  const char *right = strstr(left,"]");
3273  if (right) {
3274  ++left;
3275  while (left != right) {
3276  id = id*3 + *left;
3277  ++left;
3278  }
3279  }
3280  }
3281  }
3282  }
3283  return id;
3284 }
3285 
3286 ////////////////////////////////////////////////////////////////////////////////
3287 
3288 static void R__WriteConstructorBody(FILE *file, TIter &next)
3289 {
3290  TStreamerElement *element = 0;
3291  next.Reset();
3292  while ((element = (TStreamerElement*)next())) {
3297  if(element->GetArrayLength() <= 1) {
3298  fprintf(file," %s = 0;\n",element->GetName());
3299  } else {
3300  fprintf(file," memset(%s,0,%d);\n",element->GetName(),element->GetSize());
3301  }
3302  }
3303  if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3304  fprintf(file," %s = 0;\n",element->GetName());
3305  }
3306  }
3307 }
3308 
3309 ////////////////////////////////////////////////////////////////////////////////
3310 /// Write down the body of the 'move' constructor.
3311 
3312 static void R__WriteMoveConstructorBody(FILE *file, const TString &protoname, TIter &next)
3313 {
3314  TStreamerElement *element = 0;
3315  next.Reset();
3316  Bool_t atstart = kTRUE;
3317  while ((element = (TStreamerElement*)next())) {
3318  if (element->IsBase()) {
3319  if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3320  else fprintf(file," , ");
3321  fprintf(file, "%s(const_cast<%s &>( rhs ))\n", element->GetName(),protoname.Data());
3322  } else {
3323  if (element->GetArrayLength() <= 1) {
3324  if (atstart) { fprintf(file," : "); atstart = kFALSE; }
3325  else fprintf(file," , ");
3326  fprintf(file, "%s(const_cast<%s &>( rhs ).%s)\n",element->GetName(),protoname.Data(),element->GetName());
3327  }
3328  }
3329  }
3330  fprintf(file,"{\n");
3331  fprintf(file," // This is NOT a copy constructor. This is actually a move constructor (for stl container's sake).\n");
3332  fprintf(file," // Use at your own risk!\n");
3333  fprintf(file," (void)rhs; // avoid warning about unused parameter\n");
3334  next.Reset();
3335  Bool_t defMod = kFALSE;
3336  while ((element = (TStreamerElement*)next())) {
3339  || element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
3340  {
3341  if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3342  const char *ename = element->GetName();
3343  const char *colon2 = strstr(ename,"::");
3344  if (colon2) ename = colon2+2;
3345  if(element->GetArrayLength() <= 1) {
3346  fprintf(file," modrhs.%s = 0;\n",ename);
3347  } else {
3348  fprintf(file," memset(modrhs.%s,0,%d);\n",ename,element->GetSize());
3349  }
3350  } else {
3351  const char *ename = element->GetName();
3352  if (element->GetType() == kCharStar) {
3353  if (!defMod) {
3354  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3355  };
3356  fprintf(file," modrhs.%s = 0;\n",ename);
3357  } else if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3358  if (!defMod) {
3359  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3360  };
3361  fprintf(file," modrhs.%s = 0;\n",ename);
3362  } else if (element->GetArrayLength() > 1) {
3363  // FIXME: Need to add support for variable length array.
3364  if (element->GetArrayDim() == 1) {
3365  fprintf(file," for (Int_t i=0;i<%d;i++) %s[i] = rhs.%s[i];\n",element->GetArrayLength(),ename,ename);
3366  } else if (element->GetArrayDim() >= 2) {
3367  fprintf(file," for (Int_t i=0;i<%d;i++) (&(%s",element->GetArrayLength(),ename);
3368  for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
3369  fprintf(file,"[0]");
3370  }
3371  fprintf(file,"))[i] = (&(rhs.%s",ename);
3372  for (Int_t d = 0; d < element->GetArrayDim(); ++d) {
3373  fprintf(file,"[0]");
3374  }
3375  fprintf(file,"))[i];\n");
3376  }
3377  } else if (element->GetType() == TVirtualStreamerInfo::kSTLp) {
3378  if (!defMod) { fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE; };
3379  fprintf(file," modrhs.%s = 0;\n",ename);
3380  } else if (element->GetType() == TVirtualStreamerInfo::kSTL) {
3381  if (!defMod) {
3382  fprintf(file," %s &modrhs = const_cast<%s &>( rhs );\n",protoname.Data(),protoname.Data()); defMod = kTRUE;
3383  }
3384  TClass *cle = element->GetClassPointer();
3385  TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3386  std::string method_name = "clear";
3387  if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy && (((TStreamerSTL*)element)->GetSTLtype() == ROOT::kSTLbitset)) {
3388  method_name = "reset";
3389  }
3390  if (element->IsBase()) {
3391  fprintf(file," modrhs.%s();\n", method_name.c_str());
3392  } else {
3393  fprintf(file," modrhs.%s.%s();\n",ename, method_name.c_str());
3394  }
3395  }
3396  }
3397  }
3398 }
3399 
3400 ////////////////////////////////////////////////////////////////////////////////
3401 
3402 static void R__WriteDestructorBody(FILE *file, TIter &next)
3403 {
3404  TStreamerElement *element = 0;
3405  next.Reset();
3406  while ((element = (TStreamerElement*)next())) {
3409  || element->GetType() == TVirtualStreamerInfo::kAnyPnoVT)
3410  {
3411  const char *ename = element->GetName();
3412  const char *colon2 = strstr(ename,"::");
3413  if (colon2) ename = colon2+2;
3414  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3415  if(element->GetArrayLength() <= 1) {
3416  fprintf(file," %s = 0;\n",ename);
3417  } else {
3418  fprintf(file," memset(%s,0,%d);\n",ename,element->GetSize());
3419  }
3420  } else {
3421  if(element->GetArrayLength() <= 1) {
3422  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3423  } else {
3424  fprintf(file," for (Int_t i=0;i<%d;i++) delete %s[i]; memset(%s,0,%d);\n",element->GetArrayLength(),ename,ename,element->GetSize());
3425  }
3426  }
3427  }
3428  if (element->GetType() == TVirtualStreamerInfo::kCharStar) {
3429  const char *ename = element->GetName();
3430  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3431  fprintf(file," %s = 0;\n",ename);
3432  } else {
3433  fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3434  }
3435  }
3436  if (TVirtualStreamerInfo::kOffsetP <= element->GetType() && element->GetType() < TVirtualStreamerInfo::kObject ) {
3437  const char *ename = element->GetName();
3438  if (element->TestBit(TStreamerElement::kDoNotDelete)) {
3439  fprintf(file," %s = 0;\n",ename);
3440  } else if (element->HasCounter()) {
3441  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3442  } else {
3443  fprintf(file," delete [] %s; %s = 0;\n",ename,ename);
3444  }
3445  }
3446  if (element->GetType() == TVirtualStreamerInfo::kSTL || element->GetType() == TVirtualStreamerInfo::kSTLp) {
3447  const char *ename = element->GetName();
3448  const char *prefix = "";
3449  if ( element->GetType() == TVirtualStreamerInfo::kSTLp ) {
3450  prefix = "*";
3451  } else if ( element->IsBase() ) {
3452  ename = "this";
3453  }
3454  TClass *cle = element->GetClassPointer();
3455  TVirtualCollectionProxy *proxy = cle ? element->GetClassPointer()->GetCollectionProxy() : 0;
3456  if (!element->TestBit(TStreamerElement::kDoNotDelete) && proxy) {
3457  Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
3458 
3459  if (proxy->HasPointers()) {
3460  fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3461  //fprintf(file," %s::iterator iter;\n");
3462  //fprintf(file," %s::iterator begin = (%s %s).begin();\n");
3463  //fprintf(file," %s::iterator end (%s %s).end();\n");
3464  //fprintf(file," for( iter = begin; iter != end; ++iter) { delete *iter; }\n");
3465  } else {
3466  if (stltype == ROOT::kSTLmap || stltype == ROOT::kSTLmultimap) {
3468  std::vector<std::string> inside;
3469  int nestedLoc;
3470  TClassEdit::GetSplit(enamebasic, inside, nestedLoc, TClassEdit::kLong64);
3471  if (inside[1][inside[1].size()-1]=='*' || inside[2][inside[2].size()-1]=='*') {
3472  fprintf(file," std::for_each( (%s %s).rbegin(), (%s %s).rend(), DeleteObjectFunctor() );\n",prefix,ename,prefix,ename);
3473  }
3474  }
3475  }
3476  }
3477  if ( prefix[0] ) {
3478  fprintf(file," delete %s; %s = 0;\n",ename,ename);
3479  }
3480  }
3481  }
3482 }
3483 
3484 ////////////////////////////////////////////////////////////////////////////////
3485 /// Write the Declaration of class.
3486 
3487 void TStreamerInfo::GenerateDeclaration(FILE *fp, FILE *sfp, const TList *subClasses, Bool_t top)
3488 {
3489  if (fClassVersion == -3) {
3490  return;
3491  }
3492 
3493  Bool_t needGenericTemplate = fElements==0 || fElements->GetEntries() == 0;
3494  Bool_t isTemplate = kFALSE;
3495  const char *clname = GetName();
3496  TString template_protoname;
3497  if (strchr(clname, ':')) {
3498  // We might have a namespace in front of the classname.
3499  Int_t len = strlen(clname);
3500  const char *name = clname;
3501  UInt_t nest = 0;
3502  UInt_t pr_pos = 0;
3503  for (Int_t cur = 0; cur < len; ++cur) {
3504  switch (clname[cur]) {
3505  case '<':
3506  ++nest;
3507  pr_pos = cur;
3508  isTemplate = kTRUE;
3509  break;
3510  case '>':
3511  if (nest == 0) { cur = len; continue; } // the name is not well formed, give up.
3512  --nest;
3513  break;
3514  case ':': {
3515  if (nest == 0 && clname[cur+1] == ':') {
3516  // We have a scope
3517  isTemplate = kFALSE;
3518  name = clname + cur + 2;
3519  }
3520  break;
3521  }
3522  }
3523  }
3524  if (isTemplate) {
3525  template_protoname.Append(clname,pr_pos);
3526  }
3527  clname = name;
3528  } else {
3529  const char *where = strstr(clname, "<");
3530  isTemplate = where != 0;
3531  if (isTemplate) {
3532  template_protoname.Append(clname,where-clname);
3533  }
3534  }
3535 
3536  if (needGenericTemplate && isTemplate) {
3537  TString templateName(TMakeProject::GetHeaderName("template "+template_protoname,0));
3538  fprintf(fp, "#ifndef %s_h\n", templateName.Data());
3539  fprintf(fp, "#define %s_h\n", templateName.Data());
3540  }
3541 
3542  TString protoname;
3543  UInt_t numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, GetName(), top, protoname, 0, kFALSE, needGenericTemplate);
3544 
3545  // Generate class statement with base classes.
3546  TStreamerElement *element;
3547  TIter next(fElements);
3548  Int_t nbase = 0;
3549  while ((element = (TStreamerElement*)next())) {
3550  if (!element->IsBase()) continue;
3551  nbase++;
3552  const char *ename = element->GetName();
3553  if (nbase == 1) fprintf(fp," : public %s",ename);
3554  else fprintf(fp," , public %s",ename);
3555  }
3556  fprintf(fp," {\n");
3557 
3558  // Generate forward declaration nested classes.
3559  if (subClasses && subClasses->GetEntries()) {
3560  Bool_t needheader = true;
3561 
3562  TIter subnext(subClasses);
3563  TStreamerInfo *subinfo;
3564  Int_t len = strlen(GetName());
3565  while ((subinfo = (TStreamerInfo*)subnext())) {
3566  if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':') ) {
3567  if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3568  if (needheader) {
3569  fprintf(fp,"\npublic:\n");
3570  fprintf(fp,"// Nested classes forward declaration.\n");
3571  needheader = false;
3572  }
3573  TString sub_protoname;
3574  UInt_t sub_numberOfClasses = 0;
3575  UInt_t sub_numberOfNamespaces;
3576  if (subinfo->GetClassVersion() == -3) {
3577  sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, 3);
3578  } else {
3579  sub_numberOfNamespaces = TMakeProject::GenerateClassPrefix(fp, subinfo->GetName() + len+2, kFALSE, sub_protoname, &sub_numberOfClasses, kFALSE);
3580  fprintf(fp, ";\n");
3581  }
3582 
3583  for (UInt_t i = 0;i < sub_numberOfClasses;++i) {
3584  fprintf(fp, "}; // end of class.\n");
3585  }
3586  if (sub_numberOfNamespaces > 0) {
3587  Error("GenerateDeclaration","Nested classes %s thought to be inside a namespace inside the class %s",subinfo->GetName(),GetName());
3588  }
3589  }
3590  }
3591  }
3592  }
3593 
3594  fprintf(fp,"\npublic:\n");
3595  fprintf(fp,"// Nested classes declaration.\n");
3596 
3597  // Generate nested classes.
3598  if (subClasses && subClasses->GetEntries()) {
3599  TIter subnext(subClasses,kIterBackward);
3600  TStreamerInfo *subinfo;
3601  Int_t len = strlen(GetName());
3602  while ((subinfo = (TStreamerInfo*)subnext())) {
3603  if (strncmp(GetName(),subinfo->GetName(),len)==0 && (subinfo->GetName()[len]==':')) {
3604  if (subinfo->GetName()[len+1]==':' && strstr(subinfo->GetName()+len+2,":")==0) {
3605  subinfo->GenerateDeclaration(fp, sfp, subClasses, kFALSE);
3606  }
3607  }
3608  }
3609  }
3610 
3611  fprintf(fp,"\npublic:\n");
3612  fprintf(fp,"// Data Members.\n");
3613 
3614  {
3615  // Generate data members.
3616  TString name(128);
3617  Int_t ltype = 12;
3618  Int_t ldata = 10;
3619  Int_t lt,ld,is;
3620  TString line;
3621  line.Resize(kMaxLen);
3622  next.Reset();
3623  while ((element = (TStreamerElement*)next())) {
3624 
3625  if (element->IsBase()) continue;
3626  const char *ename = element->GetName();
3627 
3628  name = ename;
3629  for (Int_t i=0;i < element->GetArrayDim();i++) {
3630  name += TString::Format("[%d]",element->GetMaxIndex(i));
3631  }
3632  name += ";";
3633  ld = name.Length();
3634 
3635  TString enamebasic = element->GetTypeNameBasic();
3636  if (element->IsA() == TStreamerSTL::Class()) {
3637  // If we have a map, multimap, set or multiset,
3638  // and the key is a class, we need to replace the
3639  // container by a vector since we don't have the
3640  // comparator function.
3641  Int_t stltype = ((TStreamerSTL*)element)->GetSTLtype();
3642  switch (stltype) {
3643  case ROOT::kSTLmap:
3644  case ROOT::kSTLmultimap:
3645  case ROOT::kSTLset:
3646  case ROOT::kSTLmultiset:
3649  {
3650  enamebasic = TMakeProject::UpdateAssociativeToVector(enamebasic);
3651  }
3652  default:
3653  // nothing to do.
3654  break;
3655  }
3656  }
3657 
3658  lt = enamebasic.Length();
3659 
3660  line = " ";
3661  line += enamebasic;
3662  if (lt>=ltype) ltype = lt+1;
3663 
3664  for (is = 3+lt; is < (3+ltype); ++is) line += ' ';
3665 
3666  line += name;
3667  if (element->IsaPointer() && !strchr(line,'*')) line[2+ltype] = '*';
3668 
3669  if (ld>=ldata) ldata = ld+1;
3670  for (is = 3+ltype+ld; is < (3+ltype+ldata); ++is) line += ' ';
3671 
3672  line += " //";
3673  line += element->GetTitle();
3674  fprintf(fp,"%s\n",line.Data());
3675  }
3676  }
3677  if (needGenericTemplate && isTemplate) {
3678  // Generate default functions, ClassDef and trailer.
3679  fprintf(fp,"\n %s() {\n",protoname.Data());
3680  R__WriteConstructorBody(fp,next);
3681  fprintf(fp," }\n");
3682  fprintf(fp," %s(const %s & rhs )\n",protoname.Data(),protoname.Data());
3683  R__WriteMoveConstructorBody(fp,protoname,next);
3684  fprintf(fp," }\n");
3685  fprintf(fp," virtual ~%s() {\n",protoname.Data());
3686  R__WriteDestructorBody(fp,next);
3687  fprintf(fp," }\n\n");
3688 
3689  } else {
3690  // Generate default functions, ClassDef and trailer.
3691  fprintf(fp,"\n %s();\n",protoname.Data());
3692  fprintf(fp," %s(const %s & );\n",protoname.Data(),protoname.Data());
3693  fprintf(fp," virtual ~%s();\n\n",protoname.Data());
3694 
3695  // Add the implementations to the source.cxx file.
3697  fprintf(sfp,"#ifndef %s_cxx\n",guard.Data());
3698  fprintf(sfp,"#define %s_cxx\n",guard.Data());
3699  fprintf(sfp,"%s::%s() {\n",GetName(),protoname.Data());
3700  R__WriteConstructorBody(sfp,next);
3701  fprintf(sfp,"}\n");
3702 
3703  fprintf(sfp,"%s::%s(const %s & rhs)\n",GetName(),protoname.Data(),protoname.Data());
3704  R__WriteMoveConstructorBody(sfp,protoname,next);
3705  fprintf(sfp,"}\n");
3706 
3707  fprintf(sfp,"%s::~%s() {\n",GetName(),protoname.Data());
3708  R__WriteDestructorBody(sfp,next);
3709  fprintf(sfp,"}\n");
3710  fprintf(sfp,"#endif // %s_cxx\n\n",guard.Data());
3711  }
3712 
3713  TClass *cl = gROOT->GetClass(GetName());
3714  if (fClassVersion > 1 || (cl && cl->IsTObject()) ) {
3715  // add 1 to class version in case we didn't manage reproduce the class layout to 100%.
3716  if (fClassVersion == 0) {
3717  // If the class was declared 'transient', keep it that way.
3718  fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),0);
3719  } else {
3720  fprintf(fp," ClassDef(%s,%d); // Generated by MakeProject.\n",protoname.Data(),fClassVersion + 1);
3721  }
3722  }
3723  fprintf(fp,"};\n");
3724 
3725  for(UInt_t i=0;i<numberOfNamespaces;++i) {
3726  fprintf(fp,"} // namespace\n");
3727  }
3728 
3729  if (needGenericTemplate && isTemplate) {
3730  fprintf(fp,"#endif // generic template declaration\n");
3731  }
3732 }
3733 
3734 ////////////////////////////////////////////////////////////////////////////////
3735 /// Add to the header file, the \#include need for this class.
3736 
3737 UInt_t TStreamerInfo::GenerateIncludes(FILE *fp, char *inclist, const TList *extrainfos)
3738 {
3739  if (inclist[0]==0) {
3740  // Always have this include for ClassDef.
3741  TMakeProject::AddInclude( fp, "Rtypes.h", kFALSE, inclist);
3742  }
3743  UInt_t ninc = 0;
3744 
3745  const char *clname = GetName();
3746  if (strchr(clname,'<')) {
3747  // This is a template, we need to check the template parameter.
3748  ninc += TMakeProject::GenerateIncludeForTemplate(fp, clname, inclist, kFALSE, extrainfos);
3749  }
3750 
3751  TString name(1024);
3752  Int_t ltype = 10;
3753  Int_t ldata = 10;
3754  Int_t lt;
3755  Int_t ld;
3756  TIter next(fElements);
3757  TStreamerElement *element;
3758  Bool_t incRiostream = kFALSE;
3759  while ((element = (TStreamerElement*)next())) {
3760  //if (element->IsA() == TStreamerBase::Class()) continue;
3761  const char *ename = element->GetName();
3762  const char *colon2 = strstr(ename,"::");
3763  if (colon2) ename = colon2+2;
3764  name = ename;
3765  for (Int_t i=0;i < element->GetArrayDim();i++) {
3766  name += TString::Format("[%d]",element->GetMaxIndex(i));
3767  }
3768  ld = name.Length();
3769  lt = strlen(element->GetTypeName());
3770  if (ltype < lt) ltype = lt;
3771  if (ldata < ld) ldata = ld;
3772 
3773  //must include Riostream.h in case of an STL container
3774  if (!incRiostream && element->InheritsFrom(TStreamerSTL::Class())) {
3775  incRiostream = kTRUE;
3776  TMakeProject::AddInclude( fp, "Riostream.h", kFALSE, inclist);
3777  }
3778 
3779  //get include file name if any
3780  const char *include = element->GetInclude();
3781  if (!include[0]) continue;
3782 
3783  Bool_t greater = (include[0]=='<');
3784  include++;
3785 
3786  if (strncmp(include,"include/",8)==0) {
3787  include += 8;
3788  }
3789  if (strncmp(include,"include\\",9)==0) {
3790  include += 9;
3791  }
3792  if (strncmp(element->GetTypeName(),"pair<",strlen("pair<"))==0) {
3793  TMakeProject::AddInclude( fp, "utility", kTRUE, inclist);
3794  } else if (strncmp(element->GetTypeName(),"auto_ptr<",strlen("auto_ptr<"))==0) {
3795  TMakeProject::AddInclude( fp, "memory", kTRUE, inclist);
3796  } else {
3797  TString incName( include, strlen(include)-1 );
3798  incName = TMakeProject::GetHeaderName(incName,extrainfos);
3799  TMakeProject::AddInclude( fp, incName.Data(), greater, inclist);
3800  }
3801 
3802  if (strchr(element->GetTypeName(),'<')) {
3803  // This is a template, we need to check the template parameter.
3804  ninc += TMakeProject::GenerateIncludeForTemplate(fp, element->GetTypeName(), inclist, kFALSE, extrainfos);
3805  }
3806  }
3807  return ninc;
3808 }
3809 
3810 ////////////////////////////////////////////////////////////////////////////////
3811 /// Generate header file for the class described by this TStreamerInfo
3812 /// the function is called by TFile::MakeProject for each class in the file
3813 
3814 Int_t TStreamerInfo::GenerateHeaderFile(const char *dirname, const TList *subClasses, const TList *extrainfos)
3815 {
3816  // if (fClassVersion == -4) return 0;
3817  if ((fClass && fClass->GetCollectionType()) || TClassEdit::IsSTLCont(GetName())) return 0;
3818  if (strncmp(GetName(),"pair<",strlen("pair<"))==0) return 0;
3819  if (strncmp(GetName(),"auto_ptr<",strlen("auto_ptr<"))==0) return 0;
3820 
3821  TClass *cl = TClass::GetClass(GetName());
3822  if (cl) {
3823  if (cl->HasInterpreterInfo()) return 0; // skip known classes
3824  }
3825  Bool_t isTemplate = kFALSE;
3826  if (strchr(GetName(),':')) {
3827  UInt_t len = strlen(GetName());
3828  UInt_t nest = 0;
3829  UInt_t scope = 0;
3830  for(UInt_t i=len; i>0; --i) {
3831  switch(GetName()[i]) {
3832  case '>': ++nest; if (scope==0) { isTemplate = kTRUE; } break;
3833  case '<': --nest; break;
3834  case ':':
3835  if (nest==0 && GetName()[i-1]==':') {
3836  // We have a scope
3837  TString nsname(GetName(), i-1);
3838  cl = gROOT->GetClass(nsname);
3839  if (cl && (cl->Size()!=0 || (cl->Size()==0 && !cl->HasInterpreterInfo() /*empty 'base' class on file*/))) {
3840  // This class is actually nested.
3841  return 0;
3842  } else if (cl == 0 && extrainfos != 0) {
3843  TStreamerInfo *clinfo = (TStreamerInfo*)extrainfos->FindObject(nsname);
3844  if (clinfo && clinfo->GetClassVersion() == -5) {
3845  // This class is actually nested.
3846  return 0;
3847  }
3848  }
3849  ++scope;
3850  }
3851  break;
3852  }
3853  }
3854  }
3855  Bool_t needGenericTemplate = isTemplate && (fElements==0 || fElements->GetEntries()==0);
3856 
3857  if (gDebug) printf("generating code for class %s\n",GetName());
3858 
3859  // Open the file
3860 
3861  TString headername( TMakeProject::GetHeaderName( GetName(), extrainfos ) );
3862  TString filename;
3863  filename.Form("%s/%s.h",dirname,headername.Data());
3864 
3865  FILE *fp = fopen(filename.Data(),"w");
3866  if (!fp) {
3867  Error("MakeProject","Cannot open output file:%s\n",filename.Data());
3868  return 0;
3869  }
3870 
3871  filename.Form("%s/%sProjectHeaders.h",dirname,gSystem->BaseName(dirname));
3872  FILE *allfp = fopen(filename.Data(),"a");
3873  if (!allfp) {
3874  Error("MakeProject","Cannot open output file:%s\n",filename.Data());
3875  fclose(fp);
3876  return 0;
3877  }
3878  fprintf(allfp,"#include \"%s.h\"\n", headername.Data());
3879  fclose(allfp);
3880 
3881  char *inclist = new char[50000];
3882  inclist[0] = 0;
3883 
3884  // Generate class header.
3885  TDatime td;
3886  fprintf(fp,"//////////////////////////////////////////////////////////\n");
3887  fprintf(fp,"// This class has been generated by TFile::MakeProject\n");
3888  fprintf(fp,"// (%s by ROOT version %s)\n",td.AsString(),gROOT->GetVersion());
3889  fprintf(fp,"// from the StreamerInfo in file %s\n",gDirectory->GetFile()->GetName());
3890  fprintf(fp,"//////////////////////////////////////////////////////////\n");
3891  fprintf(fp,"\n");
3892  fprintf(fp,"\n");
3893  fprintf(fp,"#ifndef %s_h\n",headername.Data());
3894  fprintf(fp,"#define %s_h\n",headername.Data());
3895  TMakeProject::GenerateForwardDeclaration(fp, GetName(), inclist, kFALSE, needGenericTemplate, extrainfos);
3896  fprintf(fp,"\n");
3897 
3898  UInt_t ninc = 0;
3899  ninc += GenerateIncludes(fp, inclist, extrainfos);
3900  if (subClasses) {
3901  TIter subnext(subClasses);
3902  TStreamerInfo *subinfo;
3903  while ((subinfo = (TStreamerInfo*)subnext())) {
3904  ninc = subinfo->GenerateIncludes(fp, inclist, extrainfos);
3905  }
3906  }
3907  fprintf(fp,"\n");
3908 
3909  TString sourcename; sourcename.Form( "%s/%sProjectSource.cxx", dirname, gSystem->BaseName(dirname) );
3910  FILE *sfp = fopen( sourcename.Data(), "a" );
3911  if (sfp) {
3912  GenerateDeclaration(fp, sfp, subClasses);
3913  } else {
3914  Error("GenerateHeaderFile","Could not open %s for appending",sourcename.Data());
3915  }
3916  TMakeProject::GeneratePostDeclaration(fp, this, inclist);
3917 
3918  fprintf(fp,"#endif\n");
3919 
3920  delete [] inclist;
3921  fclose(fp);
3922  if (sfp) fclose(sfp);
3923  return 1;
3924 }
3925 
3926 ////////////////////////////////////////////////////////////////////////////////
3927 /// Compute data member offset.
3928 /// Return pointer to the Streamer function if one exists
3929 
3931 {
3932  TIter nextr(fClass->GetListOfRealData());
3933  char dmbracket[256];
3934  snprintf(dmbracket,255,"%s[",dm->GetName());
3935  Int_t offset = kMissing;
3936  if (!fClass->IsLoaded()) {
3937  // If the 'class' is not loaded, we do not have a TClass bootstrap and thus
3938  // the 'RealData' might not have enough information because of the lack
3939  // of proper ShowMember implementation.
3940  if (! (dm->Property() & kIsStatic) ) {
3941  // Give an offset only to non-static members.
3942  offset = dm->GetOffset();
3943  }
3944  }
3945  TRealData *rdm;
3946  while ((rdm = (TRealData*)nextr())) {
3947  char *rdmc = (char*)rdm->GetName();
3948  //next statement required in case a class and one of its parent class
3949  //have data members with the same name
3950  if (dm->IsaPointer() && rdmc[0] == '*') rdmc++;
3951 
3952  if (rdm->GetDataMember() != dm) continue;
3953  if (strcmp(rdmc,dm->GetName()) == 0) {
3954  offset = rdm->GetThisOffset();
3955  streamer = rdm->GetStreamer();
3956  break;
3957  }
3958  if (strcmp(rdm->GetName(),dm->GetName()) == 0) {
3959  if (rdm->IsObject()) {
3960  offset = rdm->GetThisOffset();
3961  streamer = rdm->GetStreamer();
3962  break;
3963  }
3964  }
3965  if (strstr(rdm->GetName(),dmbracket)) {
3966  offset = rdm->GetThisOffset();
3967  streamer = rdm->GetStreamer();
3968  break;
3969  }
3970  }
3971  return offset;
3972 }
3973 
3974 ////////////////////////////////////////////////////////////////////////////////
3975 /// Return the offset of the data member as indicated by this StreamerInfo.
3976 
3977 Int_t TStreamerInfo::GetOffset(const char *elementName) const
3978 {
3979  if (elementName == 0) return 0;
3980 
3981  Int_t offset = 0;
3982  TStreamerElement *elem = (TStreamerElement*)fElements->FindObject(elementName);
3983  if (elem) offset = elem->GetOffset();
3984 
3985  return offset;
3986 }
3987 
3988 ////////////////////////////////////////////////////////////////////////////////
3989 /// Return total size of all persistent elements of the class (with offsets).
3990 
3992 {
3993  return fSize;
3994 }
3995 
3996 ////////////////////////////////////////////////////////////////////////////////
3997 /// Return total size of all persistent elements of the class
3998 /// use GetSize if you want to get the real size in memory.
3999 
4001 {
4002  TIter next(fElements);
4003  TStreamerElement *element;
4004  Int_t asize = 0;
4005  while ((element = (TStreamerElement*)next())) {
4006  asize += element->GetSize();
4007  }
4008  return asize;
4009 }
4010 
4011 ////////////////////////////////////////////////////////////////////////////////
4012 /// Return the StreamerElement of "datamember" inside our
4013 /// class or any of its base classes.
4014 ///
4015 /// The offset information
4016 /// contained in the StreamerElement is related to its immediately
4017 /// containing class, so we return in 'offset' the offset inside
4018 /// our class.
4019 
4020 TStreamerElement* TStreamerInfo::GetStreamerElement(const char* datamember, Int_t& offset) const
4021 {
4022  if (!fElements) {
4023  return 0;
4024  }
4025 
4026  // Look first at the data members and base classes
4027  // of our class.
4028  TStreamerElement* element = (TStreamerElement*) fElements->FindObject(datamember);
4029  if (element) {
4030  offset = element->GetOffset();
4031  return element;
4032  }
4033 
4034  // Not found, so now try the data members and base classes
4035  // of the base classes of our class.
4036  if (fClass->HasDataMemberInfo()) {
4037  // Our class has a dictionary loaded, use it to search the base classes.
4038  TStreamerElement* base_element = 0;
4039  TBaseClass* base = 0;
4040  TClass* base_cl = 0;
4041  Int_t base_offset = 0;
4042  Int_t local_offset = 0;
4043  TIter nextb(fClass->GetListOfBases());
4044  // Iterate on list of base classes.
4045  while ((base = (TBaseClass*) nextb())) {
4046  base_cl = TClass::GetClass(base->GetName());
4047  base_element = (TStreamerElement*) fElements->FindObject(base->GetName());
4048  if (!base_cl || !base_element) {
4049  continue;
4050  }
4051  base_offset = base_element->GetOffset();
4052  element = ((TStreamerInfo*)base_cl->GetStreamerInfo())->GetStreamerElement(datamember, local_offset);
4053  if (element) {
4054  offset = base_offset + local_offset;
4055  return element;
4056  }
4057  }
4058  } else {
4059  // Our class's dictionary is not loaded. Search through the base class streamer elements.
4060  TIter next(fElements);
4061  TStreamerElement* curelem = 0;
4062  while ((curelem = (TStreamerElement*) next())) {
4063  if (curelem->InheritsFrom(TStreamerBase::Class())) {
4064  TClass* baseClass = curelem->GetClassPointer();
4065  if (!baseClass) {
4066  continue;
4067  }
4068  Int_t base_offset = curelem->GetOffset();
4069  Int_t local_offset = 0;
4070  TStreamerInfo *baseInfo;
4071  if (baseClass->Property() & kIsAbstract) {
4072  baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfoAbstractEmulated();
4073  } else {
4074  baseInfo = (TStreamerInfo*)baseClass->GetStreamerInfo();
4075  }
4076  if (baseInfo) element = baseInfo->GetStreamerElement(datamember, local_offset);
4077  if (element) {
4078  offset = base_offset + local_offset;
4079  return element;
4080  }
4081  }
4082  }
4083  }
4084  return 0;
4085 }
4086 
4087 ////////////////////////////////////////////////////////////////////////////////
4088 /// <b>Obsolete</b>: this routine is obsolete and should not longer be used.
4089 ///
4090 /// TStreamerInfo holds two types of data structures
4091 /// - TObjArray* fElements; containing the list of all TStreamerElement
4092 /// objects for this class version.
4093 /// - ULong_t* fElem; containing the preprocessed information
4094 /// by TStreamerInfo::Compile In case consecutive data members
4095 /// are of the same type, the Compile function declares the consecutive
4096 /// elements as one single element in fElems.
4097 ///
4098 /// Example with the class TAttLine:
4099 /// ~~~{.cpp}
4100 /// TClass::GetClass("TAttLine")->GetStreamerInfo()->ls(); produces;
4101 /// StreamerInfo for class: TAttLine, version=1
4102 /// short fLineColor offset= 4 type= 2 line color
4103 /// short fLineStyle offset= 6 type= 2 line style
4104 /// short fLineWidth offset= 8 type= 2 line width
4105 /// i= 0, fLineColor type= 22, offset= 4, len=3, method=0
4106 /// ~~~
4107 /// For I/O implementations (eg. XML) , one has to know the original name
4108 /// of the data member. This function can be used to return a pointer
4109 /// to the original TStreamerElement object corresponding to the j-th
4110 /// element of a compressed array in fElems.
4111 /// Parameters description:
4112 /// - i: the serial number in array fElem
4113 /// - j: the element number in the array of consecutive types
4114 /// In the above example the class TAttLine has 3 consecutive data members
4115 /// of the same type "short". Compile makes one single array of 3 elements.
4116 /// To access the TStreamerElement for the second element
4117 /// of this array, one can call:
4118 /// ~~~{.cpp}
4119 /// auto el = GetStreamerElementReal(0,1);
4120 /// auto membername = el->GetName();
4121 /// ~~~
4122 /// This function is typically called from TBuffer, TXmlBuffer.
4123 
4125 {
4126  ::Obsolete("TStreamerInfo::GetStreamerElementReal", "v5-34-20", "v6-00-02");
4127 
4128  if (i < 0 || i >= fNdata) return 0;
4129  if (j < 0) return 0;
4130  if (!fElements) return 0;
4131  TStreamerElement *se = (TStreamerElement*)fCompOpt[i]->fElem;
4132  if (!se) return 0;
4133  Int_t nelems = fElements->GetEntriesFast();
4134  for (Int_t ise=0;ise < nelems;ise++) {
4135  if (se != (TStreamerElement*)fElements->UncheckedAt(ise)) continue;
4136  if (ise+j >= nelems) return 0;
4137  return (TStreamerElement*)fElements->UncheckedAt(ise+j);
4138  }
4139  return 0;
4140 }
4141 
4142 ////////////////////////////////////////////////////////////////////////////////
4143 /// Get the value from inside a collection.
4144 
4145 template <typename T>
4147 {
4148  if (type>=kConv && type<kSTL) {
4149  type -= kConv;
4150  }
4151  switch (type) {
4152  // basic types
4153  case kBool: {Bool_t *val = (Bool_t*)ladd; return T(*val);}
4154  case kChar: {Char_t *val = (Char_t*)ladd; return T(*val);}
4155  case kShort: {Short_t *val = (Short_t*)ladd; return T(*val);}
4156  case kInt: {Int_t *val = (Int_t*)ladd; return T(*val);}
4157  case kLong: {Long_t *val = (Long_t*)ladd; return T(*val);}
4158  case kLong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4159  case kFloat: {Float_t *val = (Float_t*)ladd; return T(*val);}
4160  case kFloat16: {Float_t *val = (Float_t*)ladd; return T(*val);}
4161  case kDouble: {Double_t *val = (Double_t*)ladd; return T(*val);}
4162  case kDouble32: {Double_t *val = (Double_t*)ladd; return T(*val);}
4163  case kUChar: {UChar_t *val = (UChar_t*)ladd; return T(*val);}
4164  case kUShort: {UShort_t *val = (UShort_t*)ladd; return T(*val);}
4165  case kUInt: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4166  case kULong: {ULong_t *val = (ULong_t*)ladd; return T(*val);}
4167 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4168  case kULong64: {Long64_t *val = (Long64_t*)ladd; return T(*val);}
4169 #else
4170  case kULong64: {ULong64_t *val= (ULong64_t*)ladd; return T(*val);}
4171 #endif
4172  case kBits: {UInt_t *val = (UInt_t*)ladd; return T(*val);}
4173 
4174  // array of basic types array[8]
4175  case kOffsetL + kBool: {Bool_t *val = (Bool_t*)ladd; return T(val[k]);}
4176  case kOffsetL + kChar: {Char_t *val = (Char_t*)ladd; return T(val[k]);}
4177  case kOffsetL + kShort: {Short_t *val = (Short_t*)ladd; return T(val[k]);}
4178  case kOffsetL + kInt: {Int_t *val = (Int_t*)ladd; return T(val[k]);}
4179  case kOffsetL + kLong: {Long_t *val = (Long_t*)ladd; return T(val[k]);}
4180  case kOffsetL + kLong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4181  case kOffsetL + kFloat: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4182  case kOffsetL + kFloat16: {Float_t *val = (Float_t*)ladd; return T(val[k]);}
4183  case kOffsetL + kDouble: {Double_t *val = (Double_t*)ladd; return T(val[k]);}
4184  case kOffsetL + kDouble32:{Double_t *val = (Double_t*)ladd; return T(val[k]);}
4185  case kOffsetL + kUChar: {UChar_t *val = (UChar_t*)ladd; return T(val[k]);}
4186  case kOffsetL + kUShort: {UShort_t *val = (UShort_t*)ladd; return T(val[k]);}
4187  case kOffsetL + kUInt: {UInt_t *val = (UInt_t*)ladd; return T(val[k]);}
4188  case kOffsetL + kULong: {ULong_t *val = (ULong_t*)ladd; return T(val[k]);}
4189 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4190  case kOffsetL + kULong64: {Long64_t *val = (Long64_t*)ladd; return T(val[k]);}
4191 #else
4192  case kOffsetL + kULong64:{ULong64_t *val= (ULong64_t*)ladd; return T(val[k]);}
4193 #endif
4194 
4195 #define READ_ARRAY(TYPE_t) \
4196  { \
4197  Int_t sub_instance, index; \
4198  Int_t instance = k; \
4199  if (len) { \
4200  index = instance / len; \
4201  sub_instance = instance % len; \
4202  } else { \
4203  index = instance; \
4204  sub_instance = 0; \
4205  } \
4206  TYPE_t **val =(TYPE_t**)(ladd); \
4207  return T((val[sub_instance])[index]); \
4208  }
4209 
4210  // pointer to an array of basic types array[n]
4214  case kOffsetP + kInt_t: READ_ARRAY(Int_t)
4217  case kOffsetP + kFloat16_t:
4219  case kOffsetP + kDouble32_t:
4225 #if defined(_MSC_VER) && (_MSC_VER <= 1200)
4227 #else
4229 #endif
4230 
4231  // array counter //[n]
4232  case kCounter: {Int_t *val = (Int_t*)ladd; return T(*val);}
4233  }
4234  return 0;
4235 }
4236 
4237 
4238 
4239 template Double_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4240 template Long64_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4241 template LongDouble_t TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const;
4242 
4243 ////////////////////////////////////////////////////////////////////////////////
4244 /// Return value of element i in object at pointer.
4245 /// The function may be called in two ways:
4246 /// - method1 len < 0: i is assumed to be the TStreamerElement number i in StreamerInfo
4247 /// - method2 len >= 0: i is the type, address of variable is directly pointer.
4248 
4249 template <typename T>
4250 T TStreamerInfo::GetTypedValue(char *pointer, Int_t i, Int_t j, Int_t len) const
4251 {
4252  char *ladd;
4253  Int_t atype;
4254  if (len >= 0) {
4255  ladd = pointer;
4256  atype = i;
4257  } else {
4258  if (i < 0) return 0;
4259  ladd = pointer + fCompFull[i]->fOffset;
4260  atype = fCompFull[i]->fNewType;
4261  len = fCompFull[i]->fElem->GetArrayLength();
4262  if (atype == kSTL) {
4263  TClass *newClass = fCompFull[i]->fElem->GetNewClass();
4264  if (newClass == 0) {
4265  newClass = fCompFull[i]->fElem->GetClassPointer();
4266  }
4267  TClass *innerClass = newClass->GetCollectionProxy()->GetValueClass();
4268  if (innerClass) {
4269  return 0; // We don't know which member of the class we would want.
4270  } else {
4271  TVirtualCollectionProxy *proxy = newClass->GetCollectionProxy();
4272  // EDataType is a subset of TStreamerInfo::EReadWrite
4273  atype = (TStreamerInfo::EReadWrite)proxy->GetType();
4274  TVirtualCollectionProxy::TPushPop pop(proxy,ladd);
4275  Int_t nc = proxy->Size();
4276  if (j >= nc) return 0;
4277  char *element_ptr = (char*)proxy->At(j);
4278  return GetTypedValueAux<T>(atype,element_ptr,0,1);
4279  }
4280  }
4281  }
4282  return GetTypedValueAux<T>(atype,ladd,j,len);
4283 }
4284 
4285 ////////////////////////////////////////////////////////////////////////////////
4286 
4287 template Double_t TStreamerInfo::GetTypedValueClones<Double_t>(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4288 template Long64_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4289 template LongDouble_t TStreamerInfo::GetTypedValueClones(TClonesArray *clones, Int_t i, Int_t j, int k, Int_t eoffset) const;
4290 
4291 template <typename T>
4293 {
4294  // return value of element i in object number j in a TClonesArray and eventually
4295  // element k in a sub-array.
4296 
4297  Int_t nc = clones->GetEntriesFast();
4298  if (j >= nc) return 0;
4299 
4300  char *pointer = (char*)clones->UncheckedAt(j);
4301  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4302  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4303 }
4304 
4305 template Double_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4306 template Long64_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4307 template LongDouble_t TStreamerInfo::GetTypedValueSTL(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4308 
4309 ////////////////////////////////////////////////////////////////////////////////
4310 /// Return value of element i in object number j in a TClonesArray and eventually
4311 /// element k in a sub-array.
4312 
4313 template <typename T>
4315 {
4316  Int_t nc = cont->Size();
4317  if (j >= nc) return 0;
4318 
4319  char *pointer = (char*)cont->At(j);
4320  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4321  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4322 }
4323 
4324 template Double_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4325 template Long64_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4326 template LongDouble_t TStreamerInfo::GetTypedValueSTLP(TVirtualCollectionProxy *cont, Int_t i, Int_t j, int k, Int_t eoffset) const;
4327 
4328 ////////////////////////////////////////////////////////////////////////////////
4329 /// Return value of element i in object number j in a TClonesArray and eventually
4330 /// element k in a sub-array.
4331 
4332 template <typename T>
4334 {
4335  Int_t nc = cont->Size();
4336 
4337  if (j >= nc) return 0;
4338 
4339  char **ptr = (char**)cont->At(j);
4340  char *pointer = *ptr;
4341 
4342  char *ladd = pointer + eoffset + fCompFull[i]->fOffset;
4343  return GetTypedValueAux<T>(fCompFull[i]->fType,ladd,k,((TStreamerElement*)fCompFull[i]->fElem)->GetArrayLength());
4344 }
4345 
4346 ////////////////////////////////////////////////////////////////////////////////
4347 /// Insert new members as expressed in the array of TSchemaRule(s).
4348 
4349 void TStreamerInfo::InsertArtificialElements(std::vector<const ROOT::TSchemaRule*> &rules)
4350 {
4351  if (rules.empty()) return;
4352 
4353  TIter next(fElements);
4354  UInt_t count = 0;
4355 
4356  for(auto rule : rules) {
4357  if( rule->IsRenameRule() || rule->IsAliasRule() )
4358  continue;
4359  next.Reset();
4360  TStreamerElement *element;
4361  while ((element = (TStreamerElement*) next())) {
4362  if ( rule->HasTarget( element->GetName() ) ) {
4363 
4364  // Check whether this is an 'attribute' rule.
4365  if ( rule->GetAttributes()[0] != 0 ) {
4366  TString attr( rule->GetAttributes() );
4367  attr.ToLower();
4368  if (attr.Contains("owner")) {
4369  if (attr.Contains("notowner")) {
4371  } else {
4373  }
4374  }
4375 
4376  }
4377  break;
4378  }
4379  }
4380 
4381  // NOTE: Before adding the rule we should check that the source do
4382  // existing in this StreamerInfo.
4383  const TObjArray *sources = rule->GetSource();
4384  TIter input(sources);
4385  TObject *src;
4386  while((src = input())) {
4387  if ( !GetElements()->FindObject(src->GetName()) ) {
4388  // Missing source.
4389 #if 0 // Don't warn about not activating the rule. If don't warn the user can
4390  // have more flexibility in specifying when the rule applies and relying
4391  // on both the version number *and* the presence of the source members.
4392  // Activating this warning would for example mean that we need to carefully
4393  // tweak $ROOTSYS/etc/class.rules.
4394  TString ruleStr;
4395  rule->AsString(ruleStr);
4396  Warning("InsertArtificialElements","For class %s in StreamerInfo %d is missing the source data member %s when trying to apply the rule:\n %s",
4397  GetName(),GetClassVersion(),src->GetName(),ruleStr.Data());
4398  rule = 0;
4399 #endif
4400  break;
4401  }
4402  }
4403 
4404  if (!rule) continue;
4405 
4406  TStreamerArtificial *newel;
4407  typedef std::vector<TStreamerArtificial*> vec_t;
4408  vec_t toAdd;
4409 
4410  if (rule->GetTarget()==0) {
4411  TString newName;
4412  newName.Form("%s_rule%d",fClass->GetName(),count);
4413  newel = new TStreamerArtificial(newName,"",
4414  fClass->GetDataMemberOffset(newName),
4416  "void");
4418  newel->SetReadFunc( rule->GetReadFunctionPointer() );
4419  newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4420  toAdd.push_back(newel);
4421  } else {
4422  toAdd.reserve(rule->GetTarget()->GetEntries());
4423  TObjString * objstr = (TObjString*)(rule->GetTarget()->At(0));
4424  if (objstr) {
4425  TString newName = objstr->String();
4426  TString realDataName;
4427  if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4428  TRealData::GetName(realDataName,dm);
4429  newel = new TStreamerArtificial(realDataName,"",
4430  fClass->GetDataMemberOffset(newName),
4432  fClass->GetDataMember( newName )->GetTypeName());
4433  newel->SetReadFunc( rule->GetReadFunctionPointer() );
4434  newel->SetReadRawFunc( rule->GetReadRawFunctionPointer() );
4435  toAdd.push_back(newel);
4436  } else {
4437  // This would be a completely new member (so it would need to be cached)
4438  // TOBEDONE
4439  }
4440  for(Int_t other = 1; other < rule->GetTarget()->GetEntries(); ++other) {
4441  objstr = (TObjString*)(rule->GetTarget()->At(other));
4442  if (objstr) {
4443  newName = objstr->String();
4444  if ( TDataMember* dm = fClass->GetDataMember( newName ) ) {
4445  TRealData::GetName(realDataName,dm);
4446  newel = new TStreamerArtificial(realDataName,"",
4447  fClass->GetDataMemberOffset(newName),
4449  fClass->GetDataMember( newName )->GetTypeName());
4450  toAdd.push_back(newel);
4451  }
4452  }
4453  }
4454  } // For each target of the rule
4455  }
4456  // Now find we with need to add them
4457  TIter s_iter(rule->GetSource());
4458  Int_t loc = -1;
4459  while( TObjString *s = (TObjString*)s_iter() ) {
4460  for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4461  if (s->String() == fElements->UncheckedAt(i)->GetName()) {
4462  if (loc == -1 || (i+1)>loc) {
4463  loc = i+1;
4464  }
4465  }
4466  }
4467  }
4468  if (loc == -1) {
4469  // Verify if the last one is not 'skipped'.
4470  for(Int_t i = fElements->GetLast(); i >= 0 && (i+1) >= loc; --i) {
4471  if ( ((TStreamerElement*)fElements->UncheckedAt(i))->GetNewType() != -2 ) {
4472  break;
4473  }
4474  loc = i;
4475  }
4476  }
4477  if (loc == -1) {
4478  for(vec_t::iterator iter = toAdd.begin(); iter != toAdd.end(); ++iter) {
4479  fElements->Add(*iter);
4480  }
4481  } else {
4482  R__TObjArray_InsertAt(fElements, toAdd, loc);
4483  }
4484  } // None of the target of the rule are on file.
4485 }
4486 
4487 ////////////////////////////////////////////////////////////////////////////////
4488 /// List the TStreamerElement list and also the precomputed tables
4489 /// if option contains the string "incOrig", also prints the original
4490 /// (non-optimized elements in the list of compiled elements.
4491 
4492 void TStreamerInfo::ls(Option_t *option) const
4493 {
4494  if (fClass && (fName != fClass->GetName())) {
4495  if (fClass->IsVersioned()) {
4496  Printf("\nStreamerInfo for conversion to %s from: %s, version=%d, checksum=0x%x",fClass->GetName(),GetName(),fClassVersion,GetCheckSum());
4497  } else {
4498  Printf("\nStreamerInfo for conversion to %s from: %s, checksum=0x%x",fClass->GetName(),GetName(),GetCheckSum());
4499  }
4500  } else {
4501  if (!fClass || fClass->IsVersioned()) {
4502  Printf("\nStreamerInfo for class: %s, version=%d, checksum=0x%x",GetName(),fClassVersion,GetCheckSum());
4503  } else {
4504  Printf("\nStreamerInfo for class: %s, checksum=0x%x",GetName(),GetCheckSum());
4505  }
4506  }
4507 
4508  if (fElements) {
4509  TIter next(fElements);
4510  TObject *obj;
4511  while ((obj = next()))
4512  obj->ls(option);
4513  }
4514  if (strstr(option,"full") != 0) {
4515  for (Int_t i=0; i < fNfulldata; ++i) {
4516  TStreamerElement *element = (TStreamerElement*)fCompFull[i]->fElem;
4517  TString sequenceType;
4518  element->GetSequenceType(sequenceType);
4519  // by definition of the loop (i+1) <= fNdata
4520  if (sequenceType.Length()) {
4521  sequenceType.Prepend(" [");
4522  sequenceType += "]";
4523  }
4524  Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4525  i,element->GetName(),fCompFull[i]->fType,fCompFull[i]->fOffset,fCompFull[i]->fLength,fCompFull[i]->fMethod,
4526  sequenceType.Data());
4527  }
4528 
4529  } else {
4530  Bool_t wantOrig = strstr(option,"incOrig") != 0;
4531  Bool_t optimized = kFALSE;
4532  for (Int_t i=0,j=0;i < fNdata;++i,++j) {
4533  TStreamerElement *element = (TStreamerElement*)fCompOpt[i]->fElem;
4534  TString sequenceType;
4535  element->GetSequenceType(sequenceType);
4536  // by definition of the loop (i+1) <= fNdata
4538  if (optimized) {
4539  // This was optimized.
4540  if (sequenceType.Length() != 0) {
4541  sequenceType += ',';
4542  }
4543  sequenceType += "optimized";
4544  }
4545  if (sequenceType.Length()) {
4546  sequenceType.Prepend(" [");
4547  sequenceType += "]";
4548  }
4549  Printf(" i=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4550  i,element->GetName(),fCompOpt[i]->fType,fCompOpt[i]->fOffset,fCompOpt[i]->fLength,fCompOpt[i]->fMethod,
4551  sequenceType.Data());
4552  if (optimized && wantOrig) {
4553  Bool_t done;
4554  do {
4555  element = (TStreamerElement*)fCompFull[j]->fElem;
4556  element->GetSequenceType(sequenceType);
4557  if (sequenceType.Length()) {
4558  sequenceType.Prepend(" [");
4559  sequenceType += "]";
4560  }
4561  Printf(" j=%2d, %-15s type=%3d, offset=%3d, len=%d, method=%ld%s",
4562  j,element->GetName(),fCompFull[j]->fType,fCompFull[j]->fOffset,fCompFull[j]->fLength,fCompFull[j]->fMethod,
4563  sequenceType.Data());
4564  ++j;
4565  done = j >= fNfulldata || ( (i+1 < fNdata) && fCompOpt[i+1]->fElem == fCompFull[j+1]->fElem );
4566  } while (!done);
4567 
4568  }
4569  }
4570  }
4571 }
4572 
4573 ////////////////////////////////////////////////////////////////////////////////
4574 /// An emulated object is created at address obj, if obj is null we
4575 /// allocate memory for the object.
4576 
4577 void* TStreamerInfo::New(void *obj)
4578 {
4579  //???FIX ME: What about varying length array elements?
4580 
4581  char* p = (char*) obj;
4582 
4583  TIter next(fElements);
4584 
4585  if (!p) {
4586  // Allocate and initialize the memory block.
4587  p = new char[fSize];
4588  memset(p, 0, fSize);
4589  }
4590 
4591  next.Reset();
4592  TStreamerElement* element = (TStreamerElement*) next();
4593 
4594  for (; element; element = (TStreamerElement*) next()) {
4595 
4596  // Skip elements which have not been allocated memory.
4597  if (element->GetOffset() == kMissing) {
4598  continue;
4599  }
4600 
4601  // Skip elements for which we do not have any class
4602  // information. FIXME: Document how this could happen.
4603  TClass* cle = element->GetClassPointer();
4604  if (!cle) {
4605  continue;
4606  }
4607 
4608  char* eaddr = p + element->GetOffset();
4609  Int_t etype = element->GetType();
4610 
4611  //cle->GetStreamerInfo(); //necessary in case "->" is not specified
4612 
4613  switch (etype) {
4614 
4615  case kAnyP:
4616  case kObjectP:
4617  case kSTLp:
4618  {
4619  // Initialize array of pointers with null pointers.
4620  char** r = (char**) eaddr;
4621  Int_t len = element->GetArrayLength();
4622  for (Int_t i = 0; i < len; ++i) {
4623  r[i] = 0;
4624  }
4625  }
4626  break;
4627 
4628  case kObjectp:
4629  case kAnyp:
4630  {
4631  // If the option "->" is given in the data member comment field
4632  // it is assumed that the object exists before reading data in,
4633  // so we create an object.
4634  if (cle != TClonesArray::Class()) {
4635  void** r = (void**) eaddr;
4636  *r = cle->New();
4637  } else {
4638  // In the case of a TClonesArray, the class name of
4639  // the contained objects must be specified in the
4640  // data member comment in this format:
4641  // TClonesArray* myVar; //->(className)
4642  const char* title = element->GetTitle();
4643  const char* bracket1 = strrchr(title, '(');
4644  const char* bracket2 = strrchr(title, ')');
4645  if (bracket1 && bracket2 && (bracket2 != (bracket1 + 1))) {
4646  Int_t len = bracket2 - (bracket1 + 1);
4647  char* clonesClass = new char[len+1];
4648  clonesClass[0] = '\0';
4649  strncat(clonesClass, bracket1 + 1, len);
4650  void** r = (void**) eaddr;
4651  *r = (void*) new TClonesArray(clonesClass);
4652  delete[] clonesClass;
4653  } else {
4654  //Warning("New", "No class name found for TClonesArray initializer in data member comment (expected \"//->(className)\"");
4655  void** r = (void**) eaddr;
4656  *r = (void*) new TClonesArray();
4657  }
4658  }
4659  }
4660  break;
4661 
4662  case kBase:
4663  {
4664  if (cle->Property() & kIsAbstract) {
4666  if (einfo) einfo->New(eaddr);
4667  } else {
4668  cle->New(eaddr);
4669  }
4670  break;
4671  }
4672  case kObject:
4673  case kAny:
4674  case kTObject:
4675  case kTString:
4676  case kTNamed:
4677  {
4678  cle->New(eaddr);
4679  }
4680  break;
4681 
4682  case kSTL:
4683  {
4684  if (strcmp(element->GetName(),"This")==0 &&
4685  !cle->GetCollectionProxy()) {
4686  // missing information, avoid infinite loop
4687  // by doing nothing ....
4688  } else {
4689  cle->New(eaddr);
4690  }
4691  }
4692  break;
4693 
4694  case kObject + kOffsetL:
4695  case kAny + kOffsetL:
4696  case kTObject + kOffsetL:
4697  case kTString + kOffsetL:
4698  case kTNamed + kOffsetL:
4699  case kSTL + kOffsetL:
4700  {
4701  Int_t size = cle->Size();
4702  char* r = eaddr;
4703  Int_t len = element->GetArrayLength();
4704  for (Int_t i = 0; i < len; ++i, r += size) {
4705  cle->New(r);
4706  }
4707  }
4708  break;
4709 
4710  } // switch etype
4711  } // for TIter next(fElements)
4712 
4713  for(int nbase = 0; nbase < fNVirtualInfoLoc; ++nbase) {
4714  *(TStreamerInfo**)(p + fVirtualInfoLoc[nbase]) = this;
4715  }
4716  ++fLiveCount;
4717  return p;
4718 }
4719 
4720 ////////////////////////////////////////////////////////////////////////////////
4721 /// An array of emulated objects is created at address ary, if ary is null,
4722 /// we allocate memory for the array.
4723 
4724 void* TStreamerInfo::NewArray(Long_t nElements, void *ary)
4725 {
4726  if (fClass == 0) {
4727  Error("NewArray", "TClass pointer is null!");
4728  return 0;
4729  }
4730 
4731  Int_t size = fClass->Size();
4732 
4733  char* p = (char*) ary;
4734 
4735  if (!p) {
4736  Long_t len = nElements * size + sizeof(Long_t)*2;
4737  p = new char[len];
4738  memset(p, 0, len);
4739  }
4740 
4741  // Store the array cookie
4742  Long_t* r = (Long_t*) p;
4743  r[0] = size;
4744  r[1] = nElements;
4745  char* dataBegin = (char*) &r[2];
4746 
4747  // Do a placement new for each element.
4748  p = dataBegin;
4749  for (Long_t cnt = 0; cnt < nElements; ++cnt) {
4750  New(p);
4751  p += size;
4752  } // for nElements
4753 
4754  return dataBegin;
4755 }
4756 
4757 
4758 #define DeleteBasicPointer(addr,element,name) \
4759  { \
4760  name **f = (name**)(addr); \
4761  int n = element->GetArrayLength() ? element->GetArrayLength() : 1;\
4762  for(int j=0;j<n;j++) { \
4763  delete [] f[j]; \
4764  f[j] = 0; \
4765  } \
4766  }
4767 
4768 ////////////////////////////////////////////////////////////////////////////////
4769 /// Internal part of the destructor.
4770 /// Destruct each of the datamembers in the same order
4771 /// as the implicit destructor would.
4772 
4773 void TStreamerInfo::DestructorImpl(void* obj, Bool_t dtorOnly)
4774 {
4775  R__ASSERT(obj != 0);
4776 
4777  char *p = (char*)obj;
4778 
4779  Int_t nelements = fElements->GetEntriesFast();
4780  //for (; ele; ele = (TStreamerElement*) next())
4781  for (Int_t elenum = nelements - 1; elenum >= 0; --elenum) {
4783  if (ele->GetOffset() == kMissing) continue;
4784  char* eaddr = p + ele->GetOffset();
4785 
4786 
4787  Int_t etype = ele->GetType();
4788 
4789  switch(etype) {
4805  case TStreamerInfo::kCharStar: DeleteBasicPointer(eaddr,ele,Char_t); continue;
4806  }
4807 
4808 
4809 
4810  TClass* cle = ele->GetClassPointer();
4811  if (!cle) continue;
4812 
4813 
4814  if (etype == kObjectp || etype == kAnyp) {
4815  // Destroy an array of pre-allocated objects.
4816  Int_t len = ele->GetArrayLength();
4817  if (!len) {
4818  len = 1;
4819  }
4820  void** r = (void**) eaddr;
4821  for (Int_t j = len - 1; j >= 0; --j) {
4822  if (r[j]) {
4823  cle->Destructor(r[j]);
4824  r[j] = 0;
4825  }
4826  }
4827  }
4828 
4829  if ((etype == kObjectP || etype == kAnyP || etype == kSTLp) && !ele->TestBit(TStreamerElement::kDoNotDelete)) {
4830  // Destroy an array of pointers to not-pre-allocated objects.
4831  Int_t len = ele->GetArrayLength();
4832  if (!len) {
4833  len = 1;
4834  }
4835  void** r = (void**) eaddr;
4836  for (Int_t j = len - 1; j >= 0; --j) {
4837  if (r[j]) {
4838&#