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