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