Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TBufferXML.cxx
Go to the documentation of this file.
1 // @(#)root/:$Id: 5400e36954e1dc109fcfc306242c30234beb7312 $
2 // Author: Sergey Linev, Rene Brun 10.05.2004
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, 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 TBufferXML
14 \ingroup IO
15 
16 Class for serializing/deserializing object to/from xml.
17 
18 The simple way to create XML representation is:
19 ~~~{.cpp}
20  TNamed *obj = new TNamed("name", "title");
21  TString xml = TBufferXML::ToXML(obj);
22 ~~~
23 Produced xml can be decoded into new object:
24 ~~~{.cpp}
25  TNamed *obj2 = nullptr;
26  TBufferXML::FromXML(obj2, xml);
27 ~~~
28 
29 TBufferXML class uses streaming mechanism, provided by ROOT system,
30 therefore most of ROOT and user classes can be stored to xml.
31 There are limitations for complex objects like TTree, which can not be converted to xml.
32 */
33 
34 #include "TBufferXML.h"
35 
36 #include "Compression.h"
37 #include "TXMLFile.h"
38 #include "TObjArray.h"
39 #include "TROOT.h"
40 #include "TError.h"
41 #include "TClass.h"
42 #include "TClassTable.h"
43 #include "TDataType.h"
44 #include "TExMap.h"
45 #include "TStreamerInfo.h"
46 #include "TStreamerElement.h"
47 #include "TMemberStreamer.h"
48 #include "TStreamer.h"
49 #include "RZip.h"
50 #include "ROOT/RMakeUnique.hxx"
51 
52 ClassImp(TBufferXML);
53 
54 ////////////////////////////////////////////////////////////////////////////////
55 /// Creates buffer object to serialize/deserialize data to/from xml.
56 /// Mode should be either TBuffer::kRead or TBuffer::kWrite.
57 
58 TBufferXML::TBufferXML(TBuffer::EMode mode) : TBufferText(mode)
59 {
60 }
61 
62 ////////////////////////////////////////////////////////////////////////////////
63 /// Creates buffer object to serialize/deserialize data to/from xml.
64 /// This constructor should be used, if data from buffer supposed to be stored in file.
65 /// Mode should be either TBuffer::kRead or TBuffer::kWrite.
66 
67 TBufferXML::TBufferXML(TBuffer::EMode mode, TXMLFile *file)
68  : TBufferText(mode, file), TXMLSetup(*file)
69 {
70  // this is for the case when StreamerInfo reads elements from
71  // buffer as ReadFastArray. When it checks if size of buffer is
72  // too small and skip reading. Actually, more improved method should
73  // be used here.
74 
75  if (XmlFile()) {
76  SetXML(XmlFile()->XML());
77  SetCompressionSettings(XmlFile()->GetCompressionSettings());
78  SetIOVersion(XmlFile()->GetIOVersion());
79  }
80 }
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 /// Destroy xml buffer.
84 
85 TBufferXML::~TBufferXML()
86 {
87 }
88 
89 ////////////////////////////////////////////////////////////////////////////////
90 /// Returns pointer to TXMLFile object.
91 /// Access to file is necessary to produce unique identifier for object references.
92 
93 TXMLFile *TBufferXML::XmlFile()
94 {
95  return dynamic_cast<TXMLFile *>(GetParent());
96 }
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 /// Converts object, inherited from TObject class, to XML string
100 /// GenericLayout defines layout choice for XML file
101 /// UseNamespaces allow XML namespaces.
102 /// See TXMLSetup class for details
103 
104 TString TBufferXML::ConvertToXML(const TObject *obj, Bool_t GenericLayout, Bool_t UseNamespaces)
105 {
106  TClass *clActual = nullptr;
107  void *ptr = (void *)obj;
108 
109  if (obj) {
110  clActual = TObject::Class()->GetActualClass(obj);
111  if (!clActual)
112  clActual = TObject::Class();
113  else if (clActual != TObject::Class())
114  ptr = (void *)((Long_t)obj - clActual->GetBaseClassOffset(TObject::Class()));
115  }
116 
117  return ConvertToXML(ptr, clActual, GenericLayout, UseNamespaces);
118 }
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 /// Converts any type of object to XML string.
122 /// GenericLayout defines layout choice for XML file
123 /// UseNamespaces allow XML namespaces.
124 /// See TXMLSetup class for details
125 
126 TString TBufferXML::ConvertToXML(const void *obj, const TClass *cl, Bool_t GenericLayout, Bool_t UseNamespaces)
127 {
128  TXMLEngine xml;
129 
130  TBufferXML buf(TBuffer::kWrite);
131  buf.SetXML(&xml);
132  buf.InitMap();
133 
134  buf.SetXmlLayout(GenericLayout ? TXMLSetup::kGeneralized : TXMLSetup::kSpecialized);
135  buf.SetUseNamespaces(UseNamespaces);
136 
137  XMLNodePointer_t xmlnode = buf.XmlWriteAny(obj, cl);
138 
139  TString res;
140 
141  xml.SaveSingleNode(xmlnode, &res);
142 
143  xml.FreeNode(xmlnode);
144 
145  return res;
146 }
147 
148 ////////////////////////////////////////////////////////////////////////////////
149 /// Read object from XML, produced by ConvertToXML() method.
150 /// If object does not inherit from TObject class, return 0.
151 /// GenericLayout and UseNamespaces should be the same as in ConvertToXML()
152 
153 TObject *TBufferXML::ConvertFromXML(const char *str, Bool_t GenericLayout, Bool_t UseNamespaces)
154 {
155  TClass *cl = nullptr;
156  void *obj = ConvertFromXMLAny(str, &cl, GenericLayout, UseNamespaces);
157 
158  if (!cl || !obj)
159  return nullptr;
160 
161  Int_t delta = cl->GetBaseClassOffset(TObject::Class());
162 
163  if (delta < 0) {
164  cl->Destructor(obj);
165  return nullptr;
166  }
167 
168  return (TObject *)(((char *)obj) + delta);
169 }
170 
171 ////////////////////////////////////////////////////////////////////////////////
172 /// Read object of any class from XML, produced by ConvertToXML() method.
173 /// If cl!=0, return actual class of object.
174 /// GenericLayout and UseNamespaces should be the same as in ConvertToXML()
175 
176 void *TBufferXML::ConvertFromXMLAny(const char *str, TClass **cl, Bool_t GenericLayout, Bool_t UseNamespaces)
177 {
178  TXMLEngine xml;
179  TBufferXML buf(TBuffer::kRead);
180 
181  buf.SetXML(&xml);
182  buf.InitMap();
183 
184  buf.SetXmlLayout(GenericLayout ? TXMLSetup::kGeneralized : TXMLSetup::kSpecialized);
185  buf.SetUseNamespaces(UseNamespaces);
186 
187  XMLNodePointer_t xmlnode = xml.ReadSingleNode(str);
188 
189  void *obj = buf.XmlReadAny(xmlnode, nullptr, cl);
190 
191  xml.FreeNode(xmlnode);
192 
193  return obj;
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 /// Convert from XML and check if object derived from specified class
198 /// When possible, cast to given class
199 
200 void *TBufferXML::ConvertFromXMLChecked(const char *xml, const TClass *expectedClass, Bool_t GenericLayout,
201  Bool_t UseNamespaces)
202 {
203  TClass *objClass = nullptr;
204  void *res = ConvertFromXMLAny(xml, &objClass, GenericLayout, UseNamespaces);
205 
206  if (!res || !objClass)
207  return nullptr;
208 
209  if (objClass == expectedClass)
210  return res;
211 
212  Int_t offset = objClass->GetBaseClassOffset(expectedClass);
213  if (offset < 0) {
214  ::Error("TBufferXML::ConvertFromXMLChecked", "expected class %s is not base for read class %s",
215  expectedClass->GetName(), objClass->GetName());
216  objClass->Destructor(res);
217  return nullptr;
218  }
219 
220  return (char *)res - offset;
221 }
222 
223 ////////////////////////////////////////////////////////////////////////////////
224 /// Convert object of any class to xml structures
225 /// Return pointer on top xml element
226 
227 XMLNodePointer_t TBufferXML::XmlWriteAny(const void *obj, const TClass *cl)
228 {
229  fErrorFlag = 0;
230 
231  if (!fXML)
232  return nullptr;
233 
234  XMLNodePointer_t res = XmlWriteObject(obj, cl, kTRUE);
235 
236  return res;
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 /// Recreate object from xml structure.
241 /// Return pointer to read object.
242 /// if (cl!=0) returns pointer to class of object
243 
244 void *TBufferXML::XmlReadAny(XMLNodePointer_t node, void *obj, TClass **cl)
245 {
246  if (!node)
247  return nullptr;
248 
249  if (cl)
250  *cl = nullptr;
251 
252  fErrorFlag = 0;
253 
254  if (!fXML)
255  return nullptr;
256 
257  PushStack(node, kTRUE);
258 
259  void *res = XmlReadObject(obj, cl);
260 
261  PopStack();
262 
263  return res;
264 }
265 
266 // TXMLStackObj is used to keep stack of object hierarchy,
267 // stored in TBuffer. For example, data for parent class(es)
268 // stored in subnodes, but initial object node will be kept.
269 
270 class TXMLStackObj {
271 public:
272  TXMLStackObj(XMLNodePointer_t node) : fNode(node)
273  {
274  }
275 
276  ~TXMLStackObj()
277  {
278  if (fIsElemOwner)
279  delete fElem;
280  }
281 
282  Bool_t IsStreamerInfo() const { return fIsStreamerInfo; }
283 
284  XMLNodePointer_t fNode{nullptr};
285  TStreamerInfo *fInfo{nullptr};
286  TStreamerElement *fElem{nullptr};
287  Int_t fElemNumber{0};
288  Bool_t fCompressedClassNode{kFALSE};
289  XMLNsPointer_t fClassNs{nullptr};
290  Bool_t fIsStreamerInfo{kFALSE};
291  Bool_t fIsElemOwner{kFALSE};
292 };
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 /// Add new level to xml stack.
296 
297 TXMLStackObj *TBufferXML::PushStack(XMLNodePointer_t current, Bool_t simple)
298 {
299  if (IsReading() && !simple) {
300  current = fXML->GetChild(current);
301  fXML->SkipEmpty(current);
302  }
303 
304  fStack.emplace_back(std::make_unique<TXMLStackObj>(current));
305  return fStack.back().get();
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Remove one level from xml stack.
310 
311 TXMLStackObj *TBufferXML::PopStack()
312 {
313  if (fStack.size() > 0)
314  fStack.pop_back();
315  return fStack.size() > 0 ? fStack.back().get() : nullptr;
316 }
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 /// Return pointer on current xml node.
320 
321 XMLNodePointer_t TBufferXML::StackNode()
322 {
323  TXMLStackObj *stack = Stack();
324  return stack ? stack->fNode : nullptr;
325 }
326 
327 ////////////////////////////////////////////////////////////////////////////////
328 /// Shift stack node to next.
329 
330 void TBufferXML::ShiftStack(const char *errinfo)
331 {
332  TXMLStackObj *stack = Stack();
333  if (stack) {
334  fXML->ShiftToNext(stack->fNode);
335  if (gDebug > 4)
336  Info("ShiftStack", "%s to node %s", errinfo, fXML->GetNodeName(stack->fNode));
337  }
338 }
339 
340 ////////////////////////////////////////////////////////////////////////////////
341 /// See comments for function SetCompressionSettings.
342 
343 void TBufferXML::SetCompressionAlgorithm(Int_t algorithm)
344 {
345  if (algorithm < 0 || algorithm >= ROOT::RCompressionSetting::EAlgorithm::kUndefined)
346  algorithm = 0;
347  if (fCompressLevel < 0) {
348  fCompressLevel = 100 * algorithm + ROOT::RCompressionSetting::ELevel::kUseMin;
349  } else {
350  int level = fCompressLevel % 100;
351  fCompressLevel = 100 * algorithm + level;
352  }
353 }
354 
355 ////////////////////////////////////////////////////////////////////////////////
356 /// See comments for function SetCompressionSettings.
357 
358 void TBufferXML::SetCompressionLevel(Int_t level)
359 {
360  if (level < 0)
361  level = 0;
362  if (level > 99)
363  level = 99;
364  if (fCompressLevel < 0) {
365  // if the algorithm is not defined yet use 0 as a default
366  fCompressLevel = level;
367  } else {
368  int algorithm = fCompressLevel / 100;
369  if (algorithm >= ROOT::RCompressionSetting::EAlgorithm::kUndefined)
370  algorithm = 0;
371  fCompressLevel = 100 * algorithm + level;
372  }
373 }
374 
375 ////////////////////////////////////////////////////////////////////////////////
376 /// Used to specify the compression level and algorithm.
377 ///
378 /// See TFile constructor for the details.
379 
380 void TBufferXML::SetCompressionSettings(Int_t settings)
381 {
382  fCompressLevel = settings;
383 }
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 /// Write binary data block from buffer to xml.
387 /// This data can be produced only by direct call of TBuffer::WriteBuf() functions.
388 
389 void TBufferXML::XmlWriteBlock(XMLNodePointer_t node)
390 {
391  if (!node || (Length() == 0))
392  return;
393 
394  const char *src = Buffer();
395  int srcSize = Length();
396 
397  char *fZipBuffer = 0;
398 
399  Int_t compressionLevel = GetCompressionLevel();
400  ROOT::RCompressionSetting::EAlgorithm::EValues compressionAlgorithm =
401  static_cast<ROOT::RCompressionSetting::EAlgorithm::EValues>(GetCompressionAlgorithm());
402 
403  if ((Length() > 512) && (compressionLevel > 0)) {
404  int zipBufferSize = Length();
405  fZipBuffer = new char[zipBufferSize + 9];
406  int dataSize = Length();
407  int compressedSize = 0;
408  R__zipMultipleAlgorithm(compressionLevel, &dataSize, Buffer(), &zipBufferSize, fZipBuffer, &compressedSize,
409  compressionAlgorithm);
410  if (compressedSize > 0) {
411  src = fZipBuffer;
412  srcSize = compressedSize;
413  } else {
414  delete[] fZipBuffer;
415  fZipBuffer = nullptr;
416  }
417  }
418 
419  TString res;
420  char sbuf[500];
421  int block = 0;
422  char *tgt = sbuf;
423  int srcCnt = 0;
424 
425  while (srcCnt++ < srcSize) {
426  tgt += sprintf(tgt, " %02x", (unsigned char)*src);
427  src++;
428  if (block++ == 100) {
429  res += sbuf;
430  block = 0;
431  tgt = sbuf;
432  }
433  }
434 
435  if (block > 0)
436  res += sbuf;
437 
438  XMLNodePointer_t blocknode = fXML->NewChild(node, nullptr, xmlio::XmlBlock, res);
439  fXML->NewIntAttr(blocknode, xmlio::Size, Length());
440 
441  if (fZipBuffer) {
442  fXML->NewIntAttr(blocknode, xmlio::Zip, srcSize);
443  delete[] fZipBuffer;
444  }
445 }
446 
447 ////////////////////////////////////////////////////////////////////////////////
448 /// Read binary block of data from xml.
449 
450 void TBufferXML::XmlReadBlock(XMLNodePointer_t blocknode)
451 {
452  if (!blocknode)
453  return;
454 
455  Int_t blockSize = fXML->GetIntAttr(blocknode, xmlio::Size);
456  Bool_t blockCompressed = fXML->HasAttr(blocknode, xmlio::Zip);
457  char *fUnzipBuffer = nullptr;
458 
459  if (gDebug > 2)
460  Info("XmlReadBlock", "Block size = %d, Length = %d, Compressed = %d", blockSize, Length(), blockCompressed);
461 
462  if (blockSize > BufferSize())
463  Expand(blockSize);
464 
465  char *tgt = Buffer();
466  Int_t readSize = blockSize;
467 
468  TString content = fXML->GetNodeContent(blocknode);
469 
470  if (blockCompressed) {
471  Int_t zipSize = fXML->GetIntAttr(blocknode, xmlio::Zip);
472  fUnzipBuffer = new char[zipSize];
473 
474  tgt = fUnzipBuffer;
475  readSize = zipSize;
476  }
477 
478  char *ptr = (char *)content.Data();
479 
480  if (gDebug > 3)
481  Info("XmlReadBlock", "Content %s", ptr);
482 
483  for (int i = 0; i < readSize; i++) {
484  while ((*ptr < 48) || ((*ptr > 57) && (*ptr < 97)) || (*ptr > 102))
485  ptr++;
486 
487  int b_hi = (*ptr > 57) ? *ptr - 87 : *ptr - 48;
488  ptr++;
489  int b_lo = (*ptr > 57) ? *ptr - 87 : *ptr - 48;
490  ptr++;
491 
492  *tgt = b_hi * 16 + b_lo;
493  tgt++;
494 
495  if (gDebug > 4)
496  Info("XmlReadBlock", " Buf[%d] = %d", i, b_hi * 16 + b_lo);
497  }
498 
499  if (fUnzipBuffer) {
500 
501  int srcsize(0), tgtsize(0), unzipRes(0);
502  int status = R__unzip_header(&srcsize, (UChar_t *)fUnzipBuffer, &tgtsize);
503 
504  if (status == 0)
505  R__unzip(&readSize, (unsigned char *)fUnzipBuffer, &blockSize, (unsigned char *)Buffer(), &unzipRes);
506 
507  if (status != 0 || unzipRes != blockSize)
508  Error("XmlReadBlock", "Decompression error %d", unzipRes);
509  else if (gDebug > 2)
510  Info("XmlReadBlock", "Unzip ok");
511 
512  delete[] fUnzipBuffer;
513  }
514 }
515 
516 ////////////////////////////////////////////////////////////////////////////////
517 /// Add "ptr" attribute to node, if ptr is null or
518 /// if ptr is pointer on object, which is already saved in buffer
519 /// Automatically add "ref" attribute to node, where referenced object is stored
520 
521 Bool_t TBufferXML::ProcessPointer(const void *ptr, XMLNodePointer_t node)
522 {
523  if (!node)
524  return kFALSE;
525 
526  TString refvalue;
527 
528  if (!ptr) {
529  refvalue = xmlio::Null; // null
530  } else {
531  XMLNodePointer_t refnode = (XMLNodePointer_t)(Long_t)GetObjectTag(ptr);
532  if (!refnode)
533  return kFALSE;
534 
535  if (fXML->HasAttr(refnode, xmlio::Ref)) {
536  refvalue = fXML->GetAttr(refnode, xmlio::Ref);
537  } else {
538  refvalue = xmlio::IdBase;
539  if (XmlFile())
540  refvalue += XmlFile()->GetNextRefCounter();
541  else
542  refvalue += GetNextRefCounter();
543  fXML->NewAttr(refnode, nullptr, xmlio::Ref, refvalue.Data());
544  }
545  }
546  if (refvalue.Length() > 0) {
547  fXML->NewAttr(node, nullptr, xmlio::Ptr, refvalue.Data());
548  return kTRUE;
549  }
550 
551  return kFALSE;
552 }
553 
554 ////////////////////////////////////////////////////////////////////////////////
555 /// Searches for "ptr" attribute and returns pointer to object and class,
556 /// if "ptr" attribute reference to read object
557 
558 Bool_t TBufferXML::ExtractPointer(XMLNodePointer_t node, void *&ptr, TClass *&cl)
559 {
560  cl = nullptr;
561 
562  if (!fXML->HasAttr(node, xmlio::Ptr))
563  return kFALSE;
564 
565  const char *ptrid = fXML->GetAttr(node, xmlio::Ptr);
566 
567  if (!ptrid)
568  return kFALSE;
569 
570  // null
571  if (strcmp(ptrid, xmlio::Null) == 0) {
572  ptr = nullptr;
573  return kTRUE;
574  }
575 
576  if (strncmp(ptrid, xmlio::IdBase, strlen(xmlio::IdBase)) != 0) {
577  Error("ExtractPointer", "Pointer tag %s not started from %s", ptrid, xmlio::IdBase);
578  return kFALSE;
579  }
580 
581  Int_t id = TString(ptrid + strlen(xmlio::IdBase)).Atoi();
582 
583  GetMappedObject(id + 1, ptr, cl);
584 
585  if (!ptr || !cl)
586  Error("ExtractPointer", "not found ptr %s result %p %s", ptrid, ptr, (cl ? cl->GetName() : "null"));
587 
588  return ptr && cl;
589 }
590 
591 ////////////////////////////////////////////////////////////////////////////////
592 /// Analyze if node has "ref" attribute and register it to object map
593 
594 void TBufferXML::ExtractReference(XMLNodePointer_t node, const void *ptr, const TClass *cl)
595 {
596  if (!node || !ptr)
597  return;
598 
599  const char *refid = fXML->GetAttr(node, xmlio::Ref);
600 
601  if (!refid)
602  return;
603 
604  if (strncmp(refid, xmlio::IdBase, strlen(xmlio::IdBase)) != 0) {
605  Error("ExtractReference", "Reference tag %s not started from %s", refid, xmlio::IdBase);
606  return;
607  }
608 
609  Int_t id = TString(refid + strlen(xmlio::IdBase)).Atoi();
610 
611  MapObject(ptr, cl, id + 1);
612 
613  if (gDebug > 2)
614  Info("ExtractReference", "Find reference %s for object %p class %s", refid, ptr, (cl ? cl->GetName() : "null"));
615 }
616 
617 ////////////////////////////////////////////////////////////////////////////////
618 /// Check if node has specified name
619 
620 Bool_t TBufferXML::VerifyNode(XMLNodePointer_t node, const char *name, const char *errinfo)
621 {
622  if (!name || !node)
623  return kFALSE;
624 
625  if (strcmp(fXML->GetNodeName(node), name) != 0) {
626  if (errinfo) {
627  Error("VerifyNode", "Reading XML file (%s). Get: %s, expects: %s", errinfo, fXML->GetNodeName(node), name);
628  fErrorFlag = 1;
629  }
630  return kFALSE;
631  }
632  return kTRUE;
633 }
634 
635 ////////////////////////////////////////////////////////////////////////////////
636 /// Check, if stack node has specified name
637 
638 Bool_t TBufferXML::VerifyStackNode(const char *name, const char *errinfo)
639 {
640  return VerifyNode(StackNode(), name, errinfo);
641 }
642 
643 ////////////////////////////////////////////////////////////////////////////////
644 /// Checks, that attribute of specified name exists and has specified value
645 
646 Bool_t TBufferXML::VerifyAttr(XMLNodePointer_t node, const char *name, const char *value, const char *errinfo)
647 {
648  if (!node || !name || !value)
649  return kFALSE;
650 
651  const char *cont = fXML->GetAttr(node, name);
652  if ((!cont || (strcmp(cont, value) != 0))) {
653  if (errinfo) {
654  Error("VerifyAttr", "%s : attr %s = %s, expected: %s", errinfo, name, cont, value);
655  fErrorFlag = 1;
656  }
657  return kFALSE;
658  }
659  return kTRUE;
660 }
661 
662 ////////////////////////////////////////////////////////////////////////////////
663 /// Checks stack attribute
664 
665 Bool_t TBufferXML::VerifyStackAttr(const char *name, const char *value, const char *errinfo)
666 {
667  return VerifyAttr(StackNode(), name, value, errinfo);
668 }
669 
670 ////////////////////////////////////////////////////////////////////////////////
671 /// Create item node of specified name
672 
673 XMLNodePointer_t TBufferXML::CreateItemNode(const char *name)
674 {
675  XMLNodePointer_t node = nullptr;
676  if (GetXmlLayout() == kGeneralized) {
677  node = fXML->NewChild(StackNode(), nullptr, xmlio::Item);
678  fXML->NewAttr(node, nullptr, xmlio::Name, name);
679  } else
680  node = fXML->NewChild(StackNode(), nullptr, name);
681  return node;
682 }
683 
684 ////////////////////////////////////////////////////////////////////////////////
685 /// Checks, if stack node is item and has specified name
686 
687 Bool_t TBufferXML::VerifyItemNode(const char *name, const char *errinfo)
688 {
689  Bool_t res = kTRUE;
690  if (GetXmlLayout() == kGeneralized)
691  res = VerifyStackNode(xmlio::Item, errinfo) && VerifyStackAttr(xmlio::Name, name, errinfo);
692  else
693  res = VerifyStackNode(name, errinfo);
694  return res;
695 }
696 
697 ////////////////////////////////////////////////////////////////////////////////
698 /// Create xml node correspondent to TStreamerElement object
699 
700 void TBufferXML::CreateElemNode(const TStreamerElement *elem)
701 {
702  XMLNodePointer_t elemnode = nullptr;
703 
704  const char *elemxmlname = XmlGetElementName(elem);
705 
706  if (GetXmlLayout() == kGeneralized) {
707  elemnode = fXML->NewChild(StackNode(), nullptr, xmlio::Member);
708  fXML->NewAttr(elemnode, nullptr, xmlio::Name, elemxmlname);
709  } else {
710  // take namesapce for element only if it is not a base class or class name
711  XMLNsPointer_t ns = Stack()->fClassNs;
712  if ((elem->GetType() == TStreamerInfo::kBase) ||
713  ((elem->GetType() == TStreamerInfo::kTNamed) && !strcmp(elem->GetName(), TNamed::Class()->GetName())) ||
714  ((elem->GetType() == TStreamerInfo::kTObject) && !strcmp(elem->GetName(), TObject::Class()->GetName())) ||
715  ((elem->GetType() == TStreamerInfo::kTString) && !strcmp(elem->GetName(), TString::Class()->GetName())))
716  ns = nullptr;
717 
718  elemnode = fXML->NewChild(StackNode(), ns, elemxmlname);
719  }
720 
721  TXMLStackObj *curr = PushStack(elemnode);
722  curr->fElem = (TStreamerElement *)elem;
723 }
724 
725 ////////////////////////////////////////////////////////////////////////////////
726 /// Checks if stack node correspond to TStreamerElement object
727 
728 Bool_t TBufferXML::VerifyElemNode(const TStreamerElement *elem)
729 {
730  const char *elemxmlname = XmlGetElementName(elem);
731 
732  if (GetXmlLayout() == kGeneralized) {
733  if (!VerifyStackNode(xmlio::Member))
734  return kFALSE;
735  if (!VerifyStackAttr(xmlio::Name, elemxmlname))
736  return kFALSE;
737  } else {
738  if (!VerifyStackNode(elemxmlname))
739  return kFALSE;
740  }
741 
742  PerformPreProcessing(elem, StackNode());
743 
744  TXMLStackObj *curr = PushStack(StackNode()); // set pointer to first data inside element
745  curr->fElem = (TStreamerElement *)elem;
746  return kTRUE;
747 }
748 
749 ////////////////////////////////////////////////////////////////////////////////
750 /// Write object to buffer
751 /// If object was written before, only pointer will be stored
752 /// Return pointer to top xml node, representing object
753 
754 XMLNodePointer_t TBufferXML::XmlWriteObject(const void *obj, const TClass *cl, Bool_t cacheReuse)
755 {
756  XMLNodePointer_t objnode = fXML->NewChild(StackNode(), nullptr, xmlio::Object);
757 
758  if (!cl)
759  obj = nullptr;
760 
761  if (ProcessPointer(obj, objnode))
762  return objnode;
763 
764  TString clname = XmlConvertClassName(cl->GetName());
765 
766  fXML->NewAttr(objnode, nullptr, xmlio::ObjClass, clname);
767 
768  if (cacheReuse)
769  fMap->Add(Void_Hash(obj), (Long_t)obj, (Long_t)objnode);
770 
771  PushStack(objnode);
772 
773  ((TClass *)cl)->Streamer((void *)obj, *this);
774 
775  PopStack();
776 
777  if (gDebug > 1)
778  Info("XmlWriteObject", "Done write for class: %s", cl ? cl->GetName() : "null");
779 
780  return objnode;
781 }
782 
783 ////////////////////////////////////////////////////////////////////////////////
784 /// Read object from the buffer
785 
786 void *TBufferXML::XmlReadObject(void *obj, TClass **cl)
787 {
788  if (cl)
789  *cl = nullptr;
790 
791  XMLNodePointer_t objnode = StackNode();
792 
793  if (fErrorFlag > 0)
794  return obj;
795 
796  if (!objnode)
797  return obj;
798 
799  if (!VerifyNode(objnode, xmlio::Object, "XmlReadObjectNew"))
800  return obj;
801 
802  TClass *objClass = nullptr;
803 
804  if (ExtractPointer(objnode, obj, objClass)) {
805  ShiftStack("readobjptr");
806  if (cl)
807  *cl = objClass;
808  return obj;
809  }
810 
811  TString clname = fXML->GetAttr(objnode, xmlio::ObjClass);
812  objClass = XmlDefineClass(clname);
813  if (objClass == TDirectory::Class())
814  objClass = TDirectoryFile::Class();
815 
816  if (!objClass) {
817  Error("XmlReadObject", "Cannot find class %s", clname.Data());
818  ShiftStack("readobjerr");
819  return obj;
820  }
821 
822  if (gDebug > 1)
823  Info("XmlReadObject", "Reading object of class %s", clname.Data());
824 
825  if (!obj)
826  obj = objClass->New();
827 
828  ExtractReference(objnode, obj, objClass);
829 
830  PushStack(objnode);
831 
832  objClass->Streamer((void *)obj, *this);
833 
834  PopStack();
835 
836  ShiftStack("readobj");
837 
838  if (gDebug > 1)
839  Info("XmlReadObject", "Reading object of class %s done", clname.Data());
840 
841  if (cl)
842  *cl = objClass;
843 
844  return obj;
845 }
846 
847 ////////////////////////////////////////////////////////////////////////////////
848 /// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
849 /// and indent new level in xml structure.
850 /// This call indicates, that TStreamerInfo functions starts streaming
851 /// object data of correspondent class
852 
853 void TBufferXML::IncrementLevel(TVirtualStreamerInfo *info)
854 {
855  WorkWithClass((TStreamerInfo *)info);
856 }
857 
858 ////////////////////////////////////////////////////////////////////////////////
859 /// Prepares buffer to stream data of specified class.
860 
861 void TBufferXML::WorkWithClass(TStreamerInfo *sinfo, const TClass *cl)
862 {
863  fCanUseCompact = kFALSE;
864 
865  if (sinfo)
866  cl = sinfo->GetClass();
867 
868  if (!cl)
869  return;
870 
871  TString clname = XmlConvertClassName(cl->GetName());
872 
873  if (gDebug > 2)
874  Info("IncrementLevel", "Class: %s", clname.Data());
875 
876  Bool_t compressClassNode = (fExpectedBaseClass == cl);
877  fExpectedBaseClass = nullptr;
878 
879  TXMLStackObj *stack = Stack();
880 
881  if (IsWriting()) {
882 
883  XMLNodePointer_t classnode = nullptr;
884  if (compressClassNode) {
885  classnode = StackNode();
886  } else {
887  if (GetXmlLayout() == kGeneralized) {
888  classnode = fXML->NewChild(StackNode(), nullptr, xmlio::Class);
889  fXML->NewAttr(classnode, nullptr, "name", clname);
890  } else
891  classnode = fXML->NewChild(StackNode(), nullptr, clname);
892  stack = PushStack(classnode);
893  }
894 
895  if (fVersionBuf >= -1) {
896  if (fVersionBuf == -1)
897  fVersionBuf = 1;
898  fXML->NewIntAttr(classnode, xmlio::ClassVersion, fVersionBuf);
899  fVersionBuf = -111;
900  }
901 
902  if (IsUseNamespaces() && (GetXmlLayout() != kGeneralized))
903  stack->fClassNs = fXML->NewNS(classnode, XmlClassNameSpaceRef(cl), clname);
904 
905  } else {
906  if (!compressClassNode) {
907  if (GetXmlLayout() == kGeneralized) {
908  if (!VerifyStackNode(xmlio::Class, "StartInfo"))
909  return;
910  if (!VerifyStackAttr("name", clname, "StartInfo"))
911  return;
912  } else if (!VerifyStackNode(clname, "StartInfo"))
913  return;
914  stack = PushStack(StackNode());
915  }
916  }
917 
918  stack->fCompressedClassNode = compressClassNode;
919  stack->fInfo = sinfo;
920  stack->fIsStreamerInfo = kTRUE;
921 }
922 
923 ////////////////////////////////////////////////////////////////////////////////
924 /// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
925 /// and decrease level in xml structure.
926 
927 void TBufferXML::DecrementLevel(TVirtualStreamerInfo *info)
928 {
929  CheckVersionBuf();
930 
931  fCanUseCompact = kFALSE;
932 
933  if (gDebug > 2)
934  Info("DecrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
935 
936  TXMLStackObj *stack = Stack();
937 
938  if (!stack->IsStreamerInfo()) {
939  PerformPostProcessing();
940  stack = PopStack(); // remove stack of last element
941  }
942 
943  if (stack->fCompressedClassNode) {
944  stack->fInfo = nullptr;
945  stack->fIsStreamerInfo = kFALSE;
946  stack->fCompressedClassNode = kFALSE;
947  } else {
948  PopStack(); // back from data of stack info
949  if (IsReading())
950  ShiftStack("declevel"); // shift to next element after streamer info
951  }
952 }
953 
954 ////////////////////////////////////////////////////////////////////////////////
955 /// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
956 /// and add/verify next element of xml structure
957 /// This calls allows separate data, correspondent to one class member, from another
958 
959 void TBufferXML::SetStreamerElementNumber(TStreamerElement *elem, Int_t comptype)
960 {
961  WorkWithElement(elem, comptype);
962 }
963 
964 ////////////////////////////////////////////////////////////////////////////////
965 /// This function is a part of SetStreamerElementNumber method.
966 /// It is introduced for reading of data for specified data member of class.
967 /// Used also in ReadFastArray methods to resolve problem of compressed data,
968 /// when several data members of the same basic type streamed with single ...FastArray call
969 
970 void TBufferXML::WorkWithElement(TStreamerElement *elem, Int_t comp_type)
971 {
972  CheckVersionBuf();
973 
974  fCanUseCompact = kFALSE;
975  fExpectedBaseClass = nullptr;
976 
977  TXMLStackObj *stack = Stack();
978  if (!stack) {
979  Error("SetStreamerElementNumber", "stack is empty");
980  return;
981  }
982 
983  if (!stack->IsStreamerInfo()) { // this is not a first element
984  PerformPostProcessing();
985  PopStack(); // go level back
986  if (IsReading())
987  ShiftStack("startelem"); // shift to next element, only for reading
988  stack = Stack();
989  }
990 
991  if (!stack) {
992  Error("SetStreamerElementNumber", "Lost of stack");
993  return;
994  }
995 
996  if (!elem) {
997  Error("SetStreamerElementNumber", "Problem in Inc/Dec level");
998  return;
999  }
1000 
1001  TStreamerInfo *info = stack->fInfo;
1002 
1003  if (!stack->IsStreamerInfo()) {
1004  Error("SetStreamerElementNumber", "Problem in Inc/Dec level");
1005  return;
1006  }
1007  Int_t number = info ? info->GetElements()->IndexOf(elem) : -1;
1008 
1009  if (gDebug > 4)
1010  Info("SetStreamerElementNumber", " Next element %s", elem->GetName());
1011 
1012  Bool_t isBasicType = (elem->GetType() > 0) && (elem->GetType() < 20);
1013 
1014  fCanUseCompact =
1015  isBasicType && ((elem->GetType() == comp_type) || (elem->GetType() == comp_type - TStreamerInfo::kConv) ||
1016  (elem->GetType() == comp_type - TStreamerInfo::kSkip));
1017 
1018  if ((elem->GetType() == TStreamerInfo::kBase) ||
1019  ((elem->GetType() == TStreamerInfo::kTNamed) && !strcmp(elem->GetName(), TNamed::Class()->GetName())))
1020  fExpectedBaseClass = elem->GetClassPointer();
1021 
1022  if (fExpectedBaseClass && (gDebug > 3))
1023  Info("SetStreamerElementNumber", " Expects base class %s with standard streamer",
1024  fExpectedBaseClass->GetName());
1025 
1026  if (IsWriting()) {
1027  CreateElemNode(elem);
1028  } else {
1029  if (!VerifyElemNode(elem))
1030  return;
1031  }
1032 
1033  stack = Stack();
1034  stack->fElemNumber = number;
1035  stack->fIsElemOwner = (number < 0);
1036 }
1037 
1038 ////////////////////////////////////////////////////////////////////////////////
1039 /// Should be called at the beginning of custom class streamer.
1040 ///
1041 /// Informs buffer data about class which will be streamed now.
1042 /// ClassBegin(), ClassEnd() and ClassMemeber() should be used in
1043 /// custom class streamers to specify which kind of data are
1044 /// now streamed. Such information is used to correctly
1045 /// convert class data to XML. Without that functions calls
1046 /// classes with custom streamers cannot be used with TBufferXML
1047 
1048 void TBufferXML::ClassBegin(const TClass *cl, Version_t)
1049 {
1050  WorkWithClass(nullptr, cl);
1051 }
1052 
1053 ////////////////////////////////////////////////////////////////////////////////
1054 /// Should be called at the end of custom streamer
1055 /// See TBufferXML::ClassBegin for more details
1056 
1057 void TBufferXML::ClassEnd(const TClass *)
1058 {
1059  DecrementLevel(0);
1060 }
1061 
1062 ////////////////////////////////////////////////////////////////////////////////
1063 /// Method indicates name and typename of class member,
1064 /// which should be now streamed in custom streamer
1065 ///
1066 /// Following combinations are supported:
1067 /// -# name = "ClassName", typeName = 0 or typename==ClassName.
1068 /// This is a case, when data of parent class "ClassName" should be streamed.
1069 /// For instance, if class directly inherited from TObject, custom streamer
1070 /// should include following code:
1071 /// ~~~{.cpp}
1072 /// b.ClassMember("TObject");
1073 /// TObject::Streamer(b);
1074 /// ~~~
1075 /// -# Basic data type
1076 /// ~~~{.cpp}
1077 /// b.ClassMember("fInt","Int_t");
1078 /// b >> fInt;
1079 /// ~~~
1080 /// -# Array of basic data types
1081 /// ~~~{.cpp}
1082 /// b.ClassMember("fArr","Int_t", 5);
1083 /// b.ReadFastArray(fArr, 5);
1084 /// ~~~
1085 /// -# Object as data member
1086 /// ~~~{.cpp}
1087 /// b.ClassMemeber("fName","TString");
1088 /// fName.Streamer(b);
1089 /// ~~~
1090 /// -# Pointer on object as data member
1091 /// ~~~{.cpp}
1092 /// b.ClassMemeber("fObj","TObject*");
1093 /// b.StreamObject(fObj);
1094 /// ~~~
1095 ///
1096 /// Arrsize1 and arrsize2 arguments (when specified) indicate first and
1097 /// second dimension of array. Can be used for array of basic types.
1098 /// See ClassBegin() method for more details.
1099 
1100 void TBufferXML::ClassMember(const char *name, const char *typeName, Int_t arrsize1, Int_t arrsize2)
1101 {
1102  if (!typeName)
1103  typeName = name;
1104 
1105  if (!name || (strlen(name) == 0)) {
1106  Error("ClassMember", "Invalid member name");
1107  fErrorFlag = 1;
1108  return;
1109  }
1110 
1111  TString tname = typeName;
1112 
1113  Int_t typ_id(-1), comp_type(-1);
1114 
1115  if (strcmp(typeName, "raw:data") == 0)
1116  typ_id = TStreamerInfo::kMissing;
1117 
1118  if (typ_id < 0) {
1119  TDataType *dt = gROOT->GetType(typeName);
1120  if (dt)
1121  if ((dt->GetType() > 0) && (dt->GetType() < 20))
1122  typ_id = dt->GetType();
1123  }
1124 
1125  if (typ_id < 0)
1126  if (strcmp(name, typeName) == 0) {
1127  TClass *cl = TClass::GetClass(tname.Data());
1128  if (cl)
1129  typ_id = TStreamerInfo::kBase;
1130  }
1131 
1132  if (typ_id < 0) {
1133  Bool_t isptr = kFALSE;
1134  if (tname[tname.Length() - 1] == '*') {
1135  tname.Resize(tname.Length() - 1);
1136  isptr = kTRUE;
1137  }
1138  TClass *cl = TClass::GetClass(tname.Data());
1139  if (!cl) {
1140  Error("ClassMember", "Invalid class specifier %s", typeName);
1141  fErrorFlag = 1;
1142  return;
1143  }
1144 
1145  if (cl->IsTObject())
1146  typ_id = isptr ? TStreamerInfo::kObjectp : TStreamerInfo::kObject;
1147  else
1148  typ_id = isptr ? TStreamerInfo::kAnyp : TStreamerInfo::kAny;
1149 
1150  if ((cl == TString::Class()) && !isptr)
1151  typ_id = TStreamerInfo::kTString;
1152  }
1153 
1154  TStreamerElement *elem = nullptr;
1155 
1156  if (typ_id == TStreamerInfo::kMissing) {
1157  elem = new TStreamerElement(name, "title", 0, typ_id, "raw:data");
1158  } else if (typ_id == TStreamerInfo::kBase) {
1159  TClass *cl = TClass::GetClass(tname.Data());
1160  if (cl) {
1161  TStreamerBase *b = new TStreamerBase(tname.Data(), "title", 0);
1162  b->SetBaseVersion(cl->GetClassVersion());
1163  elem = b;
1164  }
1165  } else if ((typ_id > 0) && (typ_id < 20)) {
1166  elem = new TStreamerBasicType(name, "title", 0, typ_id, typeName);
1167  comp_type = typ_id;
1168  } else if ((typ_id == TStreamerInfo::kObject) || (typ_id == TStreamerInfo::kTObject) ||
1169  (typ_id == TStreamerInfo::kTNamed)) {
1170  elem = new TStreamerObject(name, "title", 0, tname.Data());
1171  } else if (typ_id == TStreamerInfo::kObjectp) {
1172  elem = new TStreamerObjectPointer(name, "title", 0, tname.Data());
1173  } else if (typ_id == TStreamerInfo::kAny) {
1174  elem = new TStreamerObjectAny(name, "title", 0, tname.Data());
1175  } else if (typ_id == TStreamerInfo::kAnyp) {
1176  elem = new TStreamerObjectAnyPointer(name, "title", 0, tname.Data());
1177  } else if (typ_id == TStreamerInfo::kTString) {
1178  elem = new TStreamerString(name, "title", 0);
1179  }
1180 
1181  if (!elem) {
1182  Error("ClassMember", "Invalid combination name = %s type = %s", name, typeName);
1183  fErrorFlag = 1;
1184  return;
1185  }
1186 
1187  if (arrsize1 > 0) {
1188  elem->SetArrayDim(arrsize2 > 0 ? 2 : 1);
1189  elem->SetMaxIndex(0, arrsize1);
1190  if (arrsize2 > 0)
1191  elem->SetMaxIndex(1, arrsize2);
1192  }
1193 
1194  // we indicate that there is no streamerinfo
1195  WorkWithElement(elem, comp_type);
1196 }
1197 
1198 ////////////////////////////////////////////////////////////////////////////////
1199 /// Function is converts TObject and TString structures to more compact representation
1200 
1201 void TBufferXML::PerformPostProcessing()
1202 {
1203  if (GetXmlLayout() == kGeneralized)
1204  return;
1205 
1206  const TStreamerElement *elem = Stack()->fElem;
1207  XMLNodePointer_t elemnode = IsWriting() ? Stack()->fNode : Stack(1)->fNode;
1208 
1209  if (!elem || !elemnode)
1210  return;
1211 
1212  if (elem->GetType() == TStreamerInfo::kTString) {
1213 
1214  XMLNodePointer_t node = fXML->GetChild(elemnode);
1215  fXML->SkipEmpty(node);
1216 
1217  XMLNodePointer_t nodecharstar(nullptr), nodeuchar(nullptr), nodeint(nullptr), nodestring(nullptr);
1218 
1219  while (node) {
1220  const char *name = fXML->GetNodeName(node);
1221  if (strcmp(name, xmlio::String) == 0) {
1222  if (nodestring)
1223  return;
1224  nodestring = node;
1225  } else if (strcmp(name, xmlio::UChar) == 0) {
1226  if (nodeuchar)
1227  return;
1228  nodeuchar = node;
1229  } else if (strcmp(name, xmlio::Int) == 0) {
1230  if (nodeint)
1231  return;
1232  nodeint = node;
1233  } else if (strcmp(name, xmlio::CharStar) == 0) {
1234  if (nodecharstar)
1235  return;
1236  nodecharstar = node;
1237  } else
1238  return; // can not be something else
1239  fXML->ShiftToNext(node);
1240  }
1241 
1242  TString str;
1243 
1244  if (GetIOVersion() < 3) {
1245  if (!nodeuchar)
1246  return;
1247  if (nodecharstar)
1248  str = fXML->GetAttr(nodecharstar, xmlio::v);
1249  fXML->UnlinkFreeNode(nodeuchar);
1250  fXML->UnlinkFreeNode(nodeint);
1251  fXML->UnlinkFreeNode(nodecharstar);
1252  } else {
1253  if (nodestring)
1254  str = fXML->GetAttr(nodestring, xmlio::v);
1255  fXML->UnlinkFreeNode(nodestring);
1256  }
1257 
1258  fXML->NewAttr(elemnode, nullptr, "str", str);
1259  } else if (elem->GetType() == TStreamerInfo::kTObject) {
1260  XMLNodePointer_t node = fXML->GetChild(elemnode);
1261  fXML->SkipEmpty(node);
1262 
1263  XMLNodePointer_t vnode = nullptr, idnode = nullptr, bitsnode = nullptr, prnode = nullptr;
1264 
1265  while (node) {
1266  const char *name = fXML->GetNodeName(node);
1267 
1268  if (strcmp(name, xmlio::OnlyVersion) == 0) {
1269  if (vnode)
1270  return;
1271  vnode = node;
1272  } else if (strcmp(name, xmlio::UInt) == 0) {
1273  if (!idnode)
1274  idnode = node;
1275  else if (!bitsnode)
1276  bitsnode = node;
1277  else
1278  return;
1279  } else if (strcmp(name, xmlio::UShort) == 0) {
1280  if (prnode)
1281  return;
1282  prnode = node;
1283  } else
1284  return;
1285  fXML->ShiftToNext(node);
1286  }
1287 
1288  if (!vnode || !idnode || !bitsnode)
1289  return;
1290 
1291  TString str = fXML->GetAttr(idnode, xmlio::v);
1292  fXML->NewAttr(elemnode, nullptr, "fUniqueID", str);
1293 
1294  str = fXML->GetAttr(bitsnode, xmlio::v);
1295  UInt_t bits;
1296  sscanf(str.Data(), "%u", &bits);
1297  bits = bits & ~TObject::kNotDeleted & ~TObject::kIsOnHeap;
1298 
1299  char sbuf[20];
1300  snprintf(sbuf, sizeof(sbuf), "%x", bits);
1301  fXML->NewAttr(elemnode, nullptr, "fBits", sbuf);
1302 
1303  if (prnode) {
1304  str = fXML->GetAttr(prnode, xmlio::v);
1305  fXML->NewAttr(elemnode, nullptr, "fProcessID", str);
1306  }
1307 
1308  fXML->UnlinkFreeNode(vnode);
1309  fXML->UnlinkFreeNode(idnode);
1310  fXML->UnlinkFreeNode(bitsnode);
1311  fXML->UnlinkFreeNode(prnode);
1312  }
1313 }
1314 
1315 ////////////////////////////////////////////////////////////////////////////////
1316 /// Function is unpack TObject and TString structures to be able read
1317 /// them from custom streamers of this objects
1318 
1319 void TBufferXML::PerformPreProcessing(const TStreamerElement *elem, XMLNodePointer_t elemnode)
1320 {
1321  if (GetXmlLayout() == kGeneralized)
1322  return;
1323  if (!elem || !elemnode)
1324  return;
1325 
1326  if (elem->GetType() == TStreamerInfo::kTString) {
1327 
1328  if (!fXML->HasAttr(elemnode, "str"))
1329  return;
1330  TString str = fXML->GetAttr(elemnode, "str");
1331  fXML->FreeAttr(elemnode, "str");
1332 
1333  if (GetIOVersion() < 3) {
1334  Int_t len = str.Length();
1335  XMLNodePointer_t ucharnode = fXML->NewChild(elemnode, nullptr, xmlio::UChar);
1336  char sbuf[20];
1337  snprintf(sbuf, sizeof(sbuf), "%d", len);
1338  if (len < 255) {
1339  fXML->NewAttr(ucharnode, nullptr, xmlio::v, sbuf);
1340  } else {
1341  fXML->NewAttr(ucharnode, nullptr, xmlio::v, "255");
1342  XMLNodePointer_t intnode = fXML->NewChild(elemnode, nullptr, xmlio::Int);
1343  fXML->NewAttr(intnode, nullptr, xmlio::v, sbuf);
1344  }
1345  if (len > 0) {
1346  XMLNodePointer_t node = fXML->NewChild(elemnode, nullptr, xmlio::CharStar);
1347  fXML->NewAttr(node, nullptr, xmlio::v, str);
1348  }
1349  } else {
1350  XMLNodePointer_t node = fXML->NewChild(elemnode, nullptr, xmlio::String);
1351  fXML->NewAttr(node, nullptr, xmlio::v, str);
1352  }
1353  } else if (elem->GetType() == TStreamerInfo::kTObject) {
1354  if (!fXML->HasAttr(elemnode, "fUniqueID"))
1355  return;
1356  if (!fXML->HasAttr(elemnode, "fBits"))
1357  return;
1358 
1359  TString idstr = fXML->GetAttr(elemnode, "fUniqueID");
1360  TString bitsstr = fXML->GetAttr(elemnode, "fBits");
1361  TString prstr = fXML->GetAttr(elemnode, "fProcessID");
1362 
1363  fXML->FreeAttr(elemnode, "fUniqueID");
1364  fXML->FreeAttr(elemnode, "fBits");
1365  fXML->FreeAttr(elemnode, "fProcessID");
1366 
1367  XMLNodePointer_t node = fXML->NewChild(elemnode, nullptr, xmlio::OnlyVersion);
1368  fXML->NewAttr(node, nullptr, xmlio::v, "1");
1369 
1370  node = fXML->NewChild(elemnode, nullptr, xmlio::UInt);
1371  fXML->NewAttr(node, nullptr, xmlio::v, idstr);
1372 
1373  UInt_t bits = 0;
1374  sscanf(bitsstr.Data(), "%x", &bits);
1375  bits = bits | TObject::kNotDeleted | TObject::kIsOnHeap;
1376  char sbuf[20];
1377  snprintf(sbuf, sizeof(sbuf), "%u", bits);
1378 
1379  node = fXML->NewChild(elemnode, nullptr, xmlio::UInt);
1380  fXML->NewAttr(node, nullptr, xmlio::v, sbuf);
1381 
1382  if (prstr.Length() > 0) {
1383  node = fXML->NewChild(elemnode, nullptr, xmlio::UShort);
1384  fXML->NewAttr(node, nullptr, xmlio::v, prstr.Data());
1385  }
1386  }
1387 }
1388 
1389 ////////////////////////////////////////////////////////////////////////////////
1390 /// Function is called before any IO operation of TBuffer
1391 /// Now is used to store version value if no proper calls are discovered
1392 
1393 void TBufferXML::BeforeIOoperation()
1394 {
1395  CheckVersionBuf();
1396 }
1397 
1398 ////////////////////////////////////////////////////////////////////////////////
1399 /// Function to read class from buffer, used in old-style streamers
1400 
1401 TClass *TBufferXML::ReadClass(const TClass *, UInt_t *)
1402 {
1403  const char *clname = nullptr;
1404 
1405  if (VerifyItemNode(xmlio::Class))
1406  clname = XmlReadValue(xmlio::Class);
1407 
1408  if (gDebug > 2)
1409  Info("ReadClass", "Try to read class %s", clname ? clname : "---");
1410 
1411  return clname ? gROOT->GetClass(clname) : nullptr;
1412 }
1413 
1414 ////////////////////////////////////////////////////////////////////////////////
1415 /// Function to write class into buffer, used in old-style streamers
1416 
1417 void TBufferXML::WriteClass(const TClass *cl)
1418 {
1419  if (gDebug > 2)
1420  Info("WriteClass", "Try to write class %s", cl->GetName());
1421 
1422  XmlWriteValue(cl->GetName(), xmlio::Class);
1423 }
1424 
1425 ////////////////////////////////////////////////////////////////////////////////
1426 /// Read version value from buffer
1427 
1428 Version_t TBufferXML::ReadVersion(UInt_t *start, UInt_t *bcnt, const TClass * /*cl*/)
1429 {
1430  BeforeIOoperation();
1431 
1432  Version_t res = 0;
1433 
1434  if (start)
1435  *start = 0;
1436  if (bcnt)
1437  *bcnt = 0;
1438 
1439  if (VerifyItemNode(xmlio::OnlyVersion)) {
1440  res = AtoI(XmlReadValue(xmlio::OnlyVersion));
1441  } else if (fExpectedBaseClass && (fXML->HasAttr(Stack(1)->fNode, xmlio::ClassVersion))) {
1442  res = fXML->GetIntAttr(Stack(1)->fNode, xmlio::ClassVersion);
1443  } else if (fXML->HasAttr(StackNode(), xmlio::ClassVersion)) {
1444  res = fXML->GetIntAttr(StackNode(), xmlio::ClassVersion);
1445  } else {
1446  Error("ReadVersion", "No correspondent tags to read version");
1447  fErrorFlag = 1;
1448  }
1449 
1450  if (gDebug > 2)
1451  Info("ReadVersion", "Version = %d", res);
1452 
1453  return res;
1454 }
1455 
1456 ////////////////////////////////////////////////////////////////////////////////
1457 /// Checks buffer, filled by WriteVersion
1458 /// if next data is arriving, version should be stored in buffer
1459 
1460 void TBufferXML::CheckVersionBuf()
1461 {
1462  if (IsWriting() && (fVersionBuf >= -100)) {
1463  char sbuf[20];
1464  snprintf(sbuf, sizeof(sbuf), "%d", fVersionBuf);
1465  XmlWriteValue(sbuf, xmlio::OnlyVersion);
1466  fVersionBuf = -111;
1467  }
1468 }
1469 
1470 ////////////////////////////////////////////////////////////////////////////////
1471 /// Copies class version to buffer, but not writes it to xml
1472 /// Version will be written with next I/O operation or
1473 /// will be added as attribute of class tag, created by IncrementLevel call
1474 
1475 UInt_t TBufferXML::WriteVersion(const TClass *cl, Bool_t /* useBcnt */)
1476 {
1477  BeforeIOoperation();
1478 
1479  if (fExpectedBaseClass != cl)
1480  fExpectedBaseClass = nullptr;
1481 
1482  fVersionBuf = cl->GetClassVersion();
1483 
1484  if (gDebug > 2)
1485  Info("WriteVersion", "Class: %s, version = %d", cl->GetName(), fVersionBuf);
1486 
1487  return 0;
1488 }
1489 
1490 ////////////////////////////////////////////////////////////////////////////////
1491 /// Read object from buffer. Only used from TBuffer
1492 
1493 void *TBufferXML::ReadObjectAny(const TClass *)
1494 {
1495  BeforeIOoperation();
1496  if (gDebug > 2)
1497  Info("ReadObjectAny", "From node %s", fXML->GetNodeName(StackNode()));
1498  void *res = XmlReadObject(nullptr);
1499  return res;
1500 }
1501 
1502 ////////////////////////////////////////////////////////////////////////////////
1503 /// Skip any kind of object from buffer
1504 /// Actually skip only one node on current level of xml structure
1505 
1506 void TBufferXML::SkipObjectAny()
1507 {
1508  ShiftStack("skipobjectany");
1509 }
1510 
1511 ////////////////////////////////////////////////////////////////////////////////
1512 /// Write object to buffer. Only used from TBuffer
1513 
1514 void TBufferXML::WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse)
1515 {
1516  BeforeIOoperation();
1517  if (gDebug > 2)
1518  Info("WriteObject", "Class %s", (actualClass ? actualClass->GetName() : " null"));
1519  XmlWriteObject(actualObjStart, actualClass, cacheReuse);
1520 }
1521 
1522 ////////////////////////////////////////////////////////////////////////////////
1523 /// Template method to read array content
1524 
1525 template <typename T>
1526 R__ALWAYS_INLINE void TBufferXML::XmlReadArrayContent(T *arr, Int_t arrsize)
1527 {
1528  Int_t indx = 0, cnt, curr;
1529  while (indx < arrsize) {
1530  cnt = 1;
1531  if (fXML->HasAttr(StackNode(), xmlio::cnt))
1532  cnt = fXML->GetIntAttr(StackNode(), xmlio::cnt);
1533  XmlReadBasic(arr[indx]);
1534  curr = indx++;
1535  while (cnt-- > 1)
1536  arr[indx++] = arr[curr];
1537  }
1538 }
1539 
1540 ////////////////////////////////////////////////////////////////////////////////
1541 /// Template method to read array with size attribute
1542 /// If necessary, array is created
1543 
1544 template <typename T>
1545 R__ALWAYS_INLINE Int_t TBufferXML::XmlReadArray(T *&arr, bool is_static)
1546 {
1547  BeforeIOoperation();
1548  if (!VerifyItemNode(xmlio::Array, is_static ? "ReadStaticArray" : "ReadArray"))
1549  return 0;
1550  Int_t n = fXML->GetIntAttr(StackNode(), xmlio::Size);
1551  if (n <= 0)
1552  return 0;
1553  if (!arr) {
1554  if (is_static)
1555  return 0;
1556  arr = new T[n];
1557  }
1558  PushStack(StackNode());
1559  XmlReadArrayContent(arr, n);
1560  PopStack();
1561  ShiftStack(is_static ? "readstatarr" : "readarr");
1562  return n;
1563 }
1564 
1565 ////////////////////////////////////////////////////////////////////////////////
1566 /// Read array of Bool_t from buffer
1567 
1568 Int_t TBufferXML::ReadArray(Bool_t *&b)
1569 {
1570  return XmlReadArray(b);
1571 }
1572 
1573 ////////////////////////////////////////////////////////////////////////////////
1574 /// Read array of Char_t from buffer
1575 
1576 Int_t TBufferXML::ReadArray(Char_t *&c)
1577 {
1578  return XmlReadArray(c);
1579 }
1580 
1581 ////////////////////////////////////////////////////////////////////////////////
1582 /// Read array of UChar_t from buffer
1583 
1584 Int_t TBufferXML::ReadArray(UChar_t *&c)
1585 {
1586  return XmlReadArray(c);
1587 }
1588 
1589 ////////////////////////////////////////////////////////////////////////////////
1590 /// Read array of Short_t from buffer
1591 
1592 Int_t TBufferXML::ReadArray(Short_t *&h)
1593 {
1594  return XmlReadArray(h);
1595 }
1596 
1597 ////////////////////////////////////////////////////////////////////////////////
1598 /// Read array of UShort_t from buffer
1599 
1600 Int_t TBufferXML::ReadArray(UShort_t *&h)
1601 {
1602  return XmlReadArray(h);
1603 }
1604 
1605 ////////////////////////////////////////////////////////////////////////////////
1606 /// Read array of Int_t from buffer
1607 
1608 Int_t TBufferXML::ReadArray(Int_t *&i)
1609 {
1610  return XmlReadArray(i);
1611 }
1612 
1613 ////////////////////////////////////////////////////////////////////////////////
1614 /// Read array of UInt_t from buffer
1615 
1616 Int_t TBufferXML::ReadArray(UInt_t *&i)
1617 {
1618  return XmlReadArray(i);
1619 }
1620 
1621 ////////////////////////////////////////////////////////////////////////////////
1622 /// Read array of Long_t from buffer
1623 
1624 Int_t TBufferXML::ReadArray(Long_t *&l)
1625 {
1626  return XmlReadArray(l);
1627 }
1628 
1629 ////////////////////////////////////////////////////////////////////////////////
1630 /// Read array of ULong_t from buffer
1631 
1632 Int_t TBufferXML::ReadArray(ULong_t *&l)
1633 {
1634  return XmlReadArray(l);
1635 }
1636 
1637 ////////////////////////////////////////////////////////////////////////////////
1638 /// Read array of Long64_t from buffer
1639 
1640 Int_t TBufferXML::ReadArray(Long64_t *&l)
1641 {
1642  return XmlReadArray(l);
1643 }
1644 
1645 ////////////////////////////////////////////////////////////////////////////////
1646 /// Read array of ULong64_t from buffer
1647 
1648 Int_t TBufferXML::ReadArray(ULong64_t *&l)
1649 {
1650  return XmlReadArray(l);
1651 }
1652 
1653 ////////////////////////////////////////////////////////////////////////////////
1654 /// Read array of Float_t from buffer
1655 
1656 Int_t TBufferXML::ReadArray(Float_t *&f)
1657 {
1658  return XmlReadArray(f);
1659 }
1660 
1661 ////////////////////////////////////////////////////////////////////////////////
1662 /// Read array of Double_t from buffer
1663 
1664 Int_t TBufferXML::ReadArray(Double_t *&d)
1665 {
1666  return XmlReadArray(d);
1667 }
1668 
1669 ////////////////////////////////////////////////////////////////////////////////
1670 /// Read array of Bool_t from buffer
1671 
1672 Int_t TBufferXML::ReadStaticArray(Bool_t *b)
1673 {
1674  return XmlReadArray(b, true);
1675 }
1676 
1677 ////////////////////////////////////////////////////////////////////////////////
1678 /// Read array of Char_t from buffer
1679 
1680 Int_t TBufferXML::ReadStaticArray(Char_t *c)
1681 {
1682  return XmlReadArray(c, true);
1683 }
1684 
1685 ////////////////////////////////////////////////////////////////////////////////
1686 /// Read array of UChar_t from buffer
1687 
1688 Int_t TBufferXML::ReadStaticArray(UChar_t *c)
1689 {
1690  return XmlReadArray(c, true);
1691 }
1692 
1693 ////////////////////////////////////////////////////////////////////////////////
1694 /// Read array of Short_t from buffer
1695 
1696 Int_t TBufferXML::ReadStaticArray(Short_t *h)
1697 {
1698  return XmlReadArray(h, true);
1699 }
1700 
1701 ////////////////////////////////////////////////////////////////////////////////
1702 /// Read array of UShort_t from buffer
1703 
1704 Int_t TBufferXML::ReadStaticArray(UShort_t *h)
1705 {
1706  return XmlReadArray(h, true);
1707 }
1708 
1709 ////////////////////////////////////////////////////////////////////////////////
1710 /// Read array of Int_t from buffer
1711 
1712 Int_t TBufferXML::ReadStaticArray(Int_t *i)
1713 {
1714  return XmlReadArray(i, true);
1715 }
1716 
1717 ////////////////////////////////////////////////////////////////////////////////
1718 /// Read array of UInt_t from buffer
1719 
1720 Int_t TBufferXML::ReadStaticArray(UInt_t *i)
1721 {
1722  return XmlReadArray(i, true);
1723 }
1724 
1725 ////////////////////////////////////////////////////////////////////////////////
1726 /// Read array of Long_t from buffer
1727 
1728 Int_t TBufferXML::ReadStaticArray(Long_t *l)
1729 {
1730  return XmlReadArray(l, true);
1731 }
1732 
1733 ////////////////////////////////////////////////////////////////////////////////
1734 /// Read array of ULong_t from buffer
1735 
1736 Int_t TBufferXML::ReadStaticArray(ULong_t *l)
1737 {
1738  return XmlReadArray(l, true);
1739 }
1740 
1741 ////////////////////////////////////////////////////////////////////////////////
1742 /// Read array of Long64_t from buffer
1743 
1744 Int_t TBufferXML::ReadStaticArray(Long64_t *l)
1745 {
1746  return XmlReadArray(l, true);
1747 }
1748 
1749 ////////////////////////////////////////////////////////////////////////////////
1750 /// Read array of ULong64_t from buffer
1751 
1752 Int_t TBufferXML::ReadStaticArray(ULong64_t *l)
1753 {
1754  return XmlReadArray(l, true);
1755 }
1756 
1757 ////////////////////////////////////////////////////////////////////////////////
1758 /// Read array of Float_t from buffer
1759 
1760 Int_t TBufferXML::ReadStaticArray(Float_t *f)
1761 {
1762  return XmlReadArray(f, true);
1763 }
1764 
1765 ////////////////////////////////////////////////////////////////////////////////
1766 /// Read array of Double_t from buffer
1767 
1768 Int_t TBufferXML::ReadStaticArray(Double_t *d)
1769 {
1770  return XmlReadArray(d, true);
1771 }
1772 
1773 ////////////////////////////////////////////////////////////////////////////////
1774 /// Template method to read content of array, which not include size of array
1775 /// Also treated situation, when instead of one single array chain
1776 /// of several elements should be produced
1777 
1778 template <typename T>
1779 R__ALWAYS_INLINE void TBufferXML::XmlReadFastArray(T *arr, Int_t n)
1780 {
1781  BeforeIOoperation();
1782  if (n <= 0)
1783  return;
1784  if (!VerifyItemNode(xmlio::Array, "ReadFastArray"))
1785  return;
1786  PushStack(StackNode());
1787  XmlReadArrayContent(arr, n);
1788  PopStack();
1789  ShiftStack("readfastarr");
1790 }
1791 
1792 ////////////////////////////////////////////////////////////////////////////////
1793 /// Read array of Bool_t from buffer
1794 
1795 void TBufferXML::ReadFastArray(Bool_t *b, Int_t n)
1796 {
1797  XmlReadFastArray(b, n);
1798 }
1799 
1800 ////////////////////////////////////////////////////////////////////////////////
1801 /// Read array of Char_t from buffer
1802 /// if nodename==CharStar, read all array as string
1803 
1804 void TBufferXML::ReadFastArray(Char_t *c, Int_t n)
1805 {
1806  if ((n > 0) && VerifyItemNode(xmlio::CharStar)) {
1807  const char *buf;
1808  if ((buf = XmlReadValue(xmlio::CharStar))) {
1809  Int_t size = strlen(buf);
1810  if (size < n)
1811  size = n;
1812  memcpy(c, buf, size);
1813  }
1814  } else {
1815  XmlReadFastArray(c, n);
1816  }
1817 }
1818 
1819 ////////////////////////////////////////////////////////////////////////////////
1820 /// Read array of n characters from the I/O buffer.
1821 /// Used only from TLeafC, dummy implementation here
1822 
1823 void TBufferXML::ReadFastArrayString(Char_t *c, Int_t n)
1824 {
1825  ReadFastArray(c, n);
1826 }
1827 
1828 ////////////////////////////////////////////////////////////////////////////////
1829 /// Read array of UChar_t from buffer
1830 
1831 void TBufferXML::ReadFastArray(UChar_t *c, Int_t n)
1832 {
1833  XmlReadFastArray(c, n);
1834 }
1835 
1836 ////////////////////////////////////////////////////////////////////////////////
1837 /// Read array of Short_t from buffer
1838 
1839 void TBufferXML::ReadFastArray(Short_t *h, Int_t n)
1840 {
1841  XmlReadFastArray(h, n);
1842 }
1843 
1844 ////////////////////////////////////////////////////////////////////////////////
1845 /// Read array of UShort_t from buffer
1846 
1847 void TBufferXML::ReadFastArray(UShort_t *h, Int_t n)
1848 {
1849  XmlReadFastArray(h, n);
1850 }
1851 
1852 ////////////////////////////////////////////////////////////////////////////////
1853 /// Read array of Int_t from buffer
1854 
1855 void TBufferXML::ReadFastArray(Int_t *i, Int_t n)
1856 {
1857  XmlReadFastArray(i, n);
1858 }
1859 
1860 ////////////////////////////////////////////////////////////////////////////////
1861 /// Read array of UInt_t from buffer
1862 
1863 void TBufferXML::ReadFastArray(UInt_t *i, Int_t n)
1864 {
1865  XmlReadFastArray(i, n);
1866 }
1867 
1868 ////////////////////////////////////////////////////////////////////////////////
1869 /// Read array of Long_t from buffer
1870 
1871 void TBufferXML::ReadFastArray(Long_t *l, Int_t n)
1872 {
1873  XmlReadFastArray(l, n);
1874 }
1875 
1876 ////////////////////////////////////////////////////////////////////////////////
1877 /// Read array of ULong_t from buffer
1878 
1879 void TBufferXML::ReadFastArray(ULong_t *l, Int_t n)
1880 {
1881  XmlReadFastArray(l, n);
1882 }
1883 
1884 ////////////////////////////////////////////////////////////////////////////////
1885 /// Read array of Long64_t from buffer
1886 
1887 void TBufferXML::ReadFastArray(Long64_t *l, Int_t n)
1888 {
1889  XmlReadFastArray(l, n);
1890 }
1891 
1892 ////////////////////////////////////////////////////////////////////////////////
1893 /// Read array of ULong64_t from buffer
1894 
1895 void TBufferXML::ReadFastArray(ULong64_t *l, Int_t n)
1896 {
1897  XmlReadFastArray(l, n);
1898 }
1899 
1900 ////////////////////////////////////////////////////////////////////////////////
1901 /// Read array of Float_t from buffer
1902 
1903 void TBufferXML::ReadFastArray(Float_t *f, Int_t n)
1904 {
1905  XmlReadFastArray(f, n);
1906 }
1907 
1908 ////////////////////////////////////////////////////////////////////////////////
1909 /// Read array of Double_t from buffer
1910 
1911 void TBufferXML::ReadFastArray(Double_t *d, Int_t n)
1912 {
1913  XmlReadFastArray(d, n);
1914 }
1915 
1916 ////////////////////////////////////////////////////////////////////////////////
1917 /// Read an array of 'n' objects from the I/O buffer.
1918 /// Stores the objects read starting at the address 'start'.
1919 /// The objects in the array are assume to be of class 'cl'.
1920 
1921 void TBufferXML::ReadFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer *streamer,
1922  const TClass *onFileClass)
1923 {
1924  if (streamer) {
1925  streamer->SetOnFileClass(onFileClass);
1926  (*streamer)(*this, start, 0);
1927  return;
1928  }
1929 
1930  int objectSize = cl->Size();
1931  char *obj = (char *)start;
1932  char *end = obj + n * objectSize;
1933 
1934  for (; obj < end; obj += objectSize)
1935  ((TClass *)cl)->Streamer(obj, *this, onFileClass);
1936 }
1937 
1938 ////////////////////////////////////////////////////////////////////////////////
1939 /// Read an array of 'n' objects from the I/O buffer.
1940 ///
1941 /// The objects read are stored starting at the address '*start'
1942 /// The objects in the array are assumed to be of class 'cl' or a derived class.
1943 /// 'mode' indicates whether the data member is marked with '->'
1944 
1945 void TBufferXML::ReadFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc, TMemberStreamer *streamer,
1946  const TClass *onFileClass)
1947 {
1948 
1949  Bool_t oldStyle = kFALSE; // flag used to reproduce old-style I/= actions for kSTLp
1950 
1951  if ((GetIOVersion() < 4) && !isPreAlloc) {
1952  TStreamerElement *elem = Stack()->fElem;
1953  if (elem && ((elem->GetType() == TStreamerInfo::kSTLp) ||
1954  (elem->GetType() == TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL)))
1955  oldStyle = kTRUE;
1956  }
1957 
1958  if (streamer) {
1959  if (isPreAlloc) {
1960  for (Int_t j = 0; j < n; j++) {
1961  if (!start[j])
1962  start[j] = cl->New();
1963  }
1964  }
1965  streamer->SetOnFileClass(onFileClass);
1966  (*streamer)(*this, (void *)start, oldStyle ? n : 0);
1967  return;
1968  }
1969 
1970  if (!isPreAlloc) {
1971 
1972  for (Int_t j = 0; j < n; j++) {
1973  if (oldStyle) {
1974  if (!start[j])
1975  start[j] = ((TClass *)cl)->New();
1976  ((TClass *)cl)->Streamer(start[j], *this);
1977  continue;
1978  }
1979  // delete the object or collection
1980  void *old = start[j];
1981  start[j] = ReadObjectAny(cl);
1982  if (old && old != start[j] && TStreamerInfo::CanDelete()
1983  // There are some cases where the user may set up a pointer in the (default)
1984  // constructor but not mark this pointer as transient. Sometime the value
1985  // of this pointer is the address of one of the object with just created
1986  // and the following delete would result in the deletion (possibly of the
1987  // top level object we are goint to return!).
1988  // Eventhough this is a user error, we could prevent the crash by simply
1989  // adding:
1990  // && !CheckObject(start[j],cl)
1991  // However this can increase the read time significantly (10% in the case
1992  // of one TLine pointer in the test/Track and run ./Event 200 0 0 20 30000
1993  //
1994  // If ReadObjectAny returned the same value as we previous had, this means
1995  // that when writing this object (start[j] had already been written and
1996  // is indeed pointing to the same object as the object the user set up
1997  // in the default constructor).
1998  ) {
1999  ((TClass *)cl)->Destructor(old, kFALSE); // call delete and desctructor
2000  }
2001  }
2002 
2003  } else {
2004  // case //-> in comment
2005 
2006  for (Int_t j = 0; j < n; j++) {
2007  if (!start[j])
2008  start[j] = ((TClass *)cl)->New();
2009  ((TClass *)cl)->Streamer(start[j], *this, onFileClass);
2010  }
2011  }
2012 }
2013 
2014 template <typename T>
2015 R__ALWAYS_INLINE void TBufferXML::XmlWriteArrayContent(const T *arr, Int_t arrsize)
2016 {
2017  if (fCompressLevel > 0) {
2018  Int_t indx = 0;
2019  while (indx < arrsize) {
2020  XMLNodePointer_t elemnode = XmlWriteBasic(arr[indx]);
2021  Int_t curr = indx++;
2022  while ((indx < arrsize) && (arr[indx] == arr[curr]))
2023  indx++;
2024  if (indx - curr > 1)
2025  fXML->NewIntAttr(elemnode, xmlio::cnt, indx - curr);
2026  }
2027  } else {
2028  for (Int_t indx = 0; indx < arrsize; indx++)
2029  XmlWriteBasic(arr[indx]);
2030  }
2031 }
2032 
2033 ////////////////////////////////////////////////////////////////////////////////
2034 /// Write array, including it size
2035 /// Content may be compressed
2036 
2037 template <typename T>
2038 R__ALWAYS_INLINE void TBufferXML::XmlWriteArray(const T *arr, Int_t arrsize)
2039 {
2040  BeforeIOoperation();
2041  XMLNodePointer_t arrnode = CreateItemNode(xmlio::Array);
2042  fXML->NewIntAttr(arrnode, xmlio::Size, arrsize);
2043  PushStack(arrnode);
2044  XmlWriteArrayContent(arr, arrsize);
2045  PopStack();
2046 }
2047 
2048 ////////////////////////////////////////////////////////////////////////////////
2049 /// Write array of Bool_t to buffer
2050 
2051 void TBufferXML::WriteArray(const Bool_t *b, Int_t n)
2052 {
2053  XmlWriteArray(b, n);
2054 }
2055 
2056 ////////////////////////////////////////////////////////////////////////////////
2057 /// Write array of Char_t to buffer
2058 
2059 void TBufferXML::WriteArray(const Char_t *c, Int_t n)
2060 {
2061  XmlWriteArray(c, n);
2062 }
2063 
2064 ////////////////////////////////////////////////////////////////////////////////
2065 /// Write array of UChar_t to buffer
2066 
2067 void TBufferXML::WriteArray(const UChar_t *c, Int_t n)
2068 {
2069  XmlWriteArray(c, n);
2070 }
2071 
2072 ////////////////////////////////////////////////////////////////////////////////
2073 /// Write array of Short_t to buffer
2074 
2075 void TBufferXML::WriteArray(const Short_t *h, Int_t n)
2076 {
2077  XmlWriteArray(h, n);
2078 }
2079 
2080 ////////////////////////////////////////////////////////////////////////////////
2081 /// Write array of UShort_t to buffer
2082 
2083 void TBufferXML::WriteArray(const UShort_t *h, Int_t n)
2084 {
2085  XmlWriteArray(h, n);
2086 }
2087 
2088 ////////////////////////////////////////////////////////////////////////////////
2089 /// Write array of Int_ to buffer
2090 
2091 void TBufferXML::WriteArray(const Int_t *i, Int_t n)
2092 {
2093  XmlWriteArray(i, n);
2094 }
2095 
2096 ////////////////////////////////////////////////////////////////////////////////
2097 /// Write array of UInt_t to buffer
2098 
2099 void TBufferXML::WriteArray(const UInt_t *i, Int_t n)
2100 {
2101  XmlWriteArray(i, n);
2102 }
2103 
2104 ////////////////////////////////////////////////////////////////////////////////
2105 /// Write array of Long_t to buffer
2106 
2107 void TBufferXML::WriteArray(const Long_t *l, Int_t n)
2108 {
2109  XmlWriteArray(l, n);
2110 }
2111 
2112 ////////////////////////////////////////////////////////////////////////////////
2113 /// Write array of ULong_t to buffer
2114 
2115 void TBufferXML::WriteArray(const ULong_t *l, Int_t n)
2116 {
2117  XmlWriteArray(l, n);
2118 }
2119 
2120 ////////////////////////////////////////////////////////////////////////////////
2121 /// Write array of Long64_t to buffer
2122 
2123 void TBufferXML::WriteArray(const Long64_t *l, Int_t n)
2124 {
2125  XmlWriteArray(l, n);
2126 }
2127 
2128 ////////////////////////////////////////////////////////////////////////////////
2129 /// Write array of ULong64_t to buffer
2130 
2131 void TBufferXML::WriteArray(const ULong64_t *l, Int_t n)
2132 {
2133  XmlWriteArray(l, n);
2134 }
2135 
2136 ////////////////////////////////////////////////////////////////////////////////
2137 /// Write array of Float_t to buffer
2138 
2139 void TBufferXML::WriteArray(const Float_t *f, Int_t n)
2140 {
2141  XmlWriteArray(f, n);
2142 }
2143 
2144 ////////////////////////////////////////////////////////////////////////////////
2145 /// Write array of Double_t to buffer
2146 
2147 void TBufferXML::WriteArray(const Double_t *d, Int_t n)
2148 {
2149  XmlWriteArray(d, n);
2150 }
2151 
2152 /////////////////////////////////////////////////////////////////////////////////
2153 /// Write array without size attribute
2154 /// Also treat situation, when instead of one single array
2155 /// chain of several elements should be produced
2156 
2157 template <typename T>
2158 R__ALWAYS_INLINE void TBufferXML::XmlWriteFastArray(const T *arr, Int_t n)
2159 {
2160  BeforeIOoperation();
2161  if (n <= 0)
2162  return;
2163  XMLNodePointer_t arrnode = CreateItemNode(xmlio::Array);
2164  PushStack(arrnode);
2165  XmlWriteArrayContent(arr, n);
2166  PopStack();
2167 }
2168 
2169 ////////////////////////////////////////////////////////////////////////////////
2170 /// Write array of Bool_t to buffer
2171 
2172 void TBufferXML::WriteFastArray(const Bool_t *b, Int_t n)
2173 {
2174  XmlWriteFastArray(b, n);
2175 }
2176 
2177 ////////////////////////////////////////////////////////////////////////////////
2178 /// Write array of Char_t to buffer
2179 /// If array does not include any special characters,
2180 /// it will be reproduced as CharStar node with string as attribute
2181 
2182 void TBufferXML::WriteFastArray(const Char_t *c, Int_t n)
2183 {
2184  Bool_t usedefault = (n == 0);
2185  const Char_t *buf = c;
2186  if (!usedefault)
2187  for (int i = 0; i < n; i++) {
2188  if (*buf < 27) {
2189  usedefault = kTRUE;
2190  break;
2191  }
2192  buf++;
2193  }
2194  if (usedefault) {
2195  XmlWriteFastArray(c, n);
2196  } else {
2197  Char_t *buf2 = new Char_t[n + 1];
2198  memcpy(buf2, c, n);
2199  buf2[n] = 0;
2200  XmlWriteValue(buf2, xmlio::CharStar);
2201  delete[] buf2;
2202  }
2203 }
2204 
2205 ////////////////////////////////////////////////////////////////////////////////
2206 /// Write array of UChar_t to buffer
2207 
2208 void TBufferXML::WriteFastArray(const UChar_t *c, Int_t n)
2209 {
2210  XmlWriteFastArray(c, n);
2211 }
2212 
2213 ////////////////////////////////////////////////////////////////////////////////
2214 /// Write array of Short_t to buffer
2215 
2216 void TBufferXML::WriteFastArray(const Short_t *h, Int_t n)
2217 {
2218  XmlWriteFastArray(h, n);
2219 }
2220 
2221 ////////////////////////////////////////////////////////////////////////////////
2222 /// Write array of UShort_t to buffer
2223 
2224 void TBufferXML::WriteFastArray(const UShort_t *h, Int_t n)
2225 {
2226  XmlWriteFastArray(h, n);
2227 }
2228 
2229 ////////////////////////////////////////////////////////////////////////////////
2230 /// Write array of Int_t to buffer
2231 
2232 void TBufferXML::WriteFastArray(const Int_t *i, Int_t n)
2233 {
2234  XmlWriteFastArray(i, n);
2235 }
2236 
2237 ////////////////////////////////////////////////////////////////////////////////
2238 /// Write array of UInt_t to buffer
2239 
2240 void TBufferXML::WriteFastArray(const UInt_t *i, Int_t n)
2241 {
2242  XmlWriteFastArray(i, n);
2243 }
2244 
2245 ////////////////////////////////////////////////////////////////////////////////
2246 /// Write array of Long_t to buffer
2247 
2248 void TBufferXML::WriteFastArray(const Long_t *l, Int_t n)
2249 {
2250  XmlWriteFastArray(l, n);
2251 }
2252 
2253 ////////////////////////////////////////////////////////////////////////////////
2254 /// Write array of ULong_t to buffer
2255 
2256 void TBufferXML::WriteFastArray(const ULong_t *l, Int_t n)
2257 {
2258  XmlWriteFastArray(l, n);
2259 }
2260 
2261 ////////////////////////////////////////////////////////////////////////////////
2262 /// Write array of Long64_t to buffer
2263 
2264 void TBufferXML::WriteFastArray(const Long64_t *l, Int_t n)
2265 {
2266  XmlWriteFastArray(l, n);
2267 }
2268 
2269 ////////////////////////////////////////////////////////////////////////////////
2270 /// Write array of ULong64_t to buffer
2271 
2272 void TBufferXML::WriteFastArray(const ULong64_t *l, Int_t n)
2273 {
2274  XmlWriteFastArray(l, n);
2275 }
2276 
2277 ////////////////////////////////////////////////////////////////////////////////
2278 /// Write array of Float_t to buffer
2279 
2280 void TBufferXML::WriteFastArray(const Float_t *f, Int_t n)
2281 {
2282  XmlWriteFastArray(f, n);
2283 }
2284 
2285 ////////////////////////////////////////////////////////////////////////////////
2286 /// Write array of Double_t to buffer
2287 
2288 void TBufferXML::WriteFastArray(const Double_t *d, Int_t n)
2289 {
2290  XmlWriteFastArray(d, n);
2291 }
2292 
2293 ////////////////////////////////////////////////////////////////////////////////
2294 /// Write array of n characters into the I/O buffer.
2295 /// Used only by TLeafC, just dummy implementation here
2296 
2297 void TBufferXML::WriteFastArrayString(const Char_t *c, Int_t n)
2298 {
2299  WriteFastArray(c, n);
2300 }
2301 
2302 ////////////////////////////////////////////////////////////////////////////////
2303 /// Write an array of object starting at the address 'start' and of length 'n'
2304 /// the objects in the array are assumed to be of class 'cl'
2305 
2306 void TBufferXML::WriteFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer *streamer)
2307 {
2308  if (streamer) {
2309  (*streamer)(*this, start, 0);
2310  return;
2311  }
2312 
2313  char *obj = (char *)start;
2314  if (!n)
2315  n = 1;
2316  int size = cl->Size();
2317 
2318  for (Int_t j = 0; j < n; j++, obj += size) {
2319  ((TClass *)cl)->Streamer(obj, *this);
2320  }
2321 }
2322 
2323 ////////////////////////////////////////////////////////////////////////////////
2324 /// Write an array of object starting at the address '*start' and of length 'n'
2325 /// the objects in the array are of class 'cl'
2326 /// 'isPreAlloc' indicates whether the data member is marked with '->'
2327 /// Return:
2328 /// - 0: success
2329 /// - 2: truncated success (i.e actual class is missing. Only ptrClass saved.)
2330 
2331 Int_t TBufferXML::WriteFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc, TMemberStreamer *streamer)
2332 {
2333  // if isPreAlloc is true (data member has a ->) we can assume that the pointer
2334  // is never 0.
2335 
2336  Bool_t oldStyle = kFALSE; // flag used to reproduce old-style I/O actions for kSTLp
2337 
2338  if ((GetIOVersion() < 4) && !isPreAlloc) {
2339  TStreamerElement *elem = Stack()->fElem;
2340  if (elem && ((elem->GetType() == TStreamerInfo::kSTLp) ||
2341  (elem->GetType() == TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL)))
2342  oldStyle = kTRUE;
2343  }
2344 
2345  if (streamer) {
2346  (*streamer)(*this, (void *)start, oldStyle ? n : 0);
2347  return 0;
2348  }
2349 
2350  int strInfo = 0;
2351 
2352  Int_t res = 0;
2353 
2354  if (!isPreAlloc) {
2355 
2356  for (Int_t j = 0; j < n; j++) {
2357  // must write StreamerInfo if pointer is null
2358  if (!strInfo && !start[j] && !oldStyle) {
2359  if (cl->Property() & kIsAbstract) {
2360  // Do not try to generate the StreamerInfo for an abstract class
2361  } else {
2362  TStreamerInfo *info = (TStreamerInfo *)((TClass *)cl)->GetStreamerInfo();
2363  ForceWriteInfo(info, kFALSE);
2364  }
2365  }
2366  strInfo = 2003;
2367  if (oldStyle)
2368  ((TClass *)cl)->Streamer(start[j], *this);
2369  else
2370  res |= WriteObjectAny(start[j], cl);
2371  }
2372 
2373  } else {
2374  // case //-> in comment
2375 
2376  for (Int_t j = 0; j < n; j++) {
2377  if (!start[j])
2378  start[j] = ((TClass *)cl)->New();
2379  ((TClass *)cl)->Streamer(start[j], *this);
2380  }
2381  }
2382  return res;
2383 }
2384 
2385 ////////////////////////////////////////////////////////////////////////////////
2386 /// Stream object to/from buffer
2387 
2388 void TBufferXML::StreamObject(void *obj, const TClass *cl, const TClass * /* onfileClass */)
2389 {
2390  if (GetIOVersion() < 4) {
2391  TStreamerElement *elem = Stack()->fElem;
2392  if (elem && (elem->GetType() == TStreamerInfo::kTObject)) {
2393  ((TObject *)obj)->TObject::Streamer(*this);
2394  return;
2395  } else if (elem && (elem->GetType() == TStreamerInfo::kTNamed)) {
2396  ((TNamed *)obj)->TNamed::Streamer(*this);
2397  return;
2398  }
2399  }
2400 
2401  BeforeIOoperation();
2402  if (gDebug > 1)
2403  Info("StreamObject", "Class: %s", (cl ? cl->GetName() : "none"));
2404  if (IsReading())
2405  XmlReadObject(obj);
2406  else
2407  XmlWriteObject(obj, cl, kTRUE);
2408 }
2409 
2410 ////////////////////////////////////////////////////////////////////////////////
2411 /// Reads Bool_t value from buffer
2412 
2413 void TBufferXML::ReadBool(Bool_t &b)
2414 {
2415  BeforeIOoperation();
2416  XmlReadBasic(b);
2417 }
2418 
2419 ////////////////////////////////////////////////////////////////////////////////
2420 /// Reads Char_t value from buffer
2421 
2422 void TBufferXML::ReadChar(Char_t &c)
2423 {
2424  BeforeIOoperation();
2425  XmlReadBasic(c);
2426 }
2427 
2428 ////////////////////////////////////////////////////////////////////////////////
2429 /// Reads UChar_t value from buffer
2430 
2431 void TBufferXML::ReadUChar(UChar_t &c)
2432 {
2433  BeforeIOoperation();
2434  XmlReadBasic(c);
2435 }
2436 
2437 ////////////////////////////////////////////////////////////////////////////////
2438 /// Reads Short_t value from buffer
2439 
2440 void TBufferXML::ReadShort(Short_t &h)
2441 {
2442  BeforeIOoperation();
2443  XmlReadBasic(h);
2444 }
2445 
2446 ////////////////////////////////////////////////////////////////////////////////
2447 /// Reads UShort_t value from buffer
2448 
2449 void TBufferXML::ReadUShort(UShort_t &h)
2450 {
2451  BeforeIOoperation();
2452  XmlReadBasic(h);
2453 }
2454 
2455 ////////////////////////////////////////////////////////////////////////////////
2456 /// Reads Int_t value from buffer
2457 
2458 void TBufferXML::ReadInt(Int_t &i)
2459 {
2460  BeforeIOoperation();
2461  XmlReadBasic(i);
2462 }
2463 
2464 ////////////////////////////////////////////////////////////////////////////////
2465 /// Reads UInt_t value from buffer
2466 
2467 void TBufferXML::ReadUInt(UInt_t &i)
2468 {
2469  BeforeIOoperation();
2470  XmlReadBasic(i);
2471 }
2472 
2473 ////////////////////////////////////////////////////////////////////////////////
2474 /// Reads Long_t value from buffer
2475 
2476 void TBufferXML::ReadLong(Long_t &l)
2477 {
2478  BeforeIOoperation();
2479  XmlReadBasic(l);
2480 }
2481 
2482 ////////////////////////////////////////////////////////////////////////////////
2483 /// Reads ULong_t value from buffer
2484 
2485 void TBufferXML::ReadULong(ULong_t &l)
2486 {
2487  BeforeIOoperation();
2488  XmlReadBasic(l);
2489 }
2490 
2491 ////////////////////////////////////////////////////////////////////////////////
2492 /// Reads Long64_t value from buffer
2493 
2494 void TBufferXML::ReadLong64(Long64_t &l)
2495 {
2496  BeforeIOoperation();
2497  XmlReadBasic(l);
2498 }
2499 
2500 ////////////////////////////////////////////////////////////////////////////////
2501 /// Reads ULong64_t value from buffer
2502 
2503 void TBufferXML::ReadULong64(ULong64_t &l)
2504 {
2505  BeforeIOoperation();
2506  XmlReadBasic(l);
2507 }
2508 
2509 ////////////////////////////////////////////////////////////////////////////////
2510 /// Reads Float_t value from buffer
2511 
2512 void TBufferXML::ReadFloat(Float_t &f)
2513 {
2514  BeforeIOoperation();
2515  XmlReadBasic(f);
2516 }
2517 
2518 ////////////////////////////////////////////////////////////////////////////////
2519 /// Reads Double_t value from buffer
2520 
2521 void TBufferXML::ReadDouble(Double_t &d)
2522 {
2523  BeforeIOoperation();
2524  XmlReadBasic(d);
2525 }
2526 
2527 ////////////////////////////////////////////////////////////////////////////////
2528 /// Reads array of characters from buffer
2529 
2530 void TBufferXML::ReadCharP(Char_t *c)
2531 {
2532  BeforeIOoperation();
2533  const char *buf;
2534  if ((buf = XmlReadValue(xmlio::CharStar)))
2535  strcpy(c, buf);
2536 }
2537 
2538 ////////////////////////////////////////////////////////////////////////////////
2539 /// Reads a TString
2540 
2541 void TBufferXML::ReadTString(TString &s)
2542 {
2543  if (GetIOVersion() < 3) {
2544  // original TBufferFile method can not be used, while used TString methods are private
2545  // try to reimplement close to the original
2546  Int_t nbig;
2547  UChar_t nwh;
2548  *this >> nwh;
2549  if (nwh == 0) {
2550  s.Resize(0);
2551  } else {
2552  if (nwh == 255)
2553  *this >> nbig;
2554  else
2555  nbig = nwh;
2556 
2557  char *data = new char[nbig];
2558  data[nbig] = 0;
2559  ReadFastArray(data, nbig);
2560  s = data;
2561  delete[] data;
2562  }
2563  } else {
2564  BeforeIOoperation();
2565  const char *buf = XmlReadValue(xmlio::String);
2566  if (buf)
2567  s = buf;
2568  }
2569 }
2570 
2571 ////////////////////////////////////////////////////////////////////////////////
2572 /// Reads a std::string
2573 
2574 void TBufferXML::ReadStdString(std::string *obj)
2575 {
2576  if (GetIOVersion() < 3) {
2577  if (!obj) {
2578  Error("ReadStdString", "The std::string address is nullptr but should not");
2579  return;
2580  }
2581  Int_t nbig;
2582  UChar_t nwh;
2583  *this >> nwh;
2584  if (nwh == 0) {
2585  obj->clear();
2586  } else {
2587  if (obj->size()) {
2588  // Insure that the underlying data storage is not shared
2589  (*obj)[0] = '\0';
2590  }
2591  if (nwh == 255) {
2592  *this >> nbig;
2593  obj->resize(nbig, '\0');
2594  ReadFastArray((char *)obj->data(), nbig);
2595  } else {
2596  obj->resize(nwh, '\0');
2597  ReadFastArray((char *)obj->data(), nwh);
2598  }
2599  }
2600  } else {
2601  BeforeIOoperation();
2602  const char *buf = XmlReadValue(xmlio::String);
2603  if (buf && obj)
2604  *obj = buf;
2605  }
2606 }
2607 
2608 ////////////////////////////////////////////////////////////////////////////////
2609 /// Read a char* string
2610 
2611 void TBufferXML::ReadCharStar(char *&s)
2612 {
2613  delete[] s;
2614  s = nullptr;
2615 
2616  Int_t nch;
2617  *this >> nch;
2618  if (nch > 0) {
2619  s = new char[nch + 1];
2620  ReadFastArray(s, nch);
2621  s[nch] = 0;
2622  }
2623 }
2624 
2625 ////////////////////////////////////////////////////////////////////////////////
2626 /// Writes Bool_t value to buffer
2627 
2628 void TBufferXML::WriteBool(Bool_t b)
2629 {
2630  BeforeIOoperation();
2631  XmlWriteBasic(b);
2632 }
2633 
2634 ////////////////////////////////////////////////////////////////////////////////
2635 /// Writes Char_t value to buffer
2636 
2637 void TBufferXML::WriteChar(Char_t c)
2638 {
2639  BeforeIOoperation();
2640  XmlWriteBasic(c);
2641 }
2642 
2643 ////////////////////////////////////////////////////////////////////////////////
2644 /// Writes UChar_t value to buffer
2645 
2646 void TBufferXML::WriteUChar(UChar_t c)
2647 {
2648  BeforeIOoperation();
2649  XmlWriteBasic(c);
2650 }
2651 
2652 ////////////////////////////////////////////////////////////////////////////////
2653 /// Writes Short_t value to buffer
2654 
2655 void TBufferXML::WriteShort(Short_t h)
2656 {
2657  BeforeIOoperation();
2658  XmlWriteBasic(h);
2659 }
2660 
2661 ////////////////////////////////////////////////////////////////////////////////
2662 /// Writes UShort_t value to buffer
2663 
2664 void TBufferXML::WriteUShort(UShort_t h)
2665 {
2666  BeforeIOoperation();
2667  XmlWriteBasic(h);
2668 }
2669 
2670 ////////////////////////////////////////////////////////////////////////////////
2671 /// Writes Int_t value to buffer
2672 
2673 void TBufferXML::WriteInt(Int_t i)
2674 {
2675  BeforeIOoperation();
2676  XmlWriteBasic(i);
2677 }
2678 
2679 ////////////////////////////////////////////////////////////////////////////////
2680 /// Writes UInt_t value to buffer
2681 
2682 void TBufferXML::WriteUInt(UInt_t i)
2683 {
2684  BeforeIOoperation();
2685  XmlWriteBasic(i);
2686 }
2687 
2688 ////////////////////////////////////////////////////////////////////////////////
2689 /// Writes Long_t value to buffer
2690 
2691 void TBufferXML::WriteLong(Long_t l)
2692 {
2693  BeforeIOoperation();
2694  XmlWriteBasic(l);
2695 }
2696 
2697 ////////////////////////////////////////////////////////////////////////////////
2698 /// Writes ULong_t value to buffer
2699 
2700 void TBufferXML::WriteULong(ULong_t l)
2701 {
2702  BeforeIOoperation();
2703  XmlWriteBasic(l);
2704 }
2705 
2706 ////////////////////////////////////////////////////////////////////////////////
2707 /// Writes Long64_t value to buffer
2708 
2709 void TBufferXML::WriteLong64(Long64_t l)
2710 {
2711  BeforeIOoperation();
2712  XmlWriteBasic(l);
2713 }
2714 
2715 ////////////////////////////////////////////////////////////////////////////////
2716 /// Writes ULong64_t value to buffer
2717 
2718 void TBufferXML::WriteULong64(ULong64_t l)
2719 {
2720  BeforeIOoperation();
2721  XmlWriteBasic(l);
2722 }
2723 
2724 ////////////////////////////////////////////////////////////////////////////////
2725 /// Writes Float_t value to buffer
2726 
2727 void TBufferXML::WriteFloat(Float_t f)
2728 {
2729  BeforeIOoperation();
2730  XmlWriteBasic(f);
2731 }
2732 
2733 ////////////////////////////////////////////////////////////////////////////////
2734 /// Writes Double_t value to buffer
2735 
2736 void TBufferXML::WriteDouble(Double_t d)
2737 {
2738  BeforeIOoperation();
2739  XmlWriteBasic(d);
2740 }
2741 
2742 ////////////////////////////////////////////////////////////////////////////////
2743 /// Writes array of characters to buffer
2744 
2745 void TBufferXML::WriteCharP(const Char_t *c)
2746 {
2747  BeforeIOoperation();
2748  XmlWriteValue(c, xmlio::CharStar);
2749 }
2750 
2751 ////////////////////////////////////////////////////////////////////////////////
2752 /// Writes a TString
2753 
2754 void TBufferXML::WriteTString(const TString &s)
2755 {
2756  if (GetIOVersion() < 3) {
2757  // original TBufferFile method, keep for compatibility
2758  Int_t nbig = s.Length();
2759  UChar_t nwh;
2760  if (nbig > 254) {
2761  nwh = 255;
2762  *this << nwh;
2763  *this << nbig;
2764  } else {
2765  nwh = UChar_t(nbig);
2766  *this << nwh;
2767  }
2768  const char *data = s.Data();
2769  WriteFastArray(data, nbig);
2770  } else {
2771  BeforeIOoperation();
2772  XmlWriteValue(s.Data(), xmlio::String);
2773  }
2774 }
2775 
2776 ////////////////////////////////////////////////////////////////////////////////
2777 /// Writes a std::string
2778 
2779 void TBufferXML::WriteStdString(const std::string *obj)
2780 {
2781  if (GetIOVersion() < 3) {
2782  if (!obj) {
2783  *this << (UChar_t)0;
2784  WriteFastArray("", 0);
2785  return;
2786  }
2787 
2788  UChar_t nwh;
2789  Int_t nbig = obj->length();
2790  if (nbig > 254) {
2791  nwh = 255;
2792  *this << nwh;
2793  *this << nbig;
2794  } else {
2795  nwh = UChar_t(nbig);
2796  *this << nwh;
2797  }
2798  WriteFastArray(obj->data(), nbig);
2799  } else {
2800  BeforeIOoperation();
2801  XmlWriteValue(obj ? obj->c_str() : "", xmlio::String);
2802  }
2803 }
2804 
2805 ////////////////////////////////////////////////////////////////////////////////
2806 /// Write a char* string
2807 
2808 void TBufferXML::WriteCharStar(char *s)
2809 {
2810  Int_t nch = 0;
2811  if (s) {
2812  nch = strlen(s);
2813  *this << nch;
2814  WriteFastArray(s, nch);
2815  } else {
2816  *this << nch;
2817  }
2818 }
2819 
2820 ////////////////////////////////////////////////////////////////////////////////
2821 /// Converts Char_t to string and add xml node to buffer
2822 
2823 XMLNodePointer_t TBufferXML::XmlWriteBasic(Char_t value)
2824 {
2825  char buf[50];
2826  snprintf(buf, sizeof(buf), "%d", value);
2827  return XmlWriteValue(buf, xmlio::Char);
2828 }
2829 
2830 ////////////////////////////////////////////////////////////////////////////////
2831 /// Converts Short_t to string and add xml node to buffer
2832 
2833 XMLNodePointer_t TBufferXML::XmlWriteBasic(Short_t value)
2834 {
2835  char buf[50];
2836  snprintf(buf, sizeof(buf), "%hd", value);
2837  return XmlWriteValue(buf, xmlio::Short);
2838 }
2839 
2840 ////////////////////////////////////////////////////////////////////////////////
2841 /// Converts Int_t to string and add xml node to buffer
2842 
2843 XMLNodePointer_t TBufferXML::XmlWriteBasic(Int_t value)
2844 {
2845  char buf[50];
2846  snprintf(buf, sizeof(buf), "%d", value);
2847  return XmlWriteValue(buf, xmlio::Int);
2848 }
2849 
2850 ////////////////////////////////////////////////////////////////////////////////
2851 /// Converts Long_t to string and add xml node to buffer
2852 
2853 XMLNodePointer_t TBufferXML::XmlWriteBasic(Long_t value)
2854 {
2855  char buf[50];
2856  snprintf(buf, sizeof(buf), "%ld", value);
2857  return XmlWriteValue(buf, xmlio::Long);
2858 }
2859 
2860 ////////////////////////////////////////////////////////////////////////////////
2861 /// Converts Long64_t to string and add xml node to buffer
2862 
2863 XMLNodePointer_t TBufferXML::XmlWriteBasic(Long64_t value)
2864 {
2865  std::string buf = std::to_string(value);
2866  return XmlWriteValue(buf.c_str(), xmlio::Long64);
2867 }
2868 
2869 ////////////////////////////////////////////////////////////////////////////////
2870 /// Converts Float_t to string and add xml node to buffer
2871 
2872 XMLNodePointer_t TBufferXML::XmlWriteBasic(Float_t value)
2873 {
2874  char buf[200];
2875  ConvertFloat(value, buf, sizeof(buf), kTRUE);
2876  return XmlWriteValue(buf, xmlio::Float);
2877 }
2878 
2879 ////////////////////////////////////////////////////////////////////////////////
2880 /// Converts Double_t to string and add xml node to buffer
2881 
2882 XMLNodePointer_t TBufferXML::XmlWriteBasic(Double_t value)
2883 {
2884  char buf[1000];
2885  ConvertDouble(value, buf, sizeof(buf), kTRUE);
2886  return XmlWriteValue(buf, xmlio::Double);
2887 }
2888 
2889 ////////////////////////////////////////////////////////////////////////////////
2890 /// Converts Bool_t to string and add xml node to buffer
2891 
2892 XMLNodePointer_t TBufferXML::XmlWriteBasic(Bool_t value)
2893 {
2894  return XmlWriteValue(value ? xmlio::True : xmlio::False, xmlio::Bool);
2895 }
2896 
2897 ////////////////////////////////////////////////////////////////////////////////
2898 /// Converts UChar_t to string and add xml node to buffer
2899 
2900 XMLNodePointer_t TBufferXML::XmlWriteBasic(UChar_t value)
2901 {
2902  char buf[50];
2903  snprintf(buf, sizeof(buf), "%u", value);
2904  return XmlWriteValue(buf, xmlio::UChar);
2905 }
2906 
2907 ////////////////////////////////////////////////////////////////////////////////
2908 /// Converts UShort_t to string and add xml node to buffer
2909 
2910 XMLNodePointer_t TBufferXML::XmlWriteBasic(UShort_t value)
2911 {
2912  char buf[50];
2913  snprintf(buf, sizeof(buf), "%hu", value);
2914  return XmlWriteValue(buf, xmlio::UShort);
2915 }
2916 
2917 ////////////////////////////////////////////////////////////////////////////////
2918 /// Converts UInt_t to string and add xml node to buffer
2919 
2920 XMLNodePointer_t TBufferXML::XmlWriteBasic(UInt_t value)
2921 {
2922  char buf[50];
2923  snprintf(buf, sizeof(buf), "%u", value);
2924  return XmlWriteValue(buf, xmlio::UInt);
2925 }
2926 
2927 ////////////////////////////////////////////////////////////////////////////////
2928 /// Converts ULong_t to string and add xml node to buffer
2929 
2930 XMLNodePointer_t TBufferXML::XmlWriteBasic(ULong_t value)
2931 {
2932  char buf[50];
2933  snprintf(buf, sizeof(buf), "%lu", value);
2934  return XmlWriteValue(buf, xmlio::ULong);
2935 }
2936 
2937 ////////////////////////////////////////////////////////////////////////////////
2938 /// Converts ULong64_t to string and add xml node to buffer
2939 
2940 XMLNodePointer_t TBufferXML::XmlWriteBasic(ULong64_t value)
2941 {
2942  std::string buf = std::to_string(value);
2943  return XmlWriteValue(buf.c_str(), xmlio::ULong64);
2944 }
2945 
2946 ////////////////////////////////////////////////////////////////////////////////
2947 /// Create xml node with specified name and adds it to stack node
2948 
2949 XMLNodePointer_t TBufferXML::XmlWriteValue(const char *value, const char *name)
2950 {
2951  XMLNodePointer_t node = nullptr;
2952 
2953  if (fCanUseCompact)
2954  node = StackNode();
2955  else
2956  node = CreateItemNode(name);
2957 
2958  fXML->NewAttr(node, nullptr, xmlio::v, value);
2959 
2960  fCanUseCompact = kFALSE;
2961 
2962  return node;
2963 }
2964 
2965 ////////////////////////////////////////////////////////////////////////////////
2966 /// Reads string from current xml node and convert it to Char_t value
2967 
2968 void TBufferXML::XmlReadBasic(Char_t &value)
2969 {
2970  const char *res = XmlReadValue(xmlio::Char);
2971  if (res) {
2972  int n;
2973  sscanf(res, "%d", &n);
2974  value = n;
2975  } else
2976  value = 0;
2977 }
2978 
2979 ////////////////////////////////////////////////////////////////////////////////
2980 /// Reads string from current xml node and convert it to Short_t value
2981 
2982 void TBufferXML::XmlReadBasic(Short_t &value)
2983 {
2984  const char *res = XmlReadValue(xmlio::Short);
2985  if (res)
2986  sscanf(res, "%hd", &value);
2987  else
2988  value = 0;
2989 }
2990 
2991 ////////////////////////////////////////////////////////////////////////////////
2992 /// Reads string from current xml node and convert it to Int_t value
2993 
2994 void TBufferXML::XmlReadBasic(Int_t &value)
2995 {
2996  const char *res = XmlReadValue(xmlio::Int);
2997  if (res)
2998  sscanf(res, "%d", &value);
2999  else
3000  value = 0;
3001 }
3002 
3003 ////////////////////////////////////////////////////////////////////////////////
3004 /// Reads string from current xml node and convert it to Long_t value
3005 
3006 void TBufferXML::XmlReadBasic(Long_t &value)
3007 {
3008  const char *res = XmlReadValue(xmlio::Long);
3009  if (res)
3010  sscanf(res, "%ld", &value);
3011  else
3012  value = 0;
3013 }
3014 
3015 ////////////////////////////////////////////////////////////////////////////////
3016 /// Reads string from current xml node and convert it to Long64_t value
3017 
3018 void TBufferXML::XmlReadBasic(Long64_t &value)
3019 {
3020  const char *res = XmlReadValue(xmlio::Long64);
3021  if (res)
3022  value = (Long64_t)std::stoll(res);
3023  else
3024  value = 0;
3025 }
3026 
3027 ////////////////////////////////////////////////////////////////////////////////
3028 /// Reads string from current xml node and convert it to Float_t value
3029 
3030 void TBufferXML::XmlReadBasic(Float_t &value)
3031 {
3032  const char *res = XmlReadValue(xmlio::Float);
3033  if (res)
3034  sscanf(res, "%f", &value);
3035  else
3036  value = 0.;
3037 }
3038 
3039 ////////////////////////////////////////////////////////////////////////////////
3040 /// Reads string from current xml node and convert it to Double_t value
3041 
3042 void TBufferXML::XmlReadBasic(Double_t &value)
3043 {
3044  const char *res = XmlReadValue(xmlio::Double);
3045  if (res)
3046  sscanf(res, "%lf", &value);
3047  else
3048  value = 0.;
3049 }
3050 
3051 ////////////////////////////////////////////////////////////////////////////////
3052 /// Reads string from current xml node and convert it to Bool_t value
3053 
3054 void TBufferXML::XmlReadBasic(Bool_t &value)
3055 {
3056  const char *res = XmlReadValue(xmlio::Bool);
3057  if (res)
3058  value = (strcmp(res, xmlio::True) == 0);
3059  else
3060  value = kFALSE;
3061 }
3062 
3063 ////////////////////////////////////////////////////////////////////////////////
3064 /// Reads string from current xml node and convert it to UChar_t value
3065 
3066 void TBufferXML::XmlReadBasic(UChar_t &value)
3067 {
3068  const char *res = XmlReadValue(xmlio::UChar);
3069  if (res) {
3070  unsigned int n;
3071  sscanf(res, "%ud", &n);
3072  value = n;
3073  } else
3074  value = 0;
3075 }
3076 
3077 ////////////////////////////////////////////////////////////////////////////////
3078 /// Reads string from current xml node and convert it to UShort_t value
3079 
3080 void TBufferXML::XmlReadBasic(UShort_t &value)
3081 {
3082  const char *res = XmlReadValue(xmlio::UShort);
3083  if (res)
3084  sscanf(res, "%hud", &value);
3085  else
3086  value = 0;
3087 }
3088 
3089 ////////////////////////////////////////////////////////////////////////////////
3090 /// Reads string from current xml node and convert it to UInt_t value
3091 
3092 void TBufferXML::XmlReadBasic(UInt_t &value)
3093 {
3094  const char *res = XmlReadValue(xmlio::UInt);
3095  if (res)
3096  sscanf(res, "%u", &value);
3097  else
3098  value = 0;
3099 }
3100 
3101 ////////////////////////////////////////////////////////////////////////////////
3102 /// Reads string from current xml node and convert it to ULong_t value
3103 
3104 void TBufferXML::XmlReadBasic(ULong_t &value)
3105 {
3106  const char *res = XmlReadValue(xmlio::ULong);
3107  if (res)
3108  sscanf(res, "%lu", &value);
3109  else
3110  value = 0;
3111 }
3112 
3113 ////////////////////////////////////////////////////////////////////////////////
3114 /// Reads string from current xml node and convert it to ULong64_t value
3115 
3116 void TBufferXML::XmlReadBasic(ULong64_t &value)
3117 {
3118  const char *res = XmlReadValue(xmlio::ULong64);
3119  if (res)
3120  value = (ULong64_t)std::stoull(res);
3121  else
3122  value = 0;
3123 }
3124 
3125 ////////////////////////////////////////////////////////////////////////////////
3126 /// read string value from current stack node
3127 
3128 const char *TBufferXML::XmlReadValue(const char *name)
3129 {
3130  if (fErrorFlag > 0)
3131  return 0;
3132 
3133  Bool_t trysimple = fCanUseCompact;
3134  fCanUseCompact = kFALSE;
3135 
3136  if (trysimple) {
3137  if (fXML->HasAttr(Stack(1)->fNode, xmlio::v))
3138  fValueBuf = fXML->GetAttr(Stack(1)->fNode, xmlio::v);
3139  else
3140  trysimple = kFALSE;
3141  }
3142 
3143  if (!trysimple) {
3144  if (!VerifyItemNode(name, "XmlReadValue"))
3145  return 0;
3146  fValueBuf = fXML->GetAttr(StackNode(), xmlio::v);
3147  }
3148 
3149  if (gDebug > 4)
3150  Info("XmlReadValue", " Name = %s value = %s", name, fValueBuf.Data());
3151 
3152  if (!trysimple)
3153  ShiftStack("readvalue");
3154 
3155  return fValueBuf.Data();
3156 }
3157 
3158 ////////////////////////////////////////////////////////////////////////////////
3159 /// Return current streamer info element
3160 
3161 TVirtualStreamerInfo *TBufferXML::GetInfo()
3162 {
3163  return Stack()->fInfo;
3164 }