Logo ROOT  
Reference Guide
TBufferJSON.cxx
Go to the documentation of this file.
1 //
2 // Author: Sergey Linev 4.03.2014
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2019, 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 TBufferJSON
14 \ingroup IO
15 
16 Class for serializing object to and from JavaScript Object Notation (JSON) format.
17 It creates such object representation, which can be directly
18 used in JavaScript ROOT (JSROOT) for drawing.
19 
20 TBufferJSON implements TBuffer interface, therefore most of
21 ROOT and user classes can be converted into JSON.
22 There are certain limitations for classes with custom streamers,
23 which should be equipped specially for this purposes (see TCanvas::Streamer()
24 as example).
25 
26 To perform conversion into JSON, one should use TBufferJSON::ToJSON method:
27 ~~~{.cpp}
28  TH1 *h1 = new TH1I("h1", "title", 100, 0, 10);
29  h1->FillRandom("gaus",10000);
30  TString json = TBufferJSON::ToJSON(h1);
31 ~~~
32 
33 To reconstruct object from the JSON string, one should do:
34 ~~~{.cpp}
35  TH1 *hnew = nullptr;
36  TBufferJSON::FromJSON(hnew, json);
37  if (hnew) hnew->Draw("hist");
38 ~~~
39 JSON does not include stored class version, therefore schema evolution
40 (reading of older class versions) is not supported. JSON should not be used as
41 persistent storage for object data - only for live applications.
42 
43 All STL containers by default converted into JSON Array. Vector of integers:
44 ~~~{.cpp}
45  std::vector<int> vect = {1,4,7};
46  auto json = TBufferJSON::ToJSON(&vect);
47 ~~~
48 Will produce JSON code "[1, 4, 7]".
49 
50 There are special handling for map classes like `map` and `multimap`.
51 They will create Array of pair objects with "first" and "second" as data members. Code:
52 ~~~{.cpp}
53  std::map<int,string> m;
54  m[1] = "number 1";
55  m[2] = "number 2";
56  auto json = TBufferJSON::ToJSON(&m);
57 ~~~
58 Will generate json string:
59 ~~~{.json}
60 [
61  {"$pair" : "pair<int,string>", "first" : 1, "second" : "number 1"},
62  {"$pair" : "pair<int,string>", "first" : 2, "second" : "number 2"}
63 ]
64 ~~~
65 In special cases map container can be converted into JSON object. For that key parameter
66 must be `std::string` and compact parameter should be 5.
67 Like in example:
68 ~~~{.cpp}
69 std::map<std::string,int> data;
70 data["name1"] = 11;
71 data["name2"] = 22;
72 
73 auto json = TBufferJSON::ToJSON(&data, TBufferJSON::kMapAsObject);
74 ~~~
75 Will produce JSON output:
76 ~~~
77 {
78  "_typename": "map<string,int>",
79  "name1": 11,
80  "name2": 22
81 }
82 ~~~
83 Another possibility to enforce such conversion - add "JSON_object" into comment line of correspondent
84 data member like:
85 ~~~{.cpp}
86 class Container {
87  std::map<std::string,int> data; ///< JSON_object
88 };
89 ~~~
90 
91 */
92 
93 #include "TBufferJSON.h"
94 
95 #include <typeinfo>
96 #include <string>
97 #include <cstring>
98 #include <locale.h>
99 #include <cmath>
100 #include <memory>
101 #include <cstdlib>
102 #include <fstream>
103 
104 #include <ROOT/RMakeUnique.hxx>
105 
106 #include "Compression.h"
107 
108 #include "TArrayI.h"
109 #include "TError.h"
110 #include "TBase64.h"
111 #include "TROOT.h"
112 #include "TList.h"
113 #include "TClass.h"
114 #include "TClassTable.h"
115 #include "TClassEdit.h"
116 #include "TDataType.h"
117 #include "TRealData.h"
118 #include "TDataMember.h"
119 #include "TMap.h"
120 #include "TRef.h"
121 #include "TStreamerInfo.h"
122 #include "TStreamerElement.h"
123 #include "TMemberStreamer.h"
124 #include "TStreamer.h"
125 #include "RZip.h"
126 #include "TClonesArray.h"
127 #include "TVirtualMutex.h"
128 #include "TInterpreter.h"
130 #include "snprintf.h"
131 
132 #include "json.hpp"
133 
135 
136 enum { json_TArray = 100, json_TCollection = -130, json_TString = 110, json_stdstring = 120 };
137 
138 ///////////////////////////////////////////////////////////////
139 // TArrayIndexProducer is used to correctly create
140 /// JSON array separators for multi-dimensional JSON arrays
141 /// It fully reproduces array dimensions as in original ROOT classes
142 /// Contrary to binary I/O, which always writes flat arrays
143 
144 class TArrayIndexProducer {
145 protected:
146  Int_t fTotalLen{0};
147  Int_t fCnt{-1};
148  const char *fSepar{nullptr};
149  TArrayI fIndicies;
150  TArrayI fMaxIndex;
151  TString fRes;
152  Bool_t fIsArray{kFALSE};
153 
154 public:
155  TArrayIndexProducer(TStreamerElement *elem, Int_t arraylen, const char *separ) : fSepar(separ)
156  {
157  Bool_t usearrayindx = elem && (elem->GetArrayDim() > 0);
158  Bool_t isloop = elem && ((elem->GetType() == TStreamerInfo::kStreamLoop) ||
160  Bool_t usearraylen = (arraylen > (isloop ? 0 : 1));
161 
162  if (usearrayindx && (arraylen > 0)) {
163  if (isloop) {
164  usearrayindx = kFALSE;
165  usearraylen = kTRUE;
166  } else if (arraylen != elem->GetArrayLength()) {
167  ::Error("TArrayIndexProducer", "Problem with JSON coding of element %s type %d", elem->GetName(),
168  elem->GetType());
169  }
170  }
171 
172  if (usearrayindx) {
173  fTotalLen = elem->GetArrayLength();
174  fMaxIndex.Set(elem->GetArrayDim());
175  for (int dim = 0; dim < elem->GetArrayDim(); dim++)
176  fMaxIndex[dim] = elem->GetMaxIndex(dim);
177  fIsArray = fTotalLen > 1;
178  } else if (usearraylen) {
179  fTotalLen = arraylen;
180  fMaxIndex.Set(1);
181  fMaxIndex[0] = arraylen;
182  fIsArray = kTRUE;
183  }
184 
185  if (fMaxIndex.GetSize() > 0) {
186  fIndicies.Set(fMaxIndex.GetSize());
187  fIndicies.Reset(0);
188  }
189  }
190 
191  TArrayIndexProducer(TDataMember *member, Int_t extradim, const char *separ) : fSepar(separ)
192  {
193  Int_t ndim = member->GetArrayDim();
194  if (extradim > 0)
195  ndim++;
196 
197  if (ndim > 0) {
198  fIndicies.Set(ndim);
199  fIndicies.Reset(0);
200  fMaxIndex.Set(ndim);
201  fTotalLen = 1;
202  for (int dim = 0; dim < member->GetArrayDim(); dim++) {
203  fMaxIndex[dim] = member->GetMaxIndex(dim);
204  fTotalLen *= member->GetMaxIndex(dim);
205  }
206 
207  if (extradim > 0) {
208  fMaxIndex[ndim - 1] = extradim;
209  fTotalLen *= extradim;
210  }
211  }
212  fIsArray = fTotalLen > 1;
213  }
214 
215  /// returns number of array dimensions
216  Int_t NumDimensions() const { return fIndicies.GetSize(); }
217 
218  /// return array with current index
219  TArrayI &GetIndices() { return fIndicies; };
220 
221  /// returns total number of elements in array
222  Int_t TotalLength() const { return fTotalLen; }
223 
224  Int_t ReduceDimension()
225  {
226  // reduce one dimension of the array
227  // return size of reduced dimension
228  if (fMaxIndex.GetSize() == 0)
229  return 0;
230  Int_t ndim = fMaxIndex.GetSize() - 1;
231  Int_t len = fMaxIndex[ndim];
232  fMaxIndex.Set(ndim);
233  fIndicies.Set(ndim);
234  fTotalLen = fTotalLen / len;
235  fIsArray = fTotalLen > 1;
236  return len;
237  }
238 
239  Bool_t IsArray() const { return fIsArray; }
240 
241  Bool_t IsDone() const
242  {
243  // return true when iteration over all arrays indexes are done
244  return !IsArray() || (fCnt >= fTotalLen);
245  }
246 
247  const char *GetBegin()
248  {
249  ++fCnt;
250  // return starting separator
251  fRes.Clear();
252  for (Int_t n = 0; n < fIndicies.GetSize(); ++n)
253  fRes.Append("[");
254  return fRes.Data();
255  }
256 
257  const char *GetEnd()
258  {
259  // return ending separator
260  fRes.Clear();
261  for (Int_t n = 0; n < fIndicies.GetSize(); ++n)
262  fRes.Append("]");
263  return fRes.Data();
264  }
265 
266  /// increment indexes and returns intermediate or last separator
267  const char *NextSeparator()
268  {
269  if (++fCnt >= fTotalLen)
270  return GetEnd();
271 
272  Int_t cnt = fIndicies.GetSize() - 1;
273  fIndicies[cnt]++;
274 
275  fRes.Clear();
276 
277  while ((cnt >= 0) && (cnt < fIndicies.GetSize())) {
278  if (fIndicies[cnt] >= fMaxIndex[cnt]) {
279  fRes.Append("]");
280  fIndicies[cnt--] = 0;
281  if (cnt >= 0)
282  fIndicies[cnt]++;
283  continue;
284  }
285  fRes.Append(fIndicies[cnt] == 0 ? "[" : fSepar);
286  cnt++;
287  }
288  return fRes.Data();
289  }
290 
291  nlohmann::json *ExtractNode(nlohmann::json *topnode, bool next = true)
292  {
293  if (!IsArray())
294  return topnode;
295  nlohmann::json *subnode = &((*((nlohmann::json *)topnode))[fIndicies[0]]);
296  for (int k = 1; k < fIndicies.GetSize(); ++k)
297  subnode = &((*subnode)[fIndicies[k]]);
298  if (next)
299  NextSeparator();
300  return subnode;
301  }
302 };
303 
304 // TJSONStackObj is used to keep stack of object hierarchy,
305 // stored in TBuffer. For instance, data for parent class(es)
306 // stored in subnodes, but initial object node will be kept.
307 
308 class TJSONStackObj : public TObject {
309  struct StlRead {
310  Int_t fIndx{0}; //! index of object in STL container
311  Int_t fMap{0}; //! special iterator over STL map::key members
312  Bool_t fFirst{kTRUE}; //! is first or second element is used in the pair
313  nlohmann::json::iterator fIter; //! iterator for std::map stored as JSON object
314  const char *fTypeTag{nullptr}; //! type tag used for std::map stored as JSON object
315  nlohmann::json fValue; //! temporary value reading std::map as JSON
316  nlohmann::json *GetStlNode(nlohmann::json *prnt)
317  {
318  if (fMap <= 0)
319  return &(prnt->at(fIndx++));
320 
321  if (fMap == 1) {
322  nlohmann::json *json = &(prnt->at(fIndx));
323  if (!fFirst) fIndx++;
324  json = &(json->at(fFirst ? "first" : "second"));
325  fFirst = !fFirst;
326  return json;
327  }
328 
329  if (fIndx == 0) {
330  // skip _typename if appears
331  if (fTypeTag && (fIter.key().compare(fTypeTag) == 0))
332  ++fIter;
333  fValue = fIter.key();
334  fIndx++;
335  } else {
336  fValue = fIter.value();
337  ++fIter;
338  fIndx = 0;
339  }
340  return &fValue;
341  }
342  };
343 
344 public:
345  TStreamerInfo *fInfo{nullptr}; //!
346  TStreamerElement *fElem{nullptr}; //! element in streamer info
347  Bool_t fIsStreamerInfo{kFALSE}; //!
348  Bool_t fIsElemOwner{kFALSE}; //!
349  Bool_t fIsPostProcessed{kFALSE}; //! indicate that value is written
350  Bool_t fIsObjStarted{kFALSE}; //! indicate that object writing started, should be closed in postprocess
351  Bool_t fAccObjects{kFALSE}; //! if true, accumulate whole objects in values
352  Bool_t fBase64{kFALSE}; //! enable base64 coding when writing array
353  std::vector<std::string> fValues; //! raw values
354  int fMemberCnt{1}; //! count number of object members, normally _typename is first member
355  int *fMemberPtr{nullptr}; //! pointer on members counter, can be inherit from parent stack objects
356  Int_t fLevel{0}; //! indent level
357  std::unique_ptr<TArrayIndexProducer> fIndx; //! producer of ndim indexes
358  nlohmann::json *fNode{nullptr}; //! JSON node, used for reading
359  std::unique_ptr<StlRead> fStlRead; //! custom structure for stl container reading
360  Version_t fClVersion{0}; //! keep actual class version, workaround for ReadVersion in custom streamer
361 
362  TJSONStackObj() = default;
363 
364  ~TJSONStackObj()
365  {
366  if (fIsElemOwner)
367  delete fElem;
368  }
369 
370  Bool_t IsStreamerInfo() const { return fIsStreamerInfo; }
371 
372  Bool_t IsStreamerElement() const { return !fIsStreamerInfo && fElem; }
373 
374  void PushValue(TString &v)
375  {
376  fValues.emplace_back(v.Data());
377  v.Clear();
378  }
379 
380  void PushIntValue(Int_t v) { fValues.emplace_back(std::to_string(v)); }
381 
382  ////////////////////////////////////////////////////////////////////////
383  /// returns separator for data members
384  const char *NextMemberSeparator()
385  {
386  return (!fMemberPtr || ((*fMemberPtr)++ > 0)) ? "," : "";
387  }
388 
389  Bool_t IsJsonString() { return fNode && fNode->is_string(); }
390 
391  ////////////////////////////////////////////////////////////////////////
392  /// checks if specified JSON node is array (compressed or not compressed)
393  /// returns length of array (or -1 if failure)
394  Int_t IsJsonArray(nlohmann::json *json = nullptr, const char *map_convert_type = nullptr)
395  {
396  if (!json)
397  json = fNode;
398 
399  if (map_convert_type) {
400  if (!json->is_object()) return -1;
401  int sz = 0;
402  // count size of object, excluding _typename tag
403  for (auto it = json->begin(); it != json->end(); ++it) {
404  if ((strlen(map_convert_type)==0) || (it.key().compare(map_convert_type) != 0)) sz++;
405  }
406  return sz;
407  }
408 
409  // normal uncompressed array
410  if (json->is_array())
411  return json->size();
412 
413  // compressed array, full array length in "len" attribute, only ReadFastArray
414  if (json->is_object() && (json->count("$arr") == 1))
415  return json->at("len").get<int>();
416 
417  return -1;
418  }
419 
420  Int_t PopIntValue()
421  {
422  auto res = std::stoi(fValues.back());
423  fValues.pop_back();
424  return res;
425  }
426 
427  std::unique_ptr<TArrayIndexProducer> MakeReadIndexes()
428  {
429  if (!fElem || (fElem->GetType() <= TStreamerInfo::kOffsetL) ||
430  (fElem->GetType() >= TStreamerInfo::kOffsetL + 20) || (fElem->GetArrayDim() < 2))
431  return nullptr;
432 
433  auto indx = std::make_unique<TArrayIndexProducer>(fElem, -1, "");
434 
435  // no need for single dimension - it can be handled directly
436  if (!indx->IsArray() || (indx->NumDimensions() < 2))
437  return nullptr;
438 
439  return indx;
440  }
441 
442  Bool_t IsStl() const { return fStlRead.get() != nullptr; }
443 
444  Bool_t AssignStl(TClass *cl, Int_t map_convert, const char *typename_tag)
445  {
446  fStlRead = std::make_unique<StlRead>();
447  fStlRead->fMap = map_convert;
448  if (map_convert == 2) {
449  if (!fNode->is_object()) {
450  ::Error("TJSONStackObj::AssignStl", "when reading %s expecting JSON object", cl->GetName());
451  return kFALSE;
452  }
453  fStlRead->fIter = fNode->begin();
454  fStlRead->fTypeTag = typename_tag && (strlen(typename_tag) > 0) ? typename_tag : nullptr;
455  } else {
456  if (!fNode->is_array() && !(fNode->is_object() && (fNode->count("$arr") == 1))) {
457  ::Error("TJSONStackObj::AssignStl", "when reading %s expecting JSON array", cl->GetName());
458  return kFALSE;
459  }
460  }
461  return kTRUE;
462  }
463 
464  nlohmann::json *GetStlNode()
465  {
466  return fStlRead ? fStlRead->GetStlNode(fNode) : fNode;
467  }
468 
469  void ClearStl()
470  {
471  fStlRead.reset(nullptr);
472  }
473 };
474 
475 ////////////////////////////////////////////////////////////////////////////////
476 /// Creates buffer object to serialize data into json.
477 
479  : TBufferText(mode), fOutBuffer(), fOutput(nullptr), fValue(), fStack(), fSemicolon(" : "), fArraySepar(", "),
480  fNumericLocale(), fTypeNameTag("_typename")
481 {
482  fOutBuffer.Capacity(10000);
483  fValue.Capacity(1000);
484  fOutput = &fOutBuffer;
485 
486  // checks if setlocale(LC_NUMERIC) returns others than "C"
487  // in this case locale will be changed and restored at the end of object conversion
488 
489  char *loc = setlocale(LC_NUMERIC, nullptr);
490  if (loc && (strcmp(loc, "C") != 0)) {
491  fNumericLocale = loc;
492  setlocale(LC_NUMERIC, "C");
493  }
494 }
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 /// destroy buffer
498 
500 {
501  while (fStack.size() > 0)
502  PopStack();
503 
504  if (fNumericLocale.Length() > 0)
505  setlocale(LC_NUMERIC, fNumericLocale.Data());
506 }
507 
508 ////////////////////////////////////////////////////////////////////////////////
509 /// Converts object, inherited from TObject class, to JSON string
510 /// Lower digit of compact parameter define formatting rules
511 /// - 0 - no any compression, human-readable form
512 /// - 1 - exclude spaces in the begin
513 /// - 2 - remove newlines
514 /// - 3 - exclude spaces as much as possible
515 ///
516 /// Second digit of compact parameter defines algorithm for arrays compression
517 /// - 0 - no compression, standard JSON array
518 /// - 1 - exclude leading and trailing zeros
519 /// - 2 - check values repetition and empty gaps
520 ///
521 /// Maximal compression achieved when compact parameter equal to 23
522 /// When member_name specified, converts only this data member
523 
524 TString TBufferJSON::ConvertToJSON(const TObject *obj, Int_t compact, const char *member_name)
525 {
526  TClass *clActual = nullptr;
527  void *ptr = (void *)obj;
528 
529  if (obj) {
530  clActual = TObject::Class()->GetActualClass(obj);
531  if (!clActual)
532  clActual = TObject::Class();
533  else if (clActual != TObject::Class())
534  ptr = (void *)((Long_t)obj - clActual->GetBaseClassOffset(TObject::Class()));
535  }
536 
537  return ConvertToJSON(ptr, clActual, compact, member_name);
538 }
539 
540 ////////////////////////////////////////////////////////////////////////////////
541 /// Set level of space/newline/array compression
542 /// Lower digit of compact parameter define formatting rules
543 /// - kNoCompress = 0 - no any compression, human-readable form
544 /// - kNoIndent = 1 - remove indentation spaces in the begin of each line
545 /// - kNoNewLine = 2 - remove also newlines
546 /// - kNoSpaces = 3 - exclude all spaces and new lines
547 ///
548 /// Second digit of compact parameter defines algorithm for arrays compression
549 /// - 0 - no compression, standard JSON array
550 /// - kZeroSuppression = 10 - exclude leading and trailing zeros
551 /// - kSameSuppression = 20 - check values repetition and empty gaps
552 ///
553 /// Third digit defines usage of typeinfo
554 /// - kSkipTypeInfo = 100 - "_typename" field will be skipped, reading by ROOT or JSROOT may be impossible
555 
556 void TBufferJSON::SetCompact(int level)
557 {
558  if (level < 0)
559  level = 0;
560  fCompact = level % 10;
561  if (fCompact >= kMapAsObject) {
564  }
565  fSemicolon = (fCompact >= kNoSpaces) ? ":" : " : ";
566  fArraySepar = (fCompact >= kNoSpaces) ? "," : ", ";
567  fArrayCompact = ((level / 10) % 10) * 10;
568  if ((((level / 100) % 10) * 100) == kSkipTypeInfo)
570  else if (fTypeNameTag.Length() == 0)
571  fTypeNameTag = "_typename";
572 }
573 
574 ////////////////////////////////////////////////////////////////////////////////
575 /// Configures _typename tag in JSON structures
576 /// By default "_typename" field in JSON structures used to store class information
577 /// One can specify alternative tag like "$typename" or "xy", but such JSON can not be correctly used in JSROOT
578 /// If empty string is provided, class information will not be stored
579 
580 void TBufferJSON::SetTypenameTag(const char *tag)
581 {
582  if (!tag)
584  else
585  fTypeNameTag = tag;
586 }
587 
588 ////////////////////////////////////////////////////////////////////////////////
589 /// Configures _typeversion tag in JSON
590 /// One can specify name of the JSON tag like "_typeversion" or "$tv" which will be used to store class version
591 /// Such tag can be used to correctly recover objects from JSON
592 /// If empty string is provided (default), class version will not be stored
593 
594 void TBufferJSON::SetTypeversionTag(const char *tag)
595 {
596  if (!tag)
598  else
599  fTypeVersionTag = tag;
600 }
601 
602 ////////////////////////////////////////////////////////////////////////////////
603 /// Specify class which typename will not be stored in JSON
604 /// Several classes can be configured
605 /// To exclude typeinfo for all classes, call TBufferJSON::SetTypenameTag("")
606 
608 {
609  if (cl && (std::find(fSkipClasses.begin(), fSkipClasses.end(), cl) == fSkipClasses.end()))
610  fSkipClasses.emplace_back(cl);
611 }
612 
613 ////////////////////////////////////////////////////////////////////////////////
614 /// Returns true if class info will be skipped from JSON
615 
617 {
618  return cl && (std::find(fSkipClasses.begin(), fSkipClasses.end(), cl) != fSkipClasses.end());
619 }
620 
621 ////////////////////////////////////////////////////////////////////////////////
622 /// Converts any type of object to JSON string
623 /// One should provide pointer on object and its class name
624 /// Lower digit of compact parameter define formatting rules
625 /// - TBufferJSON::kNoCompress (0) - no any compression, human-readable form
626 /// - TBufferJSON::kNoIndent (1) - exclude spaces in the begin
627 /// - TBufferJSON::kNoNewLine (2) - no indent and no newlines
628 /// - TBufferJSON::kNoSpaces (3) - exclude spaces as much as possible
629 /// Second digit of compact parameter defines algorithm for arrays compression
630 /// - 0 - no compression, standard JSON array
631 /// - TBufferJSON::kZeroSuppression (10) - exclude leading and trailing zeros
632 /// - TBufferJSON::kSameSuppression (20) - check values repetition and empty gaps
633 /// - TBufferJSON::kBase64 (30) - arrays will be coded with base64 coding
634 /// Third digit of compact parameter defines typeinfo storage:
635 /// - TBufferJSON::kSkipTypeInfo (100) - "_typename" will be skipped, not always can be read back
636 /// Maximal none-destructive compression can be achieved when
637 /// compact parameter equal to TBufferJSON::kNoSpaces + TBufferJSON::kSameSuppression
638 /// When member_name specified, converts only this data member
639 
640 TString TBufferJSON::ConvertToJSON(const void *obj, const TClass *cl, Int_t compact, const char *member_name)
641 {
642  TClass *clActual = obj ? cl->GetActualClass(obj) : nullptr;
643  const void *actualStart = obj;
644  if (clActual && (clActual != cl)) {
645  actualStart = (char *)obj - clActual->GetBaseClassOffset(cl);
646  } else {
647  // We could not determine the real type of this object,
648  // let's assume it is the one given by the caller.
649  clActual = const_cast<TClass *>(cl);
650  }
651 
652  if (member_name && actualStart) {
653  TRealData *rdata = clActual->GetRealData(member_name);
654  TDataMember *member = rdata ? rdata->GetDataMember() : nullptr;
655  if (!member) {
656  TIter iter(clActual->GetListOfRealData());
657  while ((rdata = dynamic_cast<TRealData *>(iter())) != nullptr) {
658  member = rdata->GetDataMember();
659  if (member && strcmp(member->GetName(), member_name) == 0)
660  break;
661  }
662  }
663  if (!member)
664  return TString();
665 
666  Int_t arraylen = -1;
667  if (member->GetArrayIndex() != 0) {
668  TRealData *idata = clActual->GetRealData(member->GetArrayIndex());
669  TDataMember *imember = idata ? idata->GetDataMember() : nullptr;
670  if (imember && (strcmp(imember->GetTrueTypeName(), "int") == 0)) {
671  arraylen = *((int *)((char *)actualStart + idata->GetThisOffset()));
672  }
673  }
674 
675  void *ptr = (char *)actualStart + rdata->GetThisOffset();
676  if (member->IsaPointer())
677  ptr = *((char **)ptr);
678 
679  return TBufferJSON::ConvertToJSON(ptr, member, compact, arraylen);
680  }
681 
682  TBufferJSON buf;
683 
684  buf.SetCompact(compact);
685 
686  return buf.StoreObject(actualStart, clActual);
687 }
688 
689 ////////////////////////////////////////////////////////////////////////////////
690 /// Store provided object as JSON structure
691 /// Allows to configure different TBufferJSON properties before converting object into JSON
692 /// Actual object class must be specified here
693 /// Method can be safely called once - after that TBufferJSON instance must be destroyed
694 /// Code should look like:
695 ///
696 /// auto obj = new UserClass();
697 /// TBufferJSON buf;
698 /// buf.SetCompact(TBufferJSON::kNoSpaces); // change any other settings in TBufferJSON
699 /// auto json = buf.StoreObject(obj, TClass::GetClass<UserClass>());
700 ///
701 
702 TString TBufferJSON::StoreObject(const void *obj, const TClass *cl)
703 {
704  if (IsWriting()) {
705 
706  InitMap();
707 
708  PushStack(); // dummy stack entry to avoid extra checks in the beginning
709 
710  JsonWriteObject(obj, cl);
711 
712  PopStack();
713  } else {
714  Error("StoreObject", "Can not store object into TBuffer for reading");
715  }
716 
717  return fOutBuffer.Length() ? fOutBuffer : fValue;
718 }
719 
720 ////////////////////////////////////////////////////////////////////////////////
721 /// Converts selected data member into json
722 /// Parameter ptr specifies address in memory, where data member is located
723 /// compact parameter defines compactness of produced JSON (from 0 to 3)
724 /// arraylen (when specified) is array length for this data member, //[fN] case
725 
726 TString TBufferJSON::ConvertToJSON(const void *ptr, TDataMember *member, Int_t compact, Int_t arraylen)
727 {
728  if (!ptr || !member)
729  return TString("null");
730 
731  Bool_t stlstring = !strcmp(member->GetTrueTypeName(), "string");
732 
733  Int_t isstl = member->IsSTLContainer();
734 
735  TClass *mcl = member->IsBasic() ? nullptr : gROOT->GetClass(member->GetTypeName());
736 
737  if (mcl && (mcl != TString::Class()) && !stlstring && !isstl && (mcl->GetBaseClassOffset(TArray::Class()) != 0) &&
738  (arraylen <= 0) && (member->GetArrayDim() == 0))
739  return TBufferJSON::ConvertToJSON(ptr, mcl, compact);
740 
741  TBufferJSON buf;
742 
743  buf.SetCompact(compact);
744 
745  return buf.JsonWriteMember(ptr, member, mcl, arraylen);
746 }
747 
748 ////////////////////////////////////////////////////////////////////////////////
749 /// Convert object into JSON and store in text file
750 /// Returns size of the produce file
751 /// Used in TObject::SaveAs()
752 
753 Int_t TBufferJSON::ExportToFile(const char *filename, const TObject *obj, const char *option)
754 {
755  if (!obj || !filename || (*filename == 0))
756  return 0;
757 
758  Int_t compact = strstr(filename, ".json.gz") ? 3 : 0;
759  if (option && (*option >= '0') && (*option <= '3'))
760  compact = TString(option).Atoi();
761 
762  TString json = TBufferJSON::ConvertToJSON(obj, compact);
763 
764  std::ofstream ofs(filename);
765 
766  if (strstr(filename, ".json.gz")) {
767  const char *objbuf = json.Data();
768  Long_t objlen = json.Length();
769 
770  unsigned long objcrc = R__crc32(0, NULL, 0);
771  objcrc = R__crc32(objcrc, (const unsigned char *)objbuf, objlen);
772 
773  // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
774  Int_t buflen = 10 + objlen + 8;
775  if (buflen < 512)
776  buflen = 512;
777 
778  char *buffer = (char *)malloc(buflen);
779  if (!buffer)
780  return 0; // failure
781 
782  char *bufcur = buffer;
783 
784  *bufcur++ = 0x1f; // first byte of ZIP identifier
785  *bufcur++ = 0x8b; // second byte of ZIP identifier
786  *bufcur++ = 0x08; // compression method
787  *bufcur++ = 0x00; // FLAG - empty, no any file names
788  *bufcur++ = 0; // empty timestamp
789  *bufcur++ = 0; //
790  *bufcur++ = 0; //
791  *bufcur++ = 0; //
792  *bufcur++ = 0; // XFL (eXtra FLags)
793  *bufcur++ = 3; // OS 3 means Unix
794  // strcpy(bufcur, "item.json");
795  // bufcur += strlen("item.json")+1;
796 
797  char dummy[8];
798  memcpy(dummy, bufcur - 6, 6);
799 
800  // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
801  unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, (char *)objbuf, objlen);
802 
803  memcpy(bufcur - 6, dummy, 6);
804 
805  bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
806 
807  *bufcur++ = objcrc & 0xff; // CRC32
808  *bufcur++ = (objcrc >> 8) & 0xff;
809  *bufcur++ = (objcrc >> 16) & 0xff;
810  *bufcur++ = (objcrc >> 24) & 0xff;
811 
812  *bufcur++ = objlen & 0xff; // original data length
813  *bufcur++ = (objlen >> 8) & 0xff; // original data length
814  *bufcur++ = (objlen >> 16) & 0xff; // original data length
815  *bufcur++ = (objlen >> 24) & 0xff; // original data length
816 
817  ofs.write(buffer, bufcur - buffer);
818 
819  free(buffer);
820  } else {
821  ofs << json.Data();
822  }
823 
824  ofs.close();
825 
826  return json.Length();
827 }
828 
829 ////////////////////////////////////////////////////////////////////////////////
830 /// Convert object into JSON and store in text file
831 /// Returns size of the produce file
832 
833 Int_t TBufferJSON::ExportToFile(const char *filename, const void *obj, const TClass *cl, const char *option)
834 {
835  if (!obj || !cl || !filename || (*filename == 0))
836  return 0;
837 
838  Int_t compact = strstr(filename, ".json.gz") ? 3 : 0;
839  if (option && (*option >= '0') && (*option <= '3'))
840  compact = TString(option).Atoi();
841 
842  TString json = TBufferJSON::ConvertToJSON(obj, cl, compact);
843 
844  std::ofstream ofs(filename);
845 
846  if (strstr(filename, ".json.gz")) {
847  const char *objbuf = json.Data();
848  Long_t objlen = json.Length();
849 
850  unsigned long objcrc = R__crc32(0, NULL, 0);
851  objcrc = R__crc32(objcrc, (const unsigned char *)objbuf, objlen);
852 
853  // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
854  Int_t buflen = 10 + objlen + 8;
855  if (buflen < 512)
856  buflen = 512;
857 
858  char *buffer = (char *)malloc(buflen);
859  if (!buffer)
860  return 0; // failure
861 
862  char *bufcur = buffer;
863 
864  *bufcur++ = 0x1f; // first byte of ZIP identifier
865  *bufcur++ = 0x8b; // second byte of ZIP identifier
866  *bufcur++ = 0x08; // compression method
867  *bufcur++ = 0x00; // FLAG - empty, no any file names
868  *bufcur++ = 0; // empty timestamp
869  *bufcur++ = 0; //
870  *bufcur++ = 0; //
871  *bufcur++ = 0; //
872  *bufcur++ = 0; // XFL (eXtra FLags)
873  *bufcur++ = 3; // OS 3 means Unix
874  // strcpy(bufcur, "item.json");
875  // bufcur += strlen("item.json")+1;
876 
877  char dummy[8];
878  memcpy(dummy, bufcur - 6, 6);
879 
880  // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
881  unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, (char *)objbuf, objlen);
882 
883  memcpy(bufcur - 6, dummy, 6);
884 
885  bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
886 
887  *bufcur++ = objcrc & 0xff; // CRC32
888  *bufcur++ = (objcrc >> 8) & 0xff;
889  *bufcur++ = (objcrc >> 16) & 0xff;
890  *bufcur++ = (objcrc >> 24) & 0xff;
891 
892  *bufcur++ = objlen & 0xff; // original data length
893  *bufcur++ = (objlen >> 8) & 0xff; // original data length
894  *bufcur++ = (objlen >> 16) & 0xff; // original data length
895  *bufcur++ = (objlen >> 24) & 0xff; // original data length
896 
897  ofs.write(buffer, bufcur - buffer);
898 
899  free(buffer);
900  } else {
901  ofs << json.Data();
902  }
903 
904  ofs.close();
905 
906  return json.Length();
907 }
908 
909 ////////////////////////////////////////////////////////////////////////////////
910 /// Read TObject-based class from JSON, produced by ConvertToJSON() method.
911 /// If object does not inherit from TObject class, return 0.
912 
914 {
915  TClass *cl = nullptr;
916  void *obj = ConvertFromJSONAny(str, &cl);
917 
918  if (!cl || !obj)
919  return nullptr;
920 
921  Int_t delta = cl->GetBaseClassOffset(TObject::Class());
922 
923  if (delta < 0) {
924  cl->Destructor(obj);
925  return nullptr;
926  }
927 
928  return (TObject *)(((char *)obj) + delta);
929 }
930 
931 ////////////////////////////////////////////////////////////////////////////////
932 /// Read object from JSON
933 /// In class pointer (if specified) read class is returned
934 /// One must specify expected object class, if it is TArray or STL container
935 
936 void *TBufferJSON::ConvertFromJSONAny(const char *str, TClass **cl)
937 {
939 
940  return buf.RestoreObject(str, cl);
941 }
942 
943 ////////////////////////////////////////////////////////////////////////////////
944 /// Read object from JSON
945 /// In class pointer (if specified) read class is returned
946 /// One must specify expected object class, if it is TArray or STL container
947 
948 void *TBufferJSON::RestoreObject(const char *json_str, TClass **cl)
949 {
950  if (!IsReading())
951  return nullptr;
952 
953  nlohmann::json docu = nlohmann::json::parse(json_str);
954 
955  if (docu.is_null() || (!docu.is_object() && !docu.is_array()))
956  return nullptr;
957 
958  TClass *objClass = nullptr;
959 
960  if (cl) {
961  objClass = *cl; // this is class which suppose to created when reading JSON
962  *cl = nullptr;
963  }
964 
965  InitMap();
966 
967  PushStack(0, &docu);
968 
969  void *obj = JsonReadObject(nullptr, objClass, cl);
970 
971  PopStack();
972 
973  return obj;
974 }
975 
976 ////////////////////////////////////////////////////////////////////////////////
977 /// Read objects from JSON, one can reuse existing object
978 
979 void *TBufferJSON::ConvertFromJSONChecked(const char *str, const TClass *expectedClass)
980 {
981  if (!expectedClass)
982  return nullptr;
983 
984  TClass *resClass = const_cast<TClass *>(expectedClass);
985 
986  void *res = ConvertFromJSONAny(str, &resClass);
987 
988  if (!res || !resClass)
989  return nullptr;
990 
991  if (resClass == expectedClass)
992  return res;
993 
994  Int_t offset = resClass->GetBaseClassOffset(expectedClass);
995  if (offset < 0) {
996  ::Error("TBufferJSON::ConvertFromJSONChecked", "expected class %s is not base for read class %s",
997  expectedClass->GetName(), resClass->GetName());
998  resClass->Destructor(res);
999  return nullptr;
1000  }
1001 
1002  return (char *)res - offset;
1003 }
1004 
1005 ////////////////////////////////////////////////////////////////////////////////
1006 /// Convert single data member to JSON structures
1007 /// Returns string with converted member
1008 
1009 TString TBufferJSON::JsonWriteMember(const void *ptr, TDataMember *member, TClass *memberClass, Int_t arraylen)
1010 {
1011  if (!member)
1012  return "null";
1013 
1014  if (gDebug > 2)
1015  Info("JsonWriteMember", "Write member %s type %s ndim %d", member->GetName(), member->GetTrueTypeName(),
1016  member->GetArrayDim());
1017 
1018  Int_t tid = member->GetDataType() ? member->GetDataType()->GetType() : kNoType_t;
1019  if (strcmp(member->GetTrueTypeName(), "const char*") == 0)
1020  tid = kCharStar;
1021  else if (!member->IsBasic() || (tid == kOther_t) || (tid == kVoid_t))
1022  tid = kNoType_t;
1023 
1024  if (!ptr)
1025  return (tid == kCharStar) ? "\"\"" : "null";
1026 
1027  PushStack(0);
1028  fValue.Clear();
1029 
1030  if (tid != kNoType_t) {
1031 
1032  TArrayIndexProducer indx(member, arraylen, fArraySepar.Data());
1033 
1034  Int_t shift = 1;
1035 
1036  if (indx.IsArray() && (tid == kChar_t))
1037  shift = indx.ReduceDimension();
1038 
1039  char *ppp = (char *)ptr;
1040 
1041  if (indx.IsArray())
1042  fOutBuffer.Append(indx.GetBegin());
1043 
1044  do {
1045  fValue.Clear();
1046 
1047  switch (tid) {
1048  case kChar_t:
1049  if (shift > 1)
1050  JsonWriteConstChar((Char_t *)ppp, shift);
1051  else
1052  JsonWriteBasic(*((Char_t *)ppp));
1053  break;
1054  case kShort_t: JsonWriteBasic(*((Short_t *)ppp)); break;
1055  case kInt_t: JsonWriteBasic(*((Int_t *)ppp)); break;
1056  case kLong_t: JsonWriteBasic(*((Long_t *)ppp)); break;
1057  case kFloat_t: JsonWriteBasic(*((Float_t *)ppp)); break;
1058  case kCounter: JsonWriteBasic(*((Int_t *)ppp)); break;
1059  case kCharStar: JsonWriteConstChar((Char_t *)ppp); break;
1060  case kDouble_t: JsonWriteBasic(*((Double_t *)ppp)); break;
1061  case kDouble32_t: JsonWriteBasic(*((Double_t *)ppp)); break;
1062  case kchar: JsonWriteBasic(*((char *)ppp)); break;
1063  case kUChar_t: JsonWriteBasic(*((UChar_t *)ppp)); break;
1064  case kUShort_t: JsonWriteBasic(*((UShort_t *)ppp)); break;
1065  case kUInt_t: JsonWriteBasic(*((UInt_t *)ppp)); break;
1066  case kULong_t: JsonWriteBasic(*((ULong_t *)ppp)); break;
1067  case kBits: JsonWriteBasic(*((UInt_t *)ppp)); break;
1068  case kLong64_t: JsonWriteBasic(*((Long64_t *)ppp)); break;
1069  case kULong64_t: JsonWriteBasic(*((ULong64_t *)ppp)); break;
1070  case kBool_t: JsonWriteBasic(*((Bool_t *)ppp)); break;
1071  case kFloat16_t: JsonWriteBasic(*((Float_t *)ppp)); break;
1072  case kOther_t:
1073  case kVoid_t: break;
1074  }
1075 
1077  if (indx.IsArray())
1078  fOutBuffer.Append(indx.NextSeparator());
1079 
1080  ppp += shift * member->GetUnitSize();
1081 
1082  } while (!indx.IsDone());
1083 
1084  fValue = fOutBuffer;
1085 
1086  } else if (memberClass == TString::Class()) {
1087  TString *str = (TString *)ptr;
1088  JsonWriteConstChar(str ? str->Data() : nullptr);
1089  } else if ((member->IsSTLContainer() == ROOT::kSTLvector) || (member->IsSTLContainer() == ROOT::kSTLlist) ||
1090  (member->IsSTLContainer() == ROOT::kSTLforwardlist)) {
1091 
1092  if (memberClass)
1093  memberClass->Streamer((void *)ptr, *this);
1094  else
1095  fValue = "[]";
1096 
1097  if (fValue == "0")
1098  fValue = "[]";
1099 
1100  } else if (memberClass && memberClass->GetBaseClassOffset(TArray::Class()) == 0) {
1101  TArray *arr = (TArray *)ptr;
1102  if (arr && (arr->GetSize() > 0)) {
1103  arr->Streamer(*this);
1104  // WriteFastArray(arr->GetArray(), arr->GetSize());
1105  if (Stack()->fValues.size() > 1) {
1106  Warning("TBufferJSON", "When streaming TArray, more than 1 object in the stack, use second item");
1107  fValue = Stack()->fValues[1].c_str();
1108  }
1109  } else
1110  fValue = "[]";
1111  } else if (memberClass && !strcmp(memberClass->GetName(), "string")) {
1112  // here value contains quotes, stack can be ignored
1113  memberClass->Streamer((void *)ptr, *this);
1114  }
1115  PopStack();
1116 
1117  if (fValue.Length())
1118  return fValue;
1119 
1120  if (!memberClass || (member->GetArrayDim() > 0) || (arraylen > 0))
1121  return "<not supported>";
1122 
1123  return TBufferJSON::ConvertToJSON(ptr, memberClass);
1124 }
1125 
1126 ////////////////////////////////////////////////////////////////////////////////
1127 /// add new level to the structures stack
1128 
1129 TJSONStackObj *TBufferJSON::PushStack(Int_t inclevel, void *readnode)
1130 {
1131  auto next = new TJSONStackObj();
1132  next->fLevel = inclevel;
1133  if (IsReading()) {
1134  next->fNode = (nlohmann::json *)readnode;
1135  } else if (fStack.size() > 0) {
1136  auto prev = Stack();
1137  next->fLevel += prev->fLevel;
1138  next->fMemberPtr = prev->fMemberPtr;
1139  }
1140  fStack.emplace_back(next);
1141  return next;
1142 }
1143 
1144 ////////////////////////////////////////////////////////////////////////////////
1145 /// remove one level from stack
1146 
1147 TJSONStackObj *TBufferJSON::PopStack()
1148 {
1149  if (fStack.size() > 0)
1150  fStack.pop_back();
1151 
1152  return fStack.size() > 0 ? fStack.back().get() : nullptr;
1153 }
1154 
1155 ////////////////////////////////////////////////////////////////////////////////
1156 /// Append two string to the output JSON, normally separate by line break
1157 
1158 void TBufferJSON::AppendOutput(const char *line0, const char *line1)
1159 {
1160  if (line0)
1161  fOutput->Append(line0);
1162 
1163  if (line1) {
1164  if (fCompact < 2)
1165  fOutput->Append("\n");
1166 
1167  if (strlen(line1) > 0) {
1168  if (fCompact < 1) {
1169  if (Stack()->fLevel > 0)
1170  fOutput->Append(' ', Stack()->fLevel);
1171  }
1172  fOutput->Append(line1);
1173  }
1174  }
1175 }
1176 
1177 ////////////////////////////////////////////////////////////////////////////////
1178 /// Start object element with typeinfo
1179 
1180 TJSONStackObj *TBufferJSON::JsonStartObjectWrite(const TClass *obj_class, TStreamerInfo *info)
1181 {
1182  auto stack = PushStack(2);
1183 
1184  // new object started - assign own member counter
1185  stack->fMemberPtr = &stack->fMemberCnt;
1186 
1187  if ((fTypeNameTag.Length() > 0) && !IsSkipClassInfo(obj_class)) {
1188  // stack->fMemberCnt = 1; // default value, comment out here
1189  AppendOutput("{", "\"");
1191  AppendOutput("\"");
1193  AppendOutput("\"");
1194  AppendOutput(obj_class->GetName());
1195  AppendOutput("\"");
1196  if (fTypeVersionTag.Length() > 0) {
1197  AppendOutput(stack->NextMemberSeparator(), "\"");
1199  AppendOutput("\"");
1201  AppendOutput(Form("%d", (int)(info ? info->GetClassVersion() : obj_class->GetClassVersion())));
1202  }
1203  } else {
1204  stack->fMemberCnt = 0; // exclude typename
1205  AppendOutput("{");
1206  }
1207 
1208  return stack;
1209 }
1210 
1211 ////////////////////////////////////////////////////////////////////////////////
1212 /// Start new class member in JSON structures
1213 
1214 void TBufferJSON::JsonStartElement(const TStreamerElement *elem, const TClass *base_class)
1215 {
1216  const char *elem_name = nullptr;
1217  Int_t special_kind = JsonSpecialClass(base_class);
1218 
1219  switch (special_kind) {
1220  case 0:
1221  if (!base_class)
1222  elem_name = elem->GetName();
1223  break;
1224  case TClassEdit::kVector: elem_name = "fVector"; break;
1225  case TClassEdit::kList: elem_name = "fList"; break;
1226  case TClassEdit::kForwardlist: elem_name = "fForwardlist"; break;
1227  case TClassEdit::kDeque: elem_name = "fDeque"; break;
1228  case TClassEdit::kMap: elem_name = "fMap"; break;
1229  case TClassEdit::kMultiMap: elem_name = "fMultiMap"; break;
1230  case TClassEdit::kSet: elem_name = "fSet"; break;
1231  case TClassEdit::kMultiSet: elem_name = "fMultiSet"; break;
1232  case TClassEdit::kUnorderedSet: elem_name = "fUnorderedSet"; break;
1233  case TClassEdit::kUnorderedMultiSet: elem_name = "fUnorderedMultiSet"; break;
1234  case TClassEdit::kUnorderedMap: elem_name = "fUnorderedMap"; break;
1235  case TClassEdit::kUnorderedMultiMap: elem_name = "fUnorderedMultiMap"; break;
1236  case TClassEdit::kBitSet: elem_name = "fBitSet"; break;
1237  case json_TArray: elem_name = "fArray"; break;
1238  case json_TString:
1239  case json_stdstring: elem_name = "fString"; break;
1240  }
1241 
1242  if (!elem_name)
1243  return;
1244 
1245  if (IsReading()) {
1246  nlohmann::json *json = Stack()->fNode;
1247 
1248  if (json->count(elem_name) != 1) {
1249  Error("JsonStartElement", "Missing JSON structure for element %s", elem_name);
1250  } else {
1251  Stack()->fNode = &((*json)[elem_name]);
1252  if (special_kind == json_TArray) {
1253  Int_t len = Stack()->IsJsonArray();
1254  Stack()->PushIntValue(len > 0 ? len : 0);
1255  if (len < 0)
1256  Error("JsonStartElement", "Missing array when reading TArray class for element %s", elem->GetName());
1257  }
1258  if ((gDebug > 1) && base_class)
1259  Info("JsonStartElement", "Reading baseclass %s from element %s", base_class->GetName(), elem_name);
1260  }
1261 
1262  } else {
1263  AppendOutput(Stack()->NextMemberSeparator(), "\"");
1264  AppendOutput(elem_name);
1265  AppendOutput("\"");
1267  }
1268 }
1269 
1270 ////////////////////////////////////////////////////////////////////////////////
1271 /// disable post-processing of the code
1273 {
1274  Stack()->fIsPostProcessed = kTRUE;
1275 }
1276 
1277 ////////////////////////////////////////////////////////////////////////////////
1278 /// return non-zero value when class has special handling in JSON
1279 /// it is TCollection (-130), TArray (100), TString (110), std::string (120) and STL containers (1..6)
1280 
1282 {
1283  if (!cl)
1284  return 0;
1285 
1286  Bool_t isarray = strncmp("TArray", cl->GetName(), 6) == 0;
1287  if (isarray)
1288  isarray = (const_cast<TClass *>(cl))->GetBaseClassOffset(TArray::Class()) == 0;
1289  if (isarray)
1290  return json_TArray;
1291 
1292  // negative value used to indicate that collection stored as object
1293  if ((const_cast<TClass *>(cl))->GetBaseClassOffset(TCollection::Class()) == 0)
1294  return json_TCollection;
1295 
1296  // special case for TString - it is saved as string in JSON
1297  if (cl == TString::Class())
1298  return json_TString;
1299 
1300  bool isstd = TClassEdit::IsStdClass(cl->GetName());
1301  int isstlcont(ROOT::kNotSTL);
1302  if (isstd)
1303  isstlcont = cl->GetCollectionType();
1304  if (isstlcont > 0)
1305  return isstlcont;
1306 
1307  // also special handling for STL string, which handled similar to TString
1308  if (isstd && !strcmp(cl->GetName(), "string"))
1309  return json_stdstring;
1310 
1311  return 0;
1312 }
1313 
1314 ////////////////////////////////////////////////////////////////////////////////
1315 /// Write object to buffer
1316 /// If object was written before, only pointer will be stored
1317 /// If check_map==kFALSE, object will be stored in any case and pointer will not be registered in the map
1318 
1319 void TBufferJSON::JsonWriteObject(const void *obj, const TClass *cl, Bool_t check_map)
1320 {
1321  if (!cl)
1322  obj = nullptr;
1323 
1324  if (gDebug > 0)
1325  Info("JsonWriteObject", "Object %p class %s check_map %s", obj, cl ? cl->GetName() : "null",
1326  check_map ? "true" : "false");
1327 
1328  Int_t special_kind = JsonSpecialClass(cl), map_convert{0};
1329 
1330  TString fObjectOutput, *fPrevOutput{nullptr};
1331 
1332  TJSONStackObj *stack = Stack();
1333 
1334  if (stack && stack->fAccObjects && ((fValue.Length() > 0) || (stack->fValues.size() > 0))) {
1335  // accumulate data of super-object in stack
1336 
1337  if (fValue.Length() > 0)
1338  stack->PushValue(fValue);
1339 
1340  // redirect output to local buffer, use it later as value
1341  fPrevOutput = fOutput;
1342  fOutput = &fObjectOutput;
1343  } else if ((special_kind <= 0) || (special_kind > json_TArray)) {
1344  // FIXME: later post processing should be active for all special classes, while they all keep output in the value
1346  } else if ((special_kind == TClassEdit::kMap) || (special_kind == TClassEdit::kMultiMap) ||
1347  (special_kind == TClassEdit::kUnorderedMap) || (special_kind == TClassEdit::kUnorderedMultiMap)) {
1348 
1349  if ((fMapAsObject && (fStack.size()==1)) || (stack && stack->fElem && strstr(stack->fElem->GetTitle(), "JSON_object")))
1350  map_convert = 2; // mapped into normal object
1351  else
1352  map_convert = 1;
1353  }
1354 
1355  if (!obj) {
1356  AppendOutput("null");
1357  goto post_process;
1358  }
1359 
1360  if (special_kind <= 0) {
1361  // add element name which should correspond to the object
1362  if (check_map) {
1363  Long64_t refid = GetObjectTag(obj);
1364  if (refid > 0) {
1365  // old-style refs, coded into string like "$ref12"
1366  // AppendOutput(Form("\"$ref:%u\"", iter->second));
1367  // new-style refs, coded into extra object {"$ref":12}, auto-detected by JSROOT 4.8 and higher
1368  AppendOutput(Form("{\"$ref\":%u}", (unsigned)(refid - 1)));
1369  goto post_process;
1370  }
1371  MapObject(obj, cl, fJsonrCnt + 1); // +1 used
1372  }
1373 
1374  fJsonrCnt++; // object counts required in dereferencing part
1375 
1376  stack = JsonStartObjectWrite(cl);
1377 
1378  } else if (map_convert == 2) {
1379  // special handling of map - it is object, but stored in the fValue
1380 
1381  if (check_map) {
1382  Long64_t refid = GetObjectTag(obj);
1383  if (refid > 0) {
1384  fValue.Form("{\"$ref\":%u}", (unsigned)(refid - 1));
1385  goto post_process;
1386  }
1387  MapObject(obj, cl, fJsonrCnt + 1); // +1 used
1388  }
1389 
1390  fJsonrCnt++; // object counts required in dereferencing part
1391  stack = PushStack(0);
1392 
1393  } else {
1394 
1395  bool base64 = ((special_kind == TClassEdit::kVector) && stack && stack->fElem && strstr(stack->fElem->GetTitle(), "JSON_base64"));
1396 
1397  // for array, string and STL collections different handling -
1398  // they not recognized at the end as objects in JSON
1399  stack = PushStack(0);
1400 
1401  stack->fBase64 = base64;
1402  }
1403 
1404  if (gDebug > 3)
1405  Info("JsonWriteObject", "Starting object %p write for class: %s", obj, cl->GetName());
1406 
1407  stack->fAccObjects = special_kind < ROOT::kSTLend;
1408 
1409  if (special_kind == json_TCollection)
1410  JsonWriteCollection((TCollection *)obj, cl);
1411  else
1412  (const_cast<TClass *>(cl))->Streamer((void *)obj, *this);
1413 
1414  if (gDebug > 3)
1415  Info("JsonWriteObject", "Done object %p write for class: %s", obj, cl->GetName());
1416 
1417  if (special_kind == json_TArray) {
1418  if (stack->fValues.size() != 1)
1419  Error("JsonWriteObject", "Problem when writing array");
1420  stack->fValues.clear();
1421  } else if ((special_kind == json_TString) || (special_kind == json_stdstring)) {
1422  if (stack->fValues.size() > 2)
1423  Error("JsonWriteObject", "Problem when writing TString or std::string");
1424  stack->fValues.clear();
1426  fValue.Clear();
1427  } else if ((special_kind > 0) && (special_kind < ROOT::kSTLend)) {
1428  // here make STL container processing
1429 
1430  if (map_convert == 2) {
1431  // converting map into object
1432 
1433  if (!stack->fValues.empty() && (fValue.Length() > 0))
1434  stack->PushValue(fValue);
1435 
1436  const char *separ = (fCompact < 2) ? ", " : ",";
1437  const char *semi = (fCompact < 2) ? ": " : ":";
1438  bool first = true;
1439 
1440  fValue = "{";
1441  if ((fTypeNameTag.Length() > 0) && !IsSkipClassInfo(cl)) {
1442  fValue.Append("\"");
1444  fValue.Append("\"");
1445  fValue.Append(semi);
1446  fValue.Append("\"");
1447  fValue.Append(cl->GetName());
1448  fValue.Append("\"");
1449  first = false;
1450  }
1451  for (Int_t k = 1; k < (int)stack->fValues.size() - 1; k += 2) {
1452  if (!first)
1453  fValue.Append(separ);
1454  first = false;
1455  fValue.Append(stack->fValues[k].c_str());
1456  fValue.Append(semi);
1457  fValue.Append(stack->fValues[k + 1].c_str());
1458  }
1459  fValue.Append("}");
1460  stack->fValues.clear();
1461  } else if (stack->fValues.empty()) {
1462  // empty container
1463  if (fValue != "0")
1464  Error("JsonWriteObject", "With empty stack fValue!=0");
1465  fValue = "[]";
1466  } else {
1467 
1468  auto size = std::stoi(stack->fValues[0]);
1469 
1470  bool trivial_format = false;
1471 
1472  if ((stack->fValues.size() == 1) && ((size > 1) || ((fValue.Length() > 1) && (fValue[0]=='[')))) {
1473  // prevent case of vector<vector<value_class>>
1474  const auto proxy = cl->GetCollectionProxy();
1475  TClass *value_class = proxy ? proxy->GetValueClass() : nullptr;
1476  if (value_class && TClassEdit::IsStdClass(value_class->GetName()) && (value_class->GetCollectionType() != ROOT::kNotSTL))
1477  trivial_format = false;
1478  else
1479  trivial_format = true;
1480  }
1481 
1482  if (trivial_format) {
1483  // case of simple vector, array already in the value
1484  stack->fValues.clear();
1485  if (fValue.Length() == 0) {
1486  Error("JsonWriteObject", "Empty value when it should contain something");
1487  fValue = "[]";
1488  }
1489 
1490  } else {
1491  const char *separ = "[";
1492 
1493  if (fValue.Length() > 0)
1494  stack->PushValue(fValue);
1495 
1496  if ((size * 2 == (int) stack->fValues.size() - 1) && (map_convert > 0)) {
1497  // special handling for std::map.
1498  // Create entries like { '$pair': 'typename' , 'first' : key, 'second' : value }
1499  TString pairtype = cl->GetName();
1500  if (pairtype.Index("unordered_map<") == 0)
1501  pairtype.Replace(0, 14, "pair<");
1502  else if (pairtype.Index("unordered_multimap<") == 0)
1503  pairtype.Replace(0, 19, "pair<");
1504  else if (pairtype.Index("multimap<") == 0)
1505  pairtype.Replace(0, 9, "pair<");
1506  else if (pairtype.Index("map<") == 0)
1507  pairtype.Replace(0, 4, "pair<");
1508  else
1509  pairtype = "TPair";
1510  if (fTypeNameTag.Length() == 0)
1511  pairtype = "1";
1512  else
1513  pairtype = TString("\"") + pairtype + TString("\"");
1514  for (Int_t k = 1; k < (int) stack->fValues.size() - 1; k += 2) {
1515  fValue.Append(separ);
1516  separ = fArraySepar.Data();
1517  // fJsonrCnt++; // do not add entry in the map, can conflict with objects inside values
1518  fValue.Append("{");
1519  fValue.Append("\"$pair\"");
1521  fValue.Append(pairtype.Data());
1523  fValue.Append("\"first\"");
1525  fValue.Append(stack->fValues[k].c_str());
1527  fValue.Append("\"second\"");
1529  fValue.Append(stack->fValues[k + 1].c_str());
1530  fValue.Append("}");
1531  }
1532  } else {
1533  // for most stl containers write just like blob, but skipping first element with size
1534  for (Int_t k = 1; k < (int) stack->fValues.size(); k++) {
1535  fValue.Append(separ);
1536  separ = fArraySepar.Data();
1537  fValue.Append(stack->fValues[k].c_str());
1538  }
1539  }
1540 
1541  fValue.Append("]");
1542  stack->fValues.clear();
1543  }
1544  }
1545  }
1546 
1547  // reuse post-processing code for TObject or TRef
1548  PerformPostProcessing(stack, cl);
1549 
1550  if ((special_kind == 0) && (!stack->fValues.empty() || (fValue.Length() > 0))) {
1551  if (gDebug > 0)
1552  Info("JsonWriteObject", "Create blob value for class %s", cl->GetName());
1553 
1554  AppendOutput(fArraySepar.Data(), "\"_blob\"");
1556 
1557  const char *separ = "[";
1558 
1559  for (auto &elem: stack->fValues) {
1560  AppendOutput(separ);
1561  separ = fArraySepar.Data();
1562  AppendOutput(elem.c_str());
1563  }
1564 
1565  if (fValue.Length() > 0) {
1566  AppendOutput(separ);
1568  }
1569 
1570  AppendOutput("]");
1571 
1572  fValue.Clear();
1573  stack->fValues.clear();
1574  }
1575 
1576  PopStack();
1577 
1578  if ((special_kind <= 0))
1579  AppendOutput(nullptr, "}");
1580 
1581 post_process:
1582 
1583  if (fPrevOutput) {
1584  fOutput = fPrevOutput;
1585  // for STL containers and TArray object in fValue itself
1586  if ((special_kind <= 0) || (special_kind > json_TArray))
1587  fValue = fObjectOutput;
1588  else if (fObjectOutput.Length() != 0)
1589  Error("JsonWriteObject", "Non-empty object output for special class %s", cl->GetName());
1590  }
1591 }
1592 
1593 ////////////////////////////////////////////////////////////////////////////////
1594 /// store content of ROOT collection
1595 
1597 {
1598  AppendOutput(Stack()->NextMemberSeparator(), "\"name\"");
1600  AppendOutput("\"");
1601  AppendOutput(col->GetName());
1602  AppendOutput("\"");
1603  AppendOutput(Stack()->NextMemberSeparator(), "\"arr\"");
1605 
1606  // collection treated as JS Array
1607  AppendOutput("[");
1608 
1609  bool islist = col->InheritsFrom(TList::Class());
1610  TMap *map = nullptr;
1611  if (col->InheritsFrom(TMap::Class()))
1612  map = dynamic_cast<TMap *>(col);
1613 
1614  TString sopt;
1615  if (islist) {
1616  sopt.Capacity(500);
1617  sopt = "[";
1618  }
1619 
1620  TIter iter(col);
1621  TObject *obj;
1622  Bool_t first = kTRUE;
1623  while ((obj = iter()) != nullptr) {
1624  if (!first)
1626 
1627  if (map) {
1628  // fJsonrCnt++; // do not account map pair as JSON object
1629  AppendOutput("{", "\"$pair\"");
1631  AppendOutput("\"TPair\"");
1632  AppendOutput(fArraySepar.Data(), "\"first\"");
1634  }
1635 
1637 
1638  if (map) {
1639  AppendOutput(fArraySepar.Data(), "\"second\"");
1641  WriteObjectAny(map->GetValue(obj), TObject::Class());
1642  AppendOutput("", "}");
1643  }
1644 
1645  if (islist) {
1646  if (!first)
1647  sopt.Append(fArraySepar.Data());
1648  sopt.Append("\"");
1649  sopt.Append(iter.GetOption());
1650  sopt.Append("\"");
1651  }
1652 
1653  first = kFALSE;
1654  }
1655 
1656  AppendOutput("]");
1657 
1658  if (islist) {
1659  sopt.Append("]");
1660  AppendOutput(Stack()->NextMemberSeparator(), "\"opt\"");
1662  AppendOutput(sopt.Data());
1663  }
1664  fValue.Clear();
1665 }
1666 
1667 ////////////////////////////////////////////////////////////////////////////////
1668 /// read content of ROOT collection
1669 
1671 {
1672  if (!col)
1673  return;
1674 
1675  TList *lst = nullptr;
1676  TMap *map = nullptr;
1677  TClonesArray *clones = nullptr;
1678  if (col->InheritsFrom(TList::Class()))
1679  lst = dynamic_cast<TList *>(col);
1680  else if (col->InheritsFrom(TMap::Class()))
1681  map = dynamic_cast<TMap *>(col);
1682  else if (col->InheritsFrom(TClonesArray::Class()))
1683  clones = dynamic_cast<TClonesArray *>(col);
1684 
1685  nlohmann::json *json = Stack()->fNode;
1686 
1687  std::string name = json->at("name");
1688  col->SetName(name.c_str());
1689 
1690  nlohmann::json &arr = json->at("arr");
1691  int size = arr.size();
1692 
1693  for (int n = 0; n < size; ++n) {
1694  nlohmann::json *subelem = &arr.at(n);
1695 
1696  if (map)
1697  subelem = &subelem->at("first");
1698 
1699  PushStack(0, subelem);
1700 
1701  TClass *readClass = nullptr, *objClass = nullptr;
1702  void *subobj = nullptr;
1703 
1704  if (clones) {
1705  if (n == 0) {
1706  if (!clones->GetClass() || (clones->GetSize() == 0)) {
1707  if (fTypeNameTag.Length() > 0) {
1708  clones->SetClass(subelem->at(fTypeNameTag.Data()).get<std::string>().c_str(), size);
1709  } else {
1710  Error("JsonReadCollection",
1711  "Cannot detect class name for TClonesArray - typename tag not configured");
1712  return;
1713  }
1714  } else if (size > clones->GetSize()) {
1715  Error("JsonReadCollection", "TClonesArray size %d smaller than required %d", clones->GetSize(), size);
1716  return;
1717  }
1718  }
1719  objClass = clones->GetClass();
1720  subobj = clones->ConstructedAt(n);
1721  }
1722 
1723  subobj = JsonReadObject(subobj, objClass, &readClass);
1724 
1725  PopStack();
1726 
1727  if (clones)
1728  continue;
1729 
1730  if (!subobj || !readClass) {
1731  subobj = nullptr;
1732  } else if (readClass->GetBaseClassOffset(TObject::Class()) != 0) {
1733  Error("JsonReadCollection", "Try to add object %s not derived from TObject", readClass->GetName());
1734  subobj = nullptr;
1735  }
1736 
1737  TObject *tobj = static_cast<TObject *>(subobj);
1738 
1739  if (map) {
1740  PushStack(0, &arr.at(n).at("second"));
1741 
1742  readClass = nullptr;
1743  void *subobj2 = JsonReadObject(nullptr, nullptr, &readClass);
1744 
1745  PopStack();
1746 
1747  if (!subobj2 || !readClass) {
1748  subobj2 = nullptr;
1749  } else if (readClass->GetBaseClassOffset(TObject::Class()) != 0) {
1750  Error("JsonReadCollection", "Try to add object %s not derived from TObject", readClass->GetName());
1751  subobj2 = nullptr;
1752  }
1753 
1754  map->Add(tobj, static_cast<TObject *>(subobj2));
1755  } else if (lst) {
1756  std::string opt = json->at("opt").at(n).get<std::string>();
1757  lst->Add(tobj, opt.c_str());
1758  } else {
1759  // generic method, all kinds of TCollection should work
1760  col->Add(tobj);
1761  }
1762  }
1763 }
1764 
1765 ////////////////////////////////////////////////////////////////////////////////
1766 /// Read object from current JSON node
1767 
1768 void *TBufferJSON::JsonReadObject(void *obj, const TClass *objClass, TClass **readClass)
1769 {
1770  if (readClass)
1771  *readClass = nullptr;
1772 
1773  TJSONStackObj *stack = Stack();
1774 
1775  Bool_t process_stl = stack->IsStl();
1776  nlohmann::json *json = stack->GetStlNode();
1777 
1778  // check if null pointer
1779  if (json->is_null())
1780  return nullptr;
1781 
1782  Int_t special_kind = JsonSpecialClass(objClass);
1783 
1784  // Extract pointer
1785  if (json->is_object() && (json->size() == 1) && (json->find("$ref") != json->end())) {
1786  unsigned refid = json->at("$ref").get<unsigned>();
1787 
1788  void *ref_obj = nullptr;
1789  TClass *ref_cl = nullptr;
1790 
1791  GetMappedObject(refid + 1, ref_obj, ref_cl);
1792 
1793  if (!ref_obj || !ref_cl) {
1794  Error("JsonReadObject", "Fail to find object for reference %u", refid);
1795  return nullptr;
1796  }
1797 
1798  if (readClass)
1799  *readClass = ref_cl;
1800 
1801  if (gDebug > 2)
1802  Info("JsonReadObject", "Extract object reference %u %p cl:%s expects:%s", refid, ref_obj, ref_cl->GetName(),
1803  (objClass ? objClass->GetName() : "---"));
1804 
1805  return ref_obj;
1806  }
1807 
1808  // special case of strings - they do not create JSON object, but just string
1809  if ((special_kind == json_stdstring) || (special_kind == json_TString)) {
1810  if (!obj)
1811  obj = objClass->New();
1812 
1813  if (gDebug > 2)
1814  Info("JsonReadObject", "Read string from %s", json->dump().c_str());
1815 
1816  if (special_kind == json_stdstring)
1817  *((std::string *)obj) = json->get<std::string>();
1818  else
1819  *((TString *)obj) = json->get<std::string>().c_str();
1820 
1821  if (readClass)
1822  *readClass = const_cast<TClass *>(objClass);
1823 
1824  return obj;
1825  }
1826 
1827  Bool_t isBase = (stack->fElem && objClass) ? stack->fElem->IsBase() : kFALSE; // base class
1828 
1829  if (isBase && (!obj || !objClass)) {
1830  Error("JsonReadObject", "No object when reading base class");
1831  return obj;
1832  }
1833 
1834  Int_t map_convert = 0;
1835  if ((special_kind == TClassEdit::kMap) || (special_kind == TClassEdit::kMultiMap) ||
1836  (special_kind == TClassEdit::kUnorderedMap) || (special_kind == TClassEdit::kUnorderedMultiMap)) {
1837  map_convert = json->is_object() ? 2 : 1; // check if map was written as array or as object
1838  }
1839 
1840  // from now all operations performed with sub-element,
1841  // stack should be repaired at the end
1842  if (process_stl)
1843  stack = PushStack(0, json);
1844 
1845  TClass *jsonClass = nullptr;
1846  Int_t jsonClassVersion = 0;
1847 
1848  if ((special_kind == json_TArray) || ((special_kind > 0) && (special_kind < ROOT::kSTLend))) {
1849 
1850  jsonClass = const_cast<TClass *>(objClass);
1851 
1852  if (!obj)
1853  obj = jsonClass->New();
1854 
1855  Int_t len = stack->IsJsonArray(json, map_convert == 2 ? fTypeNameTag.Data() : nullptr);
1856 
1857  stack->PushIntValue(len > 0 ? len : 0);
1858 
1859  if (len < 0) // should never happens
1860  Error("JsonReadObject", "Not array when expecting such %s", json->dump().c_str());
1861 
1862  if (gDebug > 1)
1863  Info("JsonReadObject", "Reading special kind %d %s ptr %p", special_kind, objClass->GetName(), obj);
1864 
1865  } else if (isBase) {
1866  // base class has special handling - no additional level and no extra refid
1867 
1868  jsonClass = const_cast<TClass *>(objClass);
1869 
1870  if (gDebug > 1)
1871  Info("JsonReadObject", "Reading baseclass %s ptr %p", objClass->GetName(), obj);
1872  } else {
1873 
1874  if ((fTypeNameTag.Length() > 0) && (json->count(fTypeNameTag.Data()) > 0)) {
1875  std::string clname = json->at(fTypeNameTag.Data()).get<std::string>();
1876  jsonClass = TClass::GetClass(clname.c_str());
1877  if (!jsonClass)
1878  Error("JsonReadObject", "Cannot find class %s", clname.c_str());
1879  } else {
1880  // try to use class which is assigned by streamers - better than nothing
1881  jsonClass = const_cast<TClass *>(objClass);
1882  }
1883 
1884  if (!jsonClass) {
1885  if (process_stl)
1886  PopStack();
1887  return obj;
1888  }
1889 
1890  if ((fTypeVersionTag.Length() > 0) && (json->count(fTypeVersionTag.Data()) > 0))
1891  jsonClassVersion = json->at(fTypeVersionTag.Data()).get<int>();
1892 
1893  if (objClass && (jsonClass != objClass)) {
1894  if (obj || (jsonClass->GetBaseClassOffset(objClass) != 0)) {
1895  if (jsonClass->GetBaseClassOffset(objClass) < 0)
1896  Error("JsonReadObject", "Not possible to read %s and casting to %s pointer as the two classes are unrelated",
1897  jsonClass->GetName(), objClass->GetName());
1898  else
1899  Error("JsonReadObject", "Reading %s and casting to %s pointer is currently not supported",
1900  jsonClass->GetName(), objClass->GetName());
1901  if (process_stl)
1902  PopStack();
1903  return obj;
1904  }
1905  }
1906 
1907  if (!obj)
1908  obj = jsonClass->New();
1909 
1910  if (gDebug > 1)
1911  Info("JsonReadObject", "Reading object of class %s refid %u ptr %p", jsonClass->GetName(), fJsonrCnt, obj);
1912 
1913  if (!special_kind)
1914  special_kind = JsonSpecialClass(jsonClass);
1915 
1916  // add new element to the reading map
1917  MapObject(obj, jsonClass, ++fJsonrCnt);
1918  }
1919 
1920  // there are two ways to handle custom streamers
1921  // either prepare data before streamer and tweak basic function which are reading values like UInt32_t
1922  // or try re-implement custom streamer here
1923 
1924  if ((jsonClass == TObject::Class()) || (jsonClass == TRef::Class())) {
1925  // for TObject we re-implement custom streamer - it is much easier
1926 
1928 
1929  } else if (special_kind == json_TCollection) {
1930 
1931  JsonReadCollection((TCollection *)obj, jsonClass);
1932 
1933  } else {
1934 
1935  Bool_t do_read = kTRUE;
1936 
1937  // special handling of STL which coded into arrays
1938  if ((special_kind > 0) && (special_kind < ROOT::kSTLend))
1939  do_read = stack->AssignStl(jsonClass, map_convert, fTypeNameTag.Data());
1940 
1941  // if provided - use class version from JSON
1942  stack->fClVersion = jsonClassVersion ? jsonClassVersion : jsonClass->GetClassVersion();
1943 
1944  if (gDebug > 3)
1945  Info("JsonReadObject", "Calling streamer of class %s", jsonClass->GetName());
1946 
1947  if (isBase && (special_kind == 0))
1948  Error("JsonReadObject", "Should not be used for reading of base class %s", jsonClass->GetName());
1949 
1950  if (do_read)
1951  jsonClass->Streamer((void *)obj, *this);
1952 
1953  stack->fClVersion = 0;
1954 
1955  stack->ClearStl(); // reset STL index for itself to prevent looping
1956  }
1957 
1958  // return back stack position
1959  if (process_stl)
1960  PopStack();
1961 
1962  if (gDebug > 1)
1963  Info("JsonReadObject", "Reading object of class %s done", jsonClass->GetName());
1964 
1965  if (readClass)
1966  *readClass = jsonClass;
1967 
1968  return obj;
1969 }
1970 
1971 ////////////////////////////////////////////////////////////////////////////////
1972 /// Read TObject data members from JSON.
1973 /// Do not call TObject::Streamer() to avoid special tweaking of TBufferJSON interface
1974 
1976 {
1977  nlohmann::json *json = node ? (nlohmann::json *)node : Stack()->fNode;
1978 
1979  UInt_t uid = json->at("fUniqueID").get<unsigned>();
1980  UInt_t bits = json->at("fBits").get<unsigned>();
1981  // UInt32_t pid = json->at("fPID").get<unsigned>(); // ignore PID for the moment
1982 
1983  tobj->SetUniqueID(uid);
1984 
1985  static auto tobj_fbits_offset = TObject::Class()->GetDataMemberOffset("fBits");
1986 
1987  // there is no method to set all bits directly - do it differently
1988  if (tobj_fbits_offset > 0) {
1989  UInt_t *fbits = (UInt_t *) ((char* ) tobj + tobj_fbits_offset);
1990  *fbits = (*fbits & (TObject::kIsOnHeap | TObject::kNotDeleted)) | bits;
1991  }
1992 }
1993 
1994 ////////////////////////////////////////////////////////////////////////////////
1995 /// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
1996 /// and indent new level in json structure.
1997 /// This call indicates, that TStreamerInfo functions starts streaming
1998 /// object data of correspondent class
1999 
2001 {
2002  if (gDebug > 2)
2003  Info("IncrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
2004 
2005  WorkWithClass((TStreamerInfo *)info);
2006 }
2007 
2008 ////////////////////////////////////////////////////////////////////////////////
2009 /// Prepares buffer to stream data of specified class
2010 
2012 {
2013  if (sinfo)
2014  cl = sinfo->GetClass();
2015 
2016  if (!cl)
2017  return;
2018 
2019  if (gDebug > 3)
2020  Info("WorkWithClass", "Class: %s", cl->GetName());
2021 
2022  TJSONStackObj *stack = Stack();
2023 
2024  if (IsReading()) {
2025  stack = PushStack(0, stack->fNode);
2026  } else if (stack && stack->IsStreamerElement() && !stack->fIsObjStarted &&
2027  ((stack->fElem->GetType() == TStreamerInfo::kObject) ||
2028  (stack->fElem->GetType() == TStreamerInfo::kAny))) {
2029 
2030  stack->fIsObjStarted = kTRUE;
2031 
2032  fJsonrCnt++; // count object, but do not keep reference
2033 
2034  stack = JsonStartObjectWrite(cl, sinfo);
2035  } else {
2036  stack = PushStack(0);
2037  }
2038 
2039  stack->fInfo = sinfo;
2040  stack->fIsStreamerInfo = kTRUE;
2041 }
2042 
2043 ////////////////////////////////////////////////////////////////////////////////
2044 /// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
2045 /// and decrease level in json structure.
2046 
2048 {
2049  if (gDebug > 2)
2050  Info("DecrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
2051 
2052  TJSONStackObj *stack = Stack();
2053 
2054  if (stack->IsStreamerElement()) {
2055 
2056  if (IsWriting()) {
2057  if (gDebug > 3)
2058  Info("DecrementLevel", " Perform post-processing elem: %s", stack->fElem->GetName());
2059 
2060  PerformPostProcessing(stack);
2061  }
2062 
2063  stack = PopStack(); // remove stack of last element
2064  }
2065 
2066  if (stack->fInfo != (TStreamerInfo *)info)
2067  Error("DecrementLevel", " Mismatch of streamer info");
2068 
2069  PopStack(); // back from data of stack info
2070 
2071  if (gDebug > 3)
2072  Info("DecrementLevel", "Class: %s done", (info ? info->GetClass()->GetName() : "custom"));
2073 }
2074 
2075 ////////////////////////////////////////////////////////////////////////////////
2076 /// Return current streamer info element
2077 
2079 {
2080  return Stack()->fInfo;
2081 }
2082 
2083 ////////////////////////////////////////////////////////////////////////////////
2084 /// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
2085 /// and add/verify next element of json structure
2086 /// This calls allows separate data, correspondent to one class member, from another
2087 
2089 {
2090  if (gDebug > 3)
2091  Info("SetStreamerElementNumber", "Element name %s", elem->GetName());
2092 
2093  WorkWithElement(elem, comp_type);
2094 }
2095 
2096 ////////////////////////////////////////////////////////////////////////////////
2097 /// This is call-back from streamer which indicates
2098 /// that class member will be streamed
2099 /// Name of element used in JSON
2100 
2102 {
2103  TJSONStackObj *stack = Stack();
2104  if (!stack) {
2105  Error("WorkWithElement", "stack is empty");
2106  return;
2107  }
2108 
2109  if (gDebug > 0)
2110  Info("WorkWithElement", " Start element %s type %d typename %s", elem ? elem->GetName() : "---",
2111  elem ? elem->GetType() : -1, elem ? elem->GetTypeName() : "---");
2112 
2113  if (stack->IsStreamerElement()) {
2114  // this is post processing
2115 
2116  if (IsWriting()) {
2117  if (gDebug > 3)
2118  Info("WorkWithElement", " Perform post-processing elem: %s", stack->fElem->GetName());
2119  PerformPostProcessing(stack);
2120  }
2121 
2122  stack = PopStack(); // go level back
2123  }
2124 
2125  fValue.Clear();
2126 
2127  if (!stack) {
2128  Error("WorkWithElement", "Lost of stack");
2129  return;
2130  }
2131 
2132  TStreamerInfo *info = stack->fInfo;
2133  if (!stack->IsStreamerInfo()) {
2134  Error("WorkWithElement", "Problem in Inc/Dec level");
2135  return;
2136  }
2137 
2138  Int_t number = info ? info->GetElements()->IndexOf(elem) : -1;
2139 
2140  if (!elem) {
2141  Error("WorkWithElement", "streamer info returns elem = nullptr");
2142  return;
2143  }
2144 
2145  TClass *base_class = elem->IsBase() ? elem->GetClassPointer() : nullptr;
2146 
2147  stack = PushStack(0, stack->fNode);
2148  stack->fElem = elem;
2149  stack->fIsElemOwner = (number < 0);
2150 
2151  JsonStartElement(elem, base_class);
2152 
2153  if (base_class && IsReading())
2154  stack->fClVersion = base_class->GetClassVersion();
2155 
2156  if ((elem->GetType() == TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop) && (elem->GetArrayDim() > 0)) {
2157  // array of array, start handling here
2158  stack->fIndx = std::make_unique<TArrayIndexProducer>(elem, -1, fArraySepar.Data());
2159  if (IsWriting())
2160  AppendOutput(stack->fIndx->GetBegin());
2161  }
2162 
2163  if (IsReading() && (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20)) {
2164  // reading of such array begins with reading of single Char_t value
2165  // it indicates if array should be read or not
2166  stack->PushIntValue(stack->IsJsonString() || (stack->IsJsonArray() > 0) ? 1 : 0);
2167  }
2168 }
2169 
2170 ////////////////////////////////////////////////////////////////////////////////
2171 /// Should be called in the beginning of custom class streamer.
2172 /// Informs buffer data about class which will be streamed now.
2173 ///
2174 /// ClassBegin(), ClassEnd() and ClassMember() should be used in
2175 /// custom class streamers to specify which kind of data are
2176 /// now streamed. Such information is used to correctly
2177 /// convert class data to JSON. Without that functions calls
2178 /// classes with custom streamers cannot be used with TBufferJSON
2179 
2181 {
2182  WorkWithClass(nullptr, cl);
2183 }
2184 
2185 ////////////////////////////////////////////////////////////////////////////////
2186 /// Should be called at the end of custom streamer
2187 /// See TBufferJSON::ClassBegin for more details
2188 
2190 {
2191  DecrementLevel(0);
2192 }
2193 
2194 ////////////////////////////////////////////////////////////////////////////////
2195 /// Method indicates name and typename of class member,
2196 /// which should be now streamed in custom streamer
2197 /// Following combinations are supported:
2198 /// 1. name = "ClassName", typeName = 0 or typename==ClassName
2199 /// This is a case, when data of parent class "ClassName" should be streamed.
2200 /// For instance, if class directly inherited from TObject, custom
2201 /// streamer should include following code:
2202 /// ~~~{.cpp}
2203 /// b.ClassMember("TObject");
2204 /// TObject::Streamer(b);
2205 /// ~~~
2206 /// 2. Basic data type
2207 /// ~~~{.cpp}
2208 /// b.ClassMember("fInt","Int_t");
2209 /// b >> fInt;
2210 /// ~~~
2211 /// 3. Array of basic data types
2212 /// ~~~{.cpp}
2213 /// b.ClassMember("fArr","Int_t", 5);
2214 /// b.ReadFastArray(fArr, 5);
2215 /// ~~~
2216 /// 4. Object as data member
2217 /// ~~~{.cpp}
2218 /// b.ClassMember("fName","TString");
2219 /// fName.Streamer(b);
2220 /// ~~~
2221 /// 5. Pointer on object as data member
2222 /// ~~~{.cpp}
2223 /// b.ClassMember("fObj","TObject*");
2224 /// b.StreamObject(fObj);
2225 /// ~~~
2226 ///
2227 /// arrsize1 and arrsize2 arguments (when specified) indicate first and
2228 /// second dimension of array. Can be used for array of basic types.
2229 /// See ClassBegin() method for more details.
2230 
2231 void TBufferJSON::ClassMember(const char *name, const char *typeName, Int_t arrsize1, Int_t arrsize2)
2232 {
2233  if (!typeName)
2234  typeName = name;
2235 
2236  if (!name || (strlen(name) == 0)) {
2237  Error("ClassMember", "Invalid member name");
2238  return;
2239  }
2240 
2241  TString tname = typeName;
2242 
2243  Int_t typ_id = -1;
2244 
2245  if (strcmp(typeName, "raw:data") == 0)
2246  typ_id = TStreamerInfo::kMissing;
2247 
2248  if (typ_id < 0) {
2249  TDataType *dt = gROOT->GetType(typeName);
2250  if (dt && (dt->GetType() > 0) && (dt->GetType() < 20))
2251  typ_id = dt->GetType();
2252  }
2253 
2254  if (typ_id < 0)
2255  if (strcmp(name, typeName) == 0) {
2256  TClass *cl = TClass::GetClass(tname.Data());
2257  if (cl)
2258  typ_id = TStreamerInfo::kBase;
2259  }
2260 
2261  if (typ_id < 0) {
2262  Bool_t isptr = kFALSE;
2263  if (tname[tname.Length() - 1] == '*') {
2264  tname.Resize(tname.Length() - 1);
2265  isptr = kTRUE;
2266  }
2267  TClass *cl = TClass::GetClass(tname.Data());
2268  if (!cl) {
2269  Error("ClassMember", "Invalid class specifier %s", typeName);
2270  return;
2271  }
2272 
2273  if (cl->IsTObject())
2275  else
2276  typ_id = isptr ? TStreamerInfo::kAnyp : TStreamerInfo::kAny;
2277 
2278  if ((cl == TString::Class()) && !isptr)
2279  typ_id = TStreamerInfo::kTString;
2280  }
2281 
2282  TStreamerElement *elem = nullptr;
2283 
2284  if (typ_id == TStreamerInfo::kMissing) {
2285  elem = new TStreamerElement(name, "title", 0, typ_id, "raw:data");
2286  } else if (typ_id == TStreamerInfo::kBase) {
2287  TClass *cl = TClass::GetClass(tname.Data());
2288  if (cl) {
2289  TStreamerBase *b = new TStreamerBase(tname.Data(), "title", 0);
2290  b->SetBaseVersion(cl->GetClassVersion());
2291  elem = b;
2292  }
2293  } else if ((typ_id > 0) && (typ_id < 20)) {
2294  elem = new TStreamerBasicType(name, "title", 0, typ_id, typeName);
2295  } else if ((typ_id == TStreamerInfo::kObject) || (typ_id == TStreamerInfo::kTObject) ||
2296  (typ_id == TStreamerInfo::kTNamed)) {
2297  elem = new TStreamerObject(name, "title", 0, tname.Data());
2298  } else if (typ_id == TStreamerInfo::kObjectp) {
2299  elem = new TStreamerObjectPointer(name, "title", 0, tname.Data());
2300  } else if (typ_id == TStreamerInfo::kAny) {
2301  elem = new TStreamerObjectAny(name, "title", 0, tname.Data());
2302  } else if (typ_id == TStreamerInfo::kAnyp) {
2303  elem = new TStreamerObjectAnyPointer(name, "title", 0, tname.Data());
2304  } else if (typ_id == TStreamerInfo::kTString) {
2305  elem = new TStreamerString(name, "title", 0);
2306  }
2307 
2308  if (!elem) {
2309  Error("ClassMember", "Invalid combination name = %s type = %s", name, typeName);
2310  return;
2311  }
2312 
2313  if (arrsize1 > 0) {
2314  elem->SetArrayDim(arrsize2 > 0 ? 2 : 1);
2315  elem->SetMaxIndex(0, arrsize1);
2316  if (arrsize2 > 0)
2317  elem->SetMaxIndex(1, arrsize2);
2318  }
2319 
2320  // we indicate that there is no streamerinfo
2321  WorkWithElement(elem, -1);
2322 }
2323 
2324 ////////////////////////////////////////////////////////////////////////////////
2325 /// Function is converts TObject and TString structures to more compact representation
2326 
2327 void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_cl)
2328 {
2329  if (stack->fIsPostProcessed)
2330  return;
2331 
2332  const TStreamerElement *elem = stack->fElem;
2333 
2334  if (!elem && !obj_cl)
2335  return;
2336 
2337  stack->fIsPostProcessed = kTRUE;
2338 
2339  // when element was written as separate object, close only braces and exit
2340  if (stack->fIsObjStarted) {
2341  AppendOutput("", "}");
2342  return;
2343  }
2344 
2345  Bool_t isTObject(kFALSE), isTRef(kFALSE), isTString(kFALSE), isSTLstring(kFALSE), isOffsetPArray(kFALSE),
2346  isTArray(kFALSE);
2347 
2348  if (obj_cl) {
2349  if (obj_cl == TObject::Class())
2350  isTObject = kTRUE;
2351  else if (obj_cl == TRef::Class())
2352  isTRef = kTRUE;
2353  else
2354  return;
2355  } else {
2356  const char *typname = elem->IsBase() ? elem->GetName() : elem->GetTypeName();
2357  isTObject = (elem->GetType() == TStreamerInfo::kTObject) || (strcmp("TObject", typname) == 0);
2358  isTString = elem->GetType() == TStreamerInfo::kTString;
2359  isSTLstring = elem->GetType() == TStreamerInfo::kSTLstring;
2360  isOffsetPArray = (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20);
2361  isTArray = (strncmp("TArray", typname, 6) == 0);
2362  }
2363 
2364  if (isTString || isSTLstring) {
2365  // just remove all kind of string length information
2366 
2367  if (gDebug > 3)
2368  Info("PerformPostProcessing", "reformat string value = '%s'", fValue.Data());
2369 
2370  stack->fValues.clear();
2371  } else if (isOffsetPArray) {
2372  // basic array with [fN] comment
2373 
2374  if (stack->fValues.empty() && (fValue == "0")) {
2375  fValue = "[]";
2376  } else if ((stack->fValues.size() == 1) && (stack->fValues[0] == "1")) {
2377  stack->fValues.clear();
2378  } else {
2379  Error("PerformPostProcessing", "Wrong values for kOffsetP element %s", (elem ? elem->GetName() : "---"));
2380  stack->fValues.clear();
2381  fValue = "[]";
2382  }
2383  } else if (isTObject || isTRef) {
2384  // complex workaround for TObject/TRef streamer
2385  // would be nice if other solution can be found
2386  // Here is not supported TRef on TRef (double reference)
2387 
2388  Int_t cnt = stack->fValues.size();
2389  if (fValue.Length() > 0)
2390  cnt++;
2391 
2392  if (cnt < 2 || cnt > 3) {
2393  if (gDebug > 0)
2394  Error("PerformPostProcessing", "When storing TObject/TRef, strange number of items %d", cnt);
2395  AppendOutput(stack->NextMemberSeparator(), "\"dummy\"");
2397  } else {
2398  AppendOutput(stack->NextMemberSeparator(), "\"fUniqueID\"");
2400  AppendOutput(stack->fValues[0].c_str());
2401  AppendOutput(stack->NextMemberSeparator(), "\"fBits\"");
2403  auto tbits = std::atol((stack->fValues.size() > 1) ? stack->fValues[1].c_str() : fValue.Data());
2404  AppendOutput(std::to_string(tbits & ~TObject::kNotDeleted & ~TObject::kIsOnHeap).c_str());
2405  if (cnt == 3) {
2406  AppendOutput(stack->NextMemberSeparator(), "\"fPID\"");
2408  AppendOutput((stack->fValues.size() > 2) ? stack->fValues[2].c_str() : fValue.Data());
2409  }
2410 
2411  stack->fValues.clear();
2412  fValue.Clear();
2413  return;
2414  }
2415 
2416  } else if (isTArray) {
2417  // for TArray one deletes complete stack
2418  stack->fValues.clear();
2419  }
2420 
2421  if (elem && elem->IsBase() && (fValue.Length() == 0)) {
2422  // here base class data already completely stored
2423  return;
2424  }
2425 
2426  if (!stack->fValues.empty()) {
2427  // append element blob data just as abstract array, user is responsible to decode it
2428  AppendOutput("[");
2429  for (auto &blob: stack->fValues) {
2430  AppendOutput(blob.c_str());
2432  }
2433  }
2434 
2435  if (fValue.Length() == 0) {
2436  AppendOutput("null");
2437  } else {
2439  fValue.Clear();
2440  }
2441 
2442  if (!stack->fValues.empty())
2443  AppendOutput("]");
2444 }
2445 
2446 ////////////////////////////////////////////////////////////////////////////////
2447 /// suppressed function of TBuffer
2448 
2450 {
2451  return nullptr;
2452 }
2453 
2454 ////////////////////////////////////////////////////////////////////////////////
2455 /// suppressed function of TBuffer
2456 
2458 
2459 ////////////////////////////////////////////////////////////////////////////////
2460 /// read version value from buffer
2461 
2463 {
2464  Version_t res = cl ? cl->GetClassVersion() : 0;
2465 
2466  if (start)
2467  *start = 0;
2468  if (bcnt)
2469  *bcnt = 0;
2470 
2471  if (!cl && Stack()->fClVersion) {
2472  res = Stack()->fClVersion;
2473  Stack()->fClVersion = 0;
2474  }
2475 
2476  if (gDebug > 3)
2477  Info("ReadVersion", "Result: %d Class: %s", res, (cl ? cl->GetName() : "---"));
2478 
2479  return res;
2480 }
2481 
2482 ////////////////////////////////////////////////////////////////////////////////
2483 /// Ignored in TBufferJSON
2484 
2485 UInt_t TBufferJSON::WriteVersion(const TClass * /*cl*/, Bool_t /* useBcnt */)
2486 {
2487  return 0;
2488 }
2489 
2490 ////////////////////////////////////////////////////////////////////////////////
2491 /// Read object from buffer. Only used from TBuffer
2492 
2493 void *TBufferJSON::ReadObjectAny(const TClass *expectedClass)
2494 {
2495  if (gDebug > 2)
2496  Info("ReadObjectAny", "From current JSON node");
2497  void *res = JsonReadObject(nullptr, expectedClass);
2498  return res;
2499 }
2500 
2501 ////////////////////////////////////////////////////////////////////////////////
2502 /// Skip any kind of object from buffer
2503 
2505 
2506 ////////////////////////////////////////////////////////////////////////////////
2507 /// Write object to buffer. Only used from TBuffer
2508 
2509 void TBufferJSON::WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse)
2510 {
2511  if (gDebug > 3)
2512  Info("WriteObjectClass", "Class %s", (actualClass ? actualClass->GetName() : " null"));
2513 
2514  JsonWriteObject(actualObjStart, actualClass, cacheReuse);
2515 }
2516 
2517 ////////////////////////////////////////////////////////////////////////////////
2518 /// If value exists, push in the current stack for post-processing
2519 
2521 {
2522  if (fValue.Length() > 0)
2523  Stack()->PushValue(fValue);
2524 }
2525 
2526 ////////////////////////////////////////////////////////////////////////////////
2527 /// Read array of Bool_t from buffer
2528 
2530 {
2531  return JsonReadArray(b);
2532 }
2533 
2534 ////////////////////////////////////////////////////////////////////////////////
2535 /// Read array of Char_t from buffer
2536 
2538 {
2539  return JsonReadArray(c);
2540 }
2541 
2542 ////////////////////////////////////////////////////////////////////////////////
2543 /// Read array of UChar_t from buffer
2544 
2546 {
2547  return JsonReadArray(c);
2548 }
2549 
2550 ////////////////////////////////////////////////////////////////////////////////
2551 /// Read array of Short_t from buffer
2552 
2554 {
2555  return JsonReadArray(h);
2556 }
2557 
2558 ////////////////////////////////////////////////////////////////////////////////
2559 /// Read array of UShort_t from buffer
2560 
2562 {
2563  return JsonReadArray(h);
2564 }
2565 
2566 ////////////////////////////////////////////////////////////////////////////////
2567 /// Read array of Int_t from buffer
2568 
2570 {
2571  return JsonReadArray(i);
2572 }
2573 
2574 ////////////////////////////////////////////////////////////////////////////////
2575 /// Read array of UInt_t from buffer
2576 
2578 {
2579  return JsonReadArray(i);
2580 }
2581 
2582 ////////////////////////////////////////////////////////////////////////////////
2583 /// Read array of Long_t from buffer
2584 
2586 {
2587  return JsonReadArray(l);
2588 }
2589 
2590 ////////////////////////////////////////////////////////////////////////////////
2591 /// Read array of ULong_t from buffer
2592 
2594 {
2595  return JsonReadArray(l);
2596 }
2597 
2598 ////////////////////////////////////////////////////////////////////////////////
2599 /// Read array of Long64_t from buffer
2600 
2602 {
2603  return JsonReadArray(l);
2604 }
2605 
2606 ////////////////////////////////////////////////////////////////////////////////
2607 /// Read array of ULong64_t from buffer
2608 
2610 {
2611  return JsonReadArray(l);
2612 }
2613 
2614 ////////////////////////////////////////////////////////////////////////////////
2615 /// Read array of Float_t from buffer
2616 
2618 {
2619  return JsonReadArray(f);
2620 }
2621 
2622 ////////////////////////////////////////////////////////////////////////////////
2623 /// Read array of Double_t from buffer
2624 
2626 {
2627  return JsonReadArray(d);
2628 }
2629 
2630 ////////////////////////////////////////////////////////////////////////////////
2631 /// Read static array from JSON - not used
2632 
2633 template <typename T>
2635 {
2636  Info("ReadArray", "Not implemented");
2637  return value ? 1 : 0;
2638 }
2639 
2640 ////////////////////////////////////////////////////////////////////////////////
2641 /// Read array of Bool_t from buffer
2642 
2644 {
2645  return JsonReadArray(b);
2646 }
2647 
2648 ////////////////////////////////////////////////////////////////////////////////
2649 /// Read array of Char_t from buffer
2650 
2652 {
2653  return JsonReadArray(c);
2654 }
2655 
2656 ////////////////////////////////////////////////////////////////////////////////
2657 /// Read array of UChar_t from buffer
2658 
2660 {
2661  return JsonReadArray(c);
2662 }
2663 
2664 ////////////////////////////////////////////////////////////////////////////////
2665 /// Read array of Short_t from buffer
2666 
2668 {
2669  return JsonReadArray(h);
2670 }
2671 
2672 ////////////////////////////////////////////////////////////////////////////////
2673 /// Read array of UShort_t from buffer
2674 
2676 {
2677  return JsonReadArray(h);
2678 }
2679 
2680 ////////////////////////////////////////////////////////////////////////////////
2681 /// Read array of Int_t from buffer
2682 
2684 {
2685  return JsonReadArray(i);
2686 }
2687 
2688 ////////////////////////////////////////////////////////////////////////////////
2689 /// Read array of UInt_t from buffer
2690 
2692 {
2693  return JsonReadArray(i);
2694 }
2695 
2696 ////////////////////////////////////////////////////////////////////////////////
2697 /// Read array of Long_t from buffer
2698 
2700 {
2701  return JsonReadArray(l);
2702 }
2703 
2704 ////////////////////////////////////////////////////////////////////////////////
2705 /// Read array of ULong_t from buffer
2706 
2708 {
2709  return JsonReadArray(l);
2710 }
2711 
2712 ////////////////////////////////////////////////////////////////////////////////
2713 /// Read array of Long64_t from buffer
2714 
2716 {
2717  return JsonReadArray(l);
2718 }
2719 
2720 ////////////////////////////////////////////////////////////////////////////////
2721 /// Read array of ULong64_t from buffer
2722 
2724 {
2725  return JsonReadArray(l);
2726 }
2727 
2728 ////////////////////////////////////////////////////////////////////////////////
2729 /// Read array of Float_t from buffer
2730 
2732 {
2733  return JsonReadArray(f);
2734 }
2735 
2736 ////////////////////////////////////////////////////////////////////////////////
2737 /// Read array of Double_t from buffer
2738 
2740 {
2741  return JsonReadArray(d);
2742 }
2743 
2744 ////////////////////////////////////////////////////////////////////////////////
2745 /// Template method to read array from the JSON
2746 
2747 template <typename T>
2748 R__ALWAYS_INLINE void TBufferJSON::JsonReadFastArray(T *arr, Int_t arrsize, bool asstring)
2749 {
2750  if (!arr || (arrsize <= 0))
2751  return;
2752  nlohmann::json *json = Stack()->fNode;
2753  if (gDebug > 2)
2754  Info("ReadFastArray", "Reading array sz %d from JSON %s", arrsize, json->dump().substr(0, 30).c_str());
2755  auto indexes = Stack()->MakeReadIndexes();
2756  if (indexes) { /* at least two dims */
2757  TArrayI &indx = indexes->GetIndices();
2758  Int_t lastdim = indx.GetSize() - 1;
2759  if (indexes->TotalLength() != arrsize)
2760  Error("ReadFastArray", "Mismatch %d-dim array sizes %d %d", lastdim + 1, arrsize, (int)indexes->TotalLength());
2761  for (int cnt = 0; cnt < arrsize; ++cnt) {
2762  nlohmann::json *elem = &(json->at(indx[0]));
2763  for (int k = 1; k < lastdim; ++k)
2764  elem = &((*elem)[indx[k]]);
2765  arr[cnt] = (asstring && elem->is_string()) ? elem->get<std::string>()[indx[lastdim]] : (*elem)[indx[lastdim]].get<T>();
2766  indexes->NextSeparator();
2767  }
2768  } else if (asstring && json->is_string()) {
2769  std::string str = json->get<std::string>();
2770  for (int cnt = 0; cnt < arrsize; ++cnt)
2771  arr[cnt] = (cnt < (int)str.length()) ? str[cnt] : 0;
2772  } else if (json->is_object() && (json->count("$arr") == 1)) {
2773  if (json->at("len").get<int>() != arrsize)
2774  Error("ReadFastArray", "Mismatch compressed array size %d %d", arrsize, json->at("len").get<int>());
2775 
2776  for (int cnt = 0; cnt < arrsize; ++cnt)
2777  arr[cnt] = 0;
2778 
2779  if (json->count("b") == 1) {
2780  auto base64 = json->at("b").get<std::string>();
2781 
2782  int offset = (json->count("o") == 1) ? json->at("o").get<int>() : 0;
2783 
2784  // TODO: provide TBase64::Decode with direct write into target buffer
2785  auto decode = TBase64::Decode(base64.c_str());
2786 
2787  if (arrsize * (long) sizeof(T) < (offset + decode.Length())) {
2788  Error("ReadFastArray", "Base64 data %ld larger than target array size %ld", (long) decode.Length() + offset, (long) (arrsize*sizeof(T)));
2789  } else if ((sizeof(T) > 1) && (decode.Length() % sizeof(T) != 0)) {
2790  Error("ReadFastArray", "Base64 data size %ld not matches with element size %ld", (long) decode.Length(), (long) sizeof(T));
2791  } else {
2792  memcpy((char *) arr + offset, decode.Data(), decode.Length());
2793  }
2794  return;
2795  }
2796 
2797  int p = 0, id = 0;
2798  std::string idname = "", pname, vname, nname;
2799  while (p < arrsize) {
2800  pname = std::string("p") + idname;
2801  if (json->count(pname) == 1)
2802  p = json->at(pname).get<int>();
2803  vname = std::string("v") + idname;
2804  if (json->count(vname) != 1)
2805  break;
2806  nlohmann::json &v = json->at(vname);
2807  if (v.is_array()) {
2808  for (unsigned sub = 0; sub < v.size(); ++sub)
2809  arr[p++] = v[sub].get<T>();
2810  } else {
2811  nname = std::string("n") + idname;
2812  unsigned ncopy = (json->count(nname) == 1) ? json->at(nname).get<unsigned>() : 1;
2813  for (unsigned sub = 0; sub < ncopy; ++sub)
2814  arr[p++] = v.get<T>();
2815  }
2816  idname = std::to_string(++id);
2817  }
2818  } else {
2819  if ((int)json->size() != arrsize)
2820  Error("ReadFastArray", "Mismatch array sizes %d %d", arrsize, (int)json->size());
2821  for (int cnt = 0; cnt < arrsize; ++cnt)
2822  arr[cnt] = json->at(cnt).get<T>();
2823  }
2824 }
2825 
2826 ////////////////////////////////////////////////////////////////////////////////
2827 /// read array of Bool_t from buffer
2828 
2830 {
2831  JsonReadFastArray(b, n);
2832 }
2833 
2834 ////////////////////////////////////////////////////////////////////////////////
2835 /// read array of Char_t from buffer
2836 
2838 {
2839  JsonReadFastArray(c, n, true);
2840 }
2841 
2842 ////////////////////////////////////////////////////////////////////////////////
2843 /// read array of Char_t from buffer
2844 
2846 {
2847  JsonReadFastArray(c, n, true);
2848 }
2849 
2850 ////////////////////////////////////////////////////////////////////////////////
2851 /// read array of UChar_t from buffer
2852 
2854 {
2855  JsonReadFastArray(c, n);
2856 }
2857 
2858 ////////////////////////////////////////////////////////////////////////////////
2859 /// read array of Short_t from buffer
2860 
2862 {
2863  JsonReadFastArray(h, n);
2864 }
2865 
2866 ////////////////////////////////////////////////////////////////////////////////
2867 /// read array of UShort_t from buffer
2868 
2870 {
2871  JsonReadFastArray(h, n);
2872 }
2873 
2874 ////////////////////////////////////////////////////////////////////////////////
2875 /// read array of Int_t from buffer
2876 
2878 {
2879  JsonReadFastArray(i, n);
2880 }
2881 
2882 ////////////////////////////////////////////////////////////////////////////////
2883 /// read array of UInt_t from buffer
2884 
2886 {
2887  JsonReadFastArray(i, n);
2888 }
2889 
2890 ////////////////////////////////////////////////////////////////////////////////
2891 /// read array of Long_t from buffer
2892 
2894 {
2895  JsonReadFastArray(l, n);
2896 }
2897 
2898 ////////////////////////////////////////////////////////////////////////////////
2899 /// read array of ULong_t from buffer
2900 
2902 {
2903  JsonReadFastArray(l, n);
2904 }
2905 
2906 ////////////////////////////////////////////////////////////////////////////////
2907 /// read array of Long64_t from buffer
2908 
2910 {
2911  JsonReadFastArray(l, n);
2912 }
2913 
2914 ////////////////////////////////////////////////////////////////////////////////
2915 /// read array of ULong64_t from buffer
2916 
2918 {
2919  JsonReadFastArray(l, n);
2920 }
2921 
2922 ////////////////////////////////////////////////////////////////////////////////
2923 /// read array of Float_t from buffer
2924 
2926 {
2927  JsonReadFastArray(f, n);
2928 }
2929 
2930 ////////////////////////////////////////////////////////////////////////////////
2931 /// read array of Double_t from buffer
2932 
2934 {
2935  JsonReadFastArray(d, n);
2936 }
2937 
2938 ////////////////////////////////////////////////////////////////////////////////
2939 /// Read an array of 'n' objects from the I/O buffer.
2940 /// Stores the objects read starting at the address 'start'.
2941 /// The objects in the array are assume to be of class 'cl'.
2942 /// Copied code from TBufferFile
2943 
2944 void TBufferJSON::ReadFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer * /* streamer */,
2945  const TClass * /* onFileClass */)
2946 {
2947  if (gDebug > 1)
2948  Info("ReadFastArray", "void* n:%d cl:%s", n, cl->GetName());
2949 
2950  // if (streamer) {
2951  // Info("ReadFastArray", "(void*) Calling streamer - not handled correctly");
2952  // streamer->SetOnFileClass(onFileClass);
2953  // (*streamer)(*this, start, 0);
2954  // return;
2955  // }
2956 
2957  int objectSize = cl->Size();
2958  char *obj = (char *)start;
2959 
2960  TJSONStackObj *stack = Stack();
2961  nlohmann::json *topnode = stack->fNode, *subnode = topnode;
2962  if (stack->fIndx)
2963  subnode = stack->fIndx->ExtractNode(topnode);
2964 
2965  TArrayIndexProducer indexes(stack->fElem, n, "");
2966 
2967  if (gDebug > 1)
2968  Info("ReadFastArray", "Indexes ndim:%d totallen:%d", indexes.NumDimensions(), indexes.TotalLength());
2969 
2970  for (Int_t j = 0; j < n; j++, obj += objectSize) {
2971 
2972  stack->fNode = indexes.ExtractNode(subnode);
2973 
2974  JsonReadObject(obj, cl);
2975  }
2976 
2977  // restore top node - show we use stack here?
2978  stack->fNode = topnode;
2979 }
2980 
2981 ////////////////////////////////////////////////////////////////////////////////
2982 /// redefined here to avoid warning message from gcc
2983 
2984 void TBufferJSON::ReadFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc,
2985  TMemberStreamer * /* streamer */, const TClass * /* onFileClass */)
2986 {
2987  if (gDebug > 1)
2988  Info("ReadFastArray", "void** n:%d cl:%s prealloc:%s", n, cl->GetName(), (isPreAlloc ? "true" : "false"));
2989 
2990  // if (streamer) {
2991  // Info("ReadFastArray", "(void**) Calling streamer - not handled correctly");
2992  // if (isPreAlloc) {
2993  // for (Int_t j = 0; j < n; j++) {
2994  // if (!start[j])
2995  // start[j] = cl->New();
2996  // }
2997  // }
2998  // streamer->SetOnFileClass(onFileClass);
2999  // (*streamer)(*this, (void *)start, 0);
3000  // return;
3001  // }
3002 
3003  TJSONStackObj *stack = Stack();
3004  nlohmann::json *topnode = stack->fNode, *subnode = topnode;
3005  if (stack->fIndx)
3006  subnode = stack->fIndx->ExtractNode(topnode);
3007 
3008  TArrayIndexProducer indexes(stack->fElem, n, "");
3009 
3010  for (Int_t j = 0; j < n; j++) {
3011 
3012  stack->fNode = indexes.ExtractNode(subnode);
3013 
3014  if (!isPreAlloc) {
3015  void *old = start[j];
3016  start[j] = JsonReadObject(nullptr, cl);
3017  if (old && old != start[j] && TStreamerInfo::CanDelete())
3018  (const_cast<TClass *>(cl))->Destructor(old, kFALSE); // call delete and destruct
3019  } else {
3020  if (!start[j])
3021  start[j] = (const_cast<TClass *>(cl))->New();
3022  JsonReadObject(start[j], cl);
3023  }
3024  }
3025 
3026  stack->fNode = topnode;
3027 }
3028 
3029 template <typename T>
3030 R__ALWAYS_INLINE void TBufferJSON::JsonWriteArrayCompress(const T *vname, Int_t arrsize, const char *typname)
3031 {
3032  bool is_base64 = Stack()->fBase64 || (fArrayCompact == kBase64);
3033 
3034  if (!is_base64 && ((fArrayCompact == 0) || (arrsize < 6))) {
3035  fValue.Append("[");
3036  for (Int_t indx = 0; indx < arrsize; indx++) {
3037  if (indx > 0)
3039  JsonWriteBasic(vname[indx]);
3040  }
3041  fValue.Append("]");
3042  } else if (is_base64 && !arrsize) {
3043  fValue.Append("[]");
3044  } else {
3045  fValue.Append("{");
3046  fValue.Append(TString::Format("\"$arr\":\"%s\"%s\"len\":%d", typname, fArraySepar.Data(), arrsize));
3047  Int_t aindx(0), bindx(arrsize);
3048  while ((aindx < arrsize) && (vname[aindx] == 0))
3049  aindx++;
3050  while ((aindx < bindx) && (vname[bindx - 1] == 0))
3051  bindx--;
3052 
3053  if (is_base64) {
3054  // small initial offset makes no sense - JSON code is large then size gain
3055  if ((aindx * sizeof(T) < 5) && (aindx < bindx))
3056  aindx = 0;
3057 
3058  if ((aindx > 0) && (aindx < bindx))
3059  fValue.Append(TString::Format("%s\"o\":%ld", fArraySepar.Data(), (long) (aindx * (int) sizeof(T))));
3060 
3062  fValue.Append("\"b\":\"");
3063 
3064  if (aindx < bindx)
3065  fValue.Append(TBase64::Encode((const char *) (vname + aindx), (bindx - aindx) * sizeof(T)));
3066 
3067  fValue.Append("\"");
3068  } else if (aindx < bindx) {
3069  TString suffix("");
3070  Int_t p(aindx), suffixcnt(-1), lastp(0);
3071  while (p < bindx) {
3072  if (vname[p] == 0) {
3073  p++;
3074  continue;
3075  }
3076  Int_t p0(p++), pp(0), nsame(1);
3078  pp = bindx;
3079  p = bindx + 1;
3080  nsame = 0;
3081  }
3082  for (; p <= bindx; ++p) {
3083  if ((p < bindx) && (vname[p] == vname[p - 1])) {
3084  nsame++;
3085  continue;
3086  }
3087  if (vname[p - 1] == 0) {
3088  if (nsame > 9) {
3089  nsame = 0;
3090  break;
3091  }
3092  } else if (nsame > 5) {
3093  if (pp) {
3094  p = pp;
3095  nsame = 0;
3096  } else
3097  pp = p;
3098  break;
3099  }
3100  pp = p;
3101  nsame = 1;
3102  }
3103  if (pp <= p0)
3104  continue;
3105  if (++suffixcnt > 0)
3106  suffix.Form("%d", suffixcnt);
3107  if (p0 != lastp)
3108  fValue.Append(TString::Format("%s\"p%s\":%d", fArraySepar.Data(), suffix.Data(), p0));
3109  lastp = pp; /* remember cursor, it may be the same */
3110  fValue.Append(TString::Format("%s\"v%s\":", fArraySepar.Data(), suffix.Data()));
3111  if ((nsame > 1) || (pp - p0 == 1)) {
3112  JsonWriteBasic(vname[p0]);
3113  if (nsame > 1)
3114  fValue.Append(TString::Format("%s\"n%s\":%d", fArraySepar.Data(), suffix.Data(), nsame));
3115  } else {
3116  fValue.Append("[");
3117  for (Int_t indx = p0; indx < pp; indx++) {
3118  if (indx > p0)
3120  JsonWriteBasic(vname[indx]);
3121  }
3122  fValue.Append("]");
3123  }
3124  }
3125  }
3126  fValue.Append("}");
3127  }
3128 }
3129 
3130 ////////////////////////////////////////////////////////////////////////////////
3131 /// Write array of Bool_t to buffer
3132 
3134 {
3135  JsonPushValue();
3136  JsonWriteArrayCompress(b, n, "Bool");
3137 }
3138 
3139 ////////////////////////////////////////////////////////////////////////////////
3140 /// Write array of Char_t to buffer
3141 
3143 {
3144  JsonPushValue();
3145  JsonWriteArrayCompress(c, n, "Int8");
3146 }
3147 
3148 ////////////////////////////////////////////////////////////////////////////////
3149 /// Write array of UChar_t to buffer
3150 
3152 {
3153  JsonPushValue();
3154  JsonWriteArrayCompress(c, n, "Uint8");
3155 }
3156 
3157 ////////////////////////////////////////////////////////////////////////////////
3158 /// Write array of Short_t to buffer
3159 
3161 {
3162  JsonPushValue();
3163  JsonWriteArrayCompress(h, n, "Int16");
3164 }
3165 
3166 ////////////////////////////////////////////////////////////////////////////////
3167 /// Write array of UShort_t to buffer
3168 
3170 {
3171  JsonPushValue();
3172  JsonWriteArrayCompress(h, n, "Uint16");
3173 }
3174 
3175 ////////////////////////////////////////////////////////////////////////////////
3176 /// Write array of Int_ to buffer
3177 
3179 {
3180  JsonPushValue();
3181  JsonWriteArrayCompress(i, n, "Int32");
3182 }
3183 
3184 ////////////////////////////////////////////////////////////////////////////////
3185 /// Write array of UInt_t to buffer
3186 
3188 {
3189  JsonPushValue();
3190  JsonWriteArrayCompress(i, n, "Uint32");
3191 }
3192 
3193 ////////////////////////////////////////////////////////////////////////////////
3194 /// Write array of Long_t to buffer
3195 
3197 {
3198  JsonPushValue();
3199  JsonWriteArrayCompress(l, n, "Int64");
3200 }
3201 
3202 ////////////////////////////////////////////////////////////////////////////////
3203 /// Write array of ULong_t to buffer
3204 
3206 {
3207  JsonPushValue();
3208  JsonWriteArrayCompress(l, n, "Uint64");
3209 }
3210 
3211 ////////////////////////////////////////////////////////////////////////////////
3212 /// Write array of Long64_t to buffer
3213 
3215 {
3216  JsonPushValue();
3217  JsonWriteArrayCompress(l, n, "Int64");
3218 }
3219 
3220 ////////////////////////////////////////////////////////////////////////////////
3221 /// Write array of ULong64_t to buffer
3222 
3224 {
3225  JsonPushValue();
3226  JsonWriteArrayCompress(l, n, "Uint64");
3227 }
3228 
3229 ////////////////////////////////////////////////////////////////////////////////
3230 /// Write array of Float_t to buffer
3231 
3233 {
3234  JsonPushValue();
3235  JsonWriteArrayCompress(f, n, "Float32");
3236 }
3237 
3238 ////////////////////////////////////////////////////////////////////////////////
3239 /// Write array of Double_t to buffer
3240 
3242 {
3243  JsonPushValue();
3244  JsonWriteArrayCompress(d, n, "Float64");
3245 }
3246 
3247 ////////////////////////////////////////////////////////////////////////////////
3248 /// Template method to write array of arbitrary dimensions
3249 /// Different methods can be used for store last array dimension -
3250 /// either JsonWriteArrayCompress<T>() or JsonWriteConstChar()
3251 
3252 template <typename T>
3253 R__ALWAYS_INLINE void TBufferJSON::JsonWriteFastArray(const T *arr, Int_t arrsize, const char *typname,
3254  void (TBufferJSON::*method)(const T *, Int_t, const char *))
3255 {
3256  JsonPushValue();
3257  if (arrsize <= 0) { /*fJsonrCnt++;*/
3258  fValue.Append("[]");
3259  return;
3260  }
3261 
3262  TStreamerElement *elem = Stack()->fElem;
3263  if (elem && (elem->GetArrayDim() > 1) && (elem->GetArrayLength() == arrsize)) {
3264  TArrayI indexes(elem->GetArrayDim() - 1);
3265  indexes.Reset(0);
3266  Int_t cnt = 0, shift = 0, len = elem->GetMaxIndex(indexes.GetSize());
3267  while (cnt >= 0) {
3268  if (indexes[cnt] >= elem->GetMaxIndex(cnt)) {
3269  fValue.Append("]");
3270  indexes[cnt--] = 0;
3271  if (cnt >= 0)
3272  indexes[cnt]++;
3273  continue;
3274  }
3275  fValue.Append(indexes[cnt] == 0 ? "[" : fArraySepar.Data());
3276  if (++cnt == indexes.GetSize()) {
3277  (*this.*method)((arr + shift), len, typname);
3278  indexes[--cnt]++;
3279  shift += len;
3280  }
3281  }
3282  } else {
3283  (*this.*method)(arr, arrsize, typname);
3284  }
3285 }
3286 
3287 ////////////////////////////////////////////////////////////////////////////////
3288 /// Write array of Bool_t to buffer
3289 
3291 {
3292  JsonWriteFastArray(b, n, "Bool", &TBufferJSON::JsonWriteArrayCompress<Bool_t>);
3293 }
3294 
3295 ////////////////////////////////////////////////////////////////////////////////
3296 /// Write array of Char_t to buffer
3297 ///
3298 /// Normally written as JSON string, but if string includes \0 in the middle
3299 /// or some special characters, uses regular array. From array size 1000 it
3300 /// will be automatically converted into base64 coding
3301 
3303 {
3304  Bool_t need_blob = false;
3305  Bool_t has_zero = false;
3306  for (int i=0;i<n;++i) {
3307  if (!c[i]) {
3308  has_zero = true; // might be terminal '\0'
3309  } else if (has_zero || !isprint(c[i])) {
3310  need_blob = true;
3311  break;
3312  }
3313  }
3314 
3315  if (need_blob && (n >= 1000) && (!Stack()->fElem || (Stack()->fElem->GetArrayDim() < 2)))
3316  Stack()->fBase64 = true;
3317 
3318  JsonWriteFastArray(c, n, "Int8", need_blob ? &TBufferJSON::JsonWriteArrayCompress<Char_t> : &TBufferJSON::JsonWriteConstChar);
3319 }
3320 
3321 ////////////////////////////////////////////////////////////////////////////////
3322 /// Write array of Char_t to buffer
3323 
3325 {
3327 }
3328 
3329 ////////////////////////////////////////////////////////////////////////////////
3330 /// Write array of UChar_t to buffer
3331 
3333 {
3334  JsonWriteFastArray(c, n, "Uint8", &TBufferJSON::JsonWriteArrayCompress<UChar_t>);
3335 }
3336 
3337 ////////////////////////////////////////////////////////////////////////////////
3338 /// Write array of Short_t to buffer
3339 
3341 {
3342  JsonWriteFastArray(h, n, "Int16", &TBufferJSON::JsonWriteArrayCompress<Short_t>);
3343 }
3344 
3345 ////////////////////////////////////////////////////////////////////////////////
3346 /// Write array of UShort_t to buffer
3347 
3349 {
3350  JsonWriteFastArray(h, n, "Uint16", &TBufferJSON::JsonWriteArrayCompress<UShort_t>);
3351 }
3352 
3353 ////////////////////////////////////////////////////////////////////////////////
3354 /// Write array of Int_t to buffer
3355 
3357 {
3358  JsonWriteFastArray(i, n, "Int32", &TBufferJSON::JsonWriteArrayCompress<Int_t>);
3359 }
3360 
3361 ////////////////////////////////////////////////////////////////////////////////
3362 /// Write array of UInt_t to buffer
3363 
3365 {
3366  JsonWriteFastArray(i, n, "Uint32", &TBufferJSON::JsonWriteArrayCompress<UInt_t>);
3367 }
3368 
3369 ////////////////////////////////////////////////////////////////////////////////
3370 /// Write array of Long_t to buffer
3371 
3373 {
3374  JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long_t>);
3375 }
3376 
3377 ////////////////////////////////////////////////////////////////////////////////
3378 /// Write array of ULong_t to buffer
3379 
3381 {
3382  JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong_t>);
3383 }
3384 
3385 ////////////////////////////////////////////////////////////////////////////////
3386 /// Write array of Long64_t to buffer
3387 
3389 {
3390  JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long64_t>);
3391 }
3392 
3393 ////////////////////////////////////////////////////////////////////////////////
3394 /// Write array of ULong64_t to buffer
3395 
3397 {
3398  JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong64_t>);
3399 }
3400 
3401 ////////////////////////////////////////////////////////////////////////////////
3402 /// Write array of Float_t to buffer
3403 
3405 {
3406  JsonWriteFastArray(f, n, "Float32", &TBufferJSON::JsonWriteArrayCompress<Float_t>);
3407 }
3408 
3409 ////////////////////////////////////////////////////////////////////////////////
3410 /// Write array of Double_t to buffer
3411 
3413 {
3414  JsonWriteFastArray(d, n, "Float64", &TBufferJSON::JsonWriteArrayCompress<Double_t>);
3415 }
3416 
3417 ////////////////////////////////////////////////////////////////////////////////
3418 /// Recall TBuffer function to avoid gcc warning message
3419 
3420 void TBufferJSON::WriteFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer * /* streamer */)
3421 {
3422  if (gDebug > 2)
3423  Info("WriteFastArray", "void *start cl:%s n:%d", cl ? cl->GetName() : "---", n);
3424 
3425  // if (streamer) {
3426  // JsonDisablePostprocessing();
3427  // (*streamer)(*this, start, 0);
3428  // return;
3429  // }
3430 
3431  if (n < 0) {
3432  // special handling of empty StreamLoop
3433  AppendOutput("null");
3435  } else {
3436 
3437  char *obj = (char *)start;
3438  if (!n)
3439  n = 1;
3440  int size = cl->Size();
3441 
3442  TArrayIndexProducer indexes(Stack()->fElem, n, fArraySepar.Data());
3443 
3444  if (indexes.IsArray()) {
3446  AppendOutput(indexes.GetBegin());
3447  }
3448 
3449  for (Int_t j = 0; j < n; j++, obj += size) {
3450 
3451  if (j > 0)
3452  AppendOutput(indexes.NextSeparator());
3453 
3454  JsonWriteObject(obj, cl, kFALSE);
3455 
3456  if (indexes.IsArray() && (fValue.Length() > 0)) {
3458  fValue.Clear();
3459  }
3460  }
3461 
3462  if (indexes.IsArray())
3463  AppendOutput(indexes.GetEnd());
3464  }
3465 
3466  if (Stack()->fIndx)
3467  AppendOutput(Stack()->fIndx->NextSeparator());
3468 }
3469 
3470 ////////////////////////////////////////////////////////////////////////////////
3471 /// Recall TBuffer function to avoid gcc warning message
3472 
3473 Int_t TBufferJSON::WriteFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc,
3474  TMemberStreamer * /* streamer */)
3475 {
3476  if (gDebug > 2)
3477  Info("WriteFastArray", "void **startp cl:%s n:%d", cl->GetName(), n);
3478 
3479  // if (streamer) {
3480  // JsonDisablePostprocessing();
3481  // (*streamer)(*this, (void *)start, 0);
3482  // return 0;
3483  // }
3484 
3485  if (n <= 0)
3486  return 0;
3487 
3488  Int_t res = 0;
3489 
3490  TArrayIndexProducer indexes(Stack()->fElem, n, fArraySepar.Data());
3491 
3492  if (indexes.IsArray()) {
3494  AppendOutput(indexes.GetBegin());
3495  }
3496 
3497  for (Int_t j = 0; j < n; j++) {
3498 
3499  if (j > 0)
3500  AppendOutput(indexes.NextSeparator());
3501 
3502  if (!isPreAlloc) {
3503  res |= WriteObjectAny(start[j], cl);
3504  } else {
3505  if (!start[j])
3506  start[j] = (const_cast<TClass *>(cl))->New();
3507  // ((TClass*)cl)->Streamer(start[j],*this);
3508  JsonWriteObject(start[j], cl, kFALSE);
3509  }
3510 
3511  if (indexes.IsArray() && (fValue.Length() > 0)) {
3513  fValue.Clear();
3514  }
3515  }
3516 
3517  if (indexes.IsArray())
3518  AppendOutput(indexes.GetEnd());
3519 
3520  if (Stack()->fIndx)
3521  AppendOutput(Stack()->fIndx->NextSeparator());
3522 
3523  return res;
3524 }
3525 
3526 ////////////////////////////////////////////////////////////////////////////////
3527 /// stream object to/from buffer
3528 
3529 void TBufferJSON::StreamObject(void *obj, const TClass *cl, const TClass * /* onfileClass */)
3530 {
3531  if (gDebug > 3)
3532  Info("StreamObject", "Class: %s", (cl ? cl->GetName() : "none"));
3533 
3534  if (IsWriting())
3535  JsonWriteObject(obj, cl);
3536  else
3537  JsonReadObject(obj, cl);
3538 }
3539 
3540 ////////////////////////////////////////////////////////////////////////////////
3541 /// Template function to read basic value from JSON
3542 
3543 template <typename T>
3545 {
3546  value = Stack()->GetStlNode()->get<T>();
3547 }
3548 
3549 ////////////////////////////////////////////////////////////////////////////////
3550 /// Reads Bool_t value from buffer
3551 
3553 {
3554  JsonReadBasic(val);
3555 }
3556 
3557 ////////////////////////////////////////////////////////////////////////////////
3558 /// Reads Char_t value from buffer
3559 
3561 {
3562  if (!Stack()->fValues.empty())
3563  val = (Char_t)Stack()->PopIntValue();
3564  else
3565  val = Stack()->GetStlNode()->get<Char_t>();
3566 }
3567 
3568 ////////////////////////////////////////////////////////////////////////////////
3569 /// Reads UChar_t value from buffer
3570 
3572 {
3573  JsonReadBasic(val);
3574 }
3575 
3576 ////////////////////////////////////////////////////////////////////////////////
3577 /// Reads Short_t value from buffer
3578 
3580 {
3581  JsonReadBasic(val);
3582 }
3583 
3584 ////////////////////////////////////////////////////////////////////////////////
3585 /// Reads UShort_t value from buffer
3586 
3588 {
3589  JsonReadBasic(val);
3590 }
3591 
3592 ////////////////////////////////////////////////////////////////////////////////
3593 /// Reads Int_t value from buffer
3594 
3596 {
3597  if (!Stack()->fValues.empty())
3598  val = Stack()->PopIntValue();
3599  else
3600  JsonReadBasic(val);
3601 }
3602 
3603 ////////////////////////////////////////////////////////////////////////////////
3604 /// Reads UInt_t value from buffer
3605 
3607 {
3608  JsonReadBasic(val);
3609 }
3610 
3611 ////////////////////////////////////////////////////////////////////////////////
3612 /// Reads Long_t value from buffer
3613 
3615 {
3616  JsonReadBasic(val);
3617 }
3618 
3619 ////////////////////////////////////////////////////////////////////////////////
3620 /// Reads ULong_t value from buffer
3621 
3623 {
3624  JsonReadBasic(val);
3625 }
3626 
3627 ////////////////////////////////////////////////////////////////////////////////
3628 /// Reads Long64_t value from buffer
3629 
3631 {
3632  JsonReadBasic(val);
3633 }
3634 
3635 ////////////////////////////////////////////////////////////////////////////////
3636 /// Reads ULong64_t value from buffer
3637 
3639 {
3640  JsonReadBasic(val);
3641 }
3642 
3643 ////////////////////////////////////////////////////////////////////////////////
3644 /// Reads Float_t value from buffer
3645 
3647 {
3648  nlohmann::json *json = Stack()->GetStlNode();
3649  if (json->is_null())
3650  val = std::numeric_limits<Float_t>::quiet_NaN();
3651  else
3652  val = json->get<Float_t>();
3653 }
3654 
3655 ////////////////////////////////////////////////////////////////////////////////
3656 /// Reads Double_t value from buffer
3657 
3659 {
3660  nlohmann::json *json = Stack()->GetStlNode();
3661  if (json->is_null())
3662  val = std::numeric_limits<Double_t>::quiet_NaN();
3663  else
3664  val = json->get<Double_t>();
3665 }
3666 
3667 ////////////////////////////////////////////////////////////////////////////////
3668 /// Reads array of characters from buffer
3669 
3671 {
3672  Error("ReadCharP", "Not implemented");
3673 }
3674 
3675 ////////////////////////////////////////////////////////////////////////////////
3676 /// Reads a TString
3677 
3679 {
3680  std::string str;
3681  JsonReadBasic(str);
3682  val = str.c_str();
3683 }
3684 
3685 ////////////////////////////////////////////////////////////////////////////////
3686 /// Reads a std::string
3687 
3688 void TBufferJSON::ReadStdString(std::string *val)
3689 {
3690  JsonReadBasic(*val);
3691 }
3692 
3693 ////////////////////////////////////////////////////////////////////////////////
3694 /// Reads a char* string
3695 
3697 {
3698  std::string str;
3699  JsonReadBasic(str);
3700 
3701  if (s) {
3702  delete[] s;
3703  s = nullptr;
3704  }
3705 
3706  std::size_t nch = str.length();
3707  if (nch > 0) {
3708  s = new char[nch + 1];
3709  memcpy(s, str.c_str(), nch);
3710  s[nch] = 0;
3711  }
3712 }
3713 
3714 ////////////////////////////////////////////////////////////////////////////////
3715 /// Writes Bool_t value to buffer
3716 
3718 {
3719  JsonPushValue();
3720  JsonWriteBasic(b);
3721 }
3722 
3723 ////////////////////////////////////////////////////////////////////////////////
3724 /// Writes Char_t value to buffer
3725 
3727 {
3728  JsonPushValue();
3729  JsonWriteBasic(c);
3730 }
3731 
3732 ////////////////////////////////////////////////////////////////////////////////
3733 /// Writes UChar_t value to buffer
3734 
3736 {
3737  JsonPushValue();
3738  JsonWriteBasic(c);
3739 }
3740 
3741 ////////////////////////////////////////////////////////////////////////////////
3742 /// Writes Short_t value to buffer
3743 
3745 {
3746  JsonPushValue();
3747  JsonWriteBasic(h);
3748 }
3749 
3750 ////////////////////////////////////////////////////////////////////////////////
3751 /// Writes UShort_t value to buffer
3752 
3754 {
3755  JsonPushValue();
3756  JsonWriteBasic(h);
3757 }
3758 
3759 ////////////////////////////////////////////////////////////////////////////////
3760 /// Writes Int_t value to buffer
3761 
3763 {
3764  JsonPushValue();
3765  JsonWriteBasic(i);
3766 }
3767 
3768 ////////////////////////////////////////////////////////////////////////////////
3769 /// Writes UInt_t value to buffer
3770 
3772 {
3773  JsonPushValue();
3774  JsonWriteBasic(i);
3775 }
3776 
3777 ////////////////////////////////////////////////////////////////////////////////
3778 /// Writes Long_t value to buffer
3779 
3781 {
3782  JsonPushValue();
3783  JsonWriteBasic(l);
3784 }
3785 
3786 ////////////////////////////////////////////////////////////////////////////////
3787 /// Writes ULong_t value to buffer
3788 
3790 {
3791  JsonPushValue();
3792  JsonWriteBasic(l);
3793 }
3794 
3795 ////////////////////////////////////////////////////////////////////////////////
3796 /// Writes Long64_t value to buffer
3797 
3799 {
3800  JsonPushValue();
3801  JsonWriteBasic(l);
3802 }
3803 
3804 ////////////////////////////////////////////////////////////////////////////////
3805 /// Writes ULong64_t value to buffer
3806 
3808 {
3809  JsonPushValue();
3810  JsonWriteBasic(l);
3811 }
3812 
3813 ////////////////////////////////////////////////////////////////////////////////
3814 /// Writes Float_t value to buffer
3815 
3817 {
3818  JsonPushValue();
3819  JsonWriteBasic(f);
3820 }
3821 
3822 ////////////////////////////////////////////////////////////////////////////////
3823 /// Writes Double_t value to buffer
3824 
3826 {
3827  JsonPushValue();
3828  JsonWriteBasic(d);
3829 }
3830 
3831 ////////////////////////////////////////////////////////////////////////////////
3832 /// Writes array of characters to buffer
3833 
3835 {
3836  JsonPushValue();
3837 
3839 }
3840 
3841 ////////////////////////////////////////////////////////////////////////////////
3842 /// Writes a TString
3843 
3845 {
3846  JsonPushValue();
3847 
3848  JsonWriteConstChar(s.Data(), s.Length());
3849 }
3850 
3851 ////////////////////////////////////////////////////////////////////////////////
3852 /// Writes a std::string
3853 
3854 void TBufferJSON::WriteStdString(const std::string *s)
3855 {
3856  JsonPushValue();
3857 
3858  if (s)
3859  JsonWriteConstChar(s->c_str(), s->length());
3860  else
3861  JsonWriteConstChar("", 0);
3862 }
3863 
3864 ////////////////////////////////////////////////////////////////////////////////
3865 /// Writes a char*
3866 
3868 {
3869  JsonPushValue();
3870 
3872 }
3873 
3874 ////////////////////////////////////////////////////////////////////////////////
3875 /// converts Char_t to string and add to json value buffer
3876 
3878 {
3879  char buf[50];
3880  snprintf(buf, sizeof(buf), "%d", value);
3881  fValue.Append(buf);
3882 }
3883 
3884 ////////////////////////////////////////////////////////////////////////////////
3885 /// converts Short_t to string and add to json value buffer
3886 
3888 {
3889  char buf[50];
3890  snprintf(buf, sizeof(buf), "%hd", value);
3891  fValue.Append(buf);
3892 }
3893 
3894 ////////////////////////////////////////////////////////////////////////////////
3895 /// converts Int_t to string and add to json value buffer
3896 
3898 {
3899  char buf[50];
3900  snprintf(buf, sizeof(buf), "%d", value);
3901  fValue.Append(buf);
3902 }
3903 
3904 ////////////////////////////////////////////////////////////////////////////////
3905 /// converts Long_t to string and add to json value buffer
3906 
3908 {
3909  char buf[50];
3910  snprintf(buf, sizeof(buf), "%ld", value);
3911  fValue.Append(buf);
3912 }
3913 
3914 ////////////////////////////////////////////////////////////////////////////////
3915 /// converts Long64_t to string and add to json value buffer
3916 
3918 {
3919  fValue.Append(std::to_string(value).c_str());
3920 }
3921 
3922 ////////////////////////////////////////////////////////////////////////////////
3923 /// converts Float_t to string and add to json value buffer
3924 
3926 {
3927  if (std::isinf(value)) {
3928  fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3929  } else if (std::isnan(value)) {
3930  fValue.Append("null");
3931  } else {
3932  char buf[200];
3933  ConvertFloat(value, buf, sizeof(buf));
3934  fValue.Append(buf);
3935  }
3936 }
3937 
3938 ////////////////////////////////////////////////////////////////////////////////
3939 /// converts Double_t to string and add to json value buffer
3940 
3942 {
3943  if (std::isinf(value)) {
3944  fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3945  } else if (std::isnan(value)) {
3946  fValue.Append("null");
3947  } else {
3948  char buf[200];
3949  ConvertDouble(value, buf, sizeof(buf));
3950  fValue.Append(buf);
3951  }
3952 }
3953 
3954 ////////////////////////////////////////////////////////////////////////////////
3955 /// converts Bool_t to string and add to json value buffer
3956 
3958 {
3959  fValue.Append(value ? "true" : "false");
3960 }
3961 
3962 ////////////////////////////////////////////////////////////////////////////////
3963 /// converts UChar_t to string and add to json value buffer
3964 
3966 {
3967  char buf[50];
3968  snprintf(buf, sizeof(buf), "%u", value);
3969  fValue.Append(buf);
3970 }
3971 
3972 ////////////////////////////////////////////////////////////////////////////////
3973 /// converts UShort_t to string and add to json value buffer
3974 
3976 {
3977  char buf[50];
3978  snprintf(buf, sizeof(buf), "%hu", value);
3979  fValue.Append(buf);
3980 }
3981 
3982 ////////////////////////////////////////////////////////////////////////////////
3983 /// converts UInt_t to string and add to json value buffer
3984 
3986 {
3987  char buf[50];
3988  snprintf(buf, sizeof(buf), "%u", value);
3989  fValue.Append(buf);
3990 }
3991 
3992 ////////////////////////////////////////////////////////////////////////////////
3993 /// converts ULong_t to string and add to json value buffer
3994 
3996 {
3997  char buf[50];
3998  snprintf(buf, sizeof(buf), "%lu", value);
3999  fValue.Append(buf);
4000 }
4001 
4002 ////////////////////////////////////////////////////////////////////////////////
4003 /// converts ULong64_t to string and add to json value buffer
4004 
4006 {
4007  fValue.Append(std::to_string(value).c_str());
4008 }
4009 
4010 ////////////////////////////////////////////////////////////////////////////////
4011 /// writes string value, processing all kind of special characters
4012 
4013 void TBufferJSON::JsonWriteConstChar(const char *value, Int_t len, const char * /* typname */)
4014 {
4015  if (!value) {
4016 
4017  fValue.Append("\"\"");
4018 
4019  } else {
4020 
4021  fValue.Append("\"");
4022 
4023  if (len < 0)
4024  len = strlen(value);
4025 
4026  for (Int_t n = 0; n < len; n++) {
4027  char c = value[n];
4028  if (c == 0)
4029  break;
4030  switch (c) {
4031  case '\n': fValue.Append("\\n"); break;
4032  case '\t': fValue.Append("\\t"); break;
4033  case '\"': fValue.Append("\\\""); break;
4034  case '\\': fValue.Append("\\\\"); break;
4035  case '\b': fValue.Append("\\b"); break;
4036  case '\f': fValue.Append("\\f"); break;
4037  case '\r': fValue.Append("\\r"); break;
4038  case '/': fValue.Append("\\/"); break;
4039  default:
4040  if ((c > 31) && (c < 127))
4041  fValue.Append(c);
4042  else
4043  fValue.Append(TString::Format("\\u%04x", (unsigned)c));
4044  }
4045  }
4046 
4047  fValue.Append("\"");
4048  }
4049 }
4050 
4051 ////////////////////////////////////////////////////////////////////////////////
4052 /// Read data of base class.
4053 
4055 {
4056  if (elem->GetClassPointer() == TObject::Class()) {
4057  JsonReadTObjectMembers((TObject *)start);
4058  } else {
4059  TBufferText::ReadBaseClass(start, elem);
4060  }
4061 }
kULong64_t
@ kULong64_t
Definition: TDataType.h:32
TStreamerElement::GetMaxIndex
Int_t GetMaxIndex(Int_t i) const
Definition: TStreamerElement.h:113
c
#define c(i)
Definition: RSha256.hxx:101
l
auto * l
Definition: textangle.C:4
TBufferJSON::WriteFastArrayString
void WriteFastArrayString(const Char_t *c, Int_t n) final
Write array of Char_t to buffer.
Definition: TBufferJSON.cxx:3324
TClassEdit::kUnorderedMultiSet
@ kUnorderedMultiSet
Definition: TClassEdit.h:103
TDataMember::GetTypeName
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
Definition: TDataMember.cxx:604
Compression.h
kDouble_t
@ kDouble_t
Definition: TDataType.h:31
TBufferJSON::fArrayCompact
Int_t fArrayCompact
! 0 - no array compression, 1 - exclude leading/trailing zeros, 2 - check value repetition
Definition: TBufferJSON.h:325
TBufferJSON::WriteTString
void WriteTString(const TString &s) final
Writes a TString.
Definition: TBufferJSON.cxx:3844
n
const Int_t n
Definition: legend1.C:16
kUChar_t
@ kUChar_t
Definition: TDataType.h:29
kInt_t
@ kInt_t
Definition: TDataType.h:30
TBufferJSON::WriteChar
void WriteChar(Char_t c) final
Writes Char_t value to buffer.
Definition: TBufferJSON.cxx:3726
TBufferJSON::fTypeNameTag
TString fTypeNameTag
! JSON member used for storing class name, when empty - no class name will be stored
Definition: TBufferJSON.h:328
first
Definition: first.py:1
TBufferJSON::ReadClass
TClass * ReadClass(const TClass *cl=nullptr, UInt_t *objTag=nullptr) final
suppressed function of TBuffer
Definition: TBufferJSON.cxx:2449
TBufferJSON::TBufferJSON
TBufferJSON(TBuffer::EMode mode=TBuffer::kWrite)
Creates buffer object to serialize data into json.
Definition: TBufferJSON.cxx:478
TBufferJSON::WriteLong64
void WriteLong64(Long64_t l) final
Writes Long64_t value to buffer.
Definition: TBufferJSON.cxx:3798
ROOT::kSTLvector
@ kSTLvector
Definition: ESTLType.h:30
TClass::GetCollectionProxy
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2854
kTRUE
const Bool_t kTRUE
Definition: RtypesCore.h:91
TBufferJSON::ReadBool
void ReadBool(Bool_t &b) final
Reads Bool_t value from buffer.
Definition: TBufferJSON.cxx:3552
TBufferJSON::WorkWithClass
void WorkWithClass(TStreamerInfo *info, const TClass *cl=nullptr)
Prepares buffer to stream data of specified class.
Definition: TBufferJSON.cxx:2011
TBufferJSON::ClassBegin
void ClassBegin(const TClass *, Version_t=-1) final
Should be called in the beginning of custom class streamer.
Definition: TBufferJSON.cxx:2180
Version_t
short Version_t
Definition: RtypesCore.h:65
TBufferJSON::ReadCharStar
void ReadCharStar(char *&s) final
Reads a char* string.
Definition: TBufferJSON.cxx:3696
TBufferJSON::fSkipClasses
std::vector< const TClass * > fSkipClasses
! list of classes, which class info is not stored
Definition: TBufferJSON.h:330
snprintf
#define snprintf
Definition: civetweb.c:1540
TClass::Streamer
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=0) const
Definition: TClass.h:554
TDataMember::GetUnitSize
Int_t GetUnitSize() const
Get the sizeof the underlying type of the data member (i.e.
Definition: TDataMember.cxx:695
f
#define f(i)
Definition: RSha256.hxx:104
kNoType_t
@ kNoType_t
Definition: TDataType.h:33
TStreamerElement::GetTypeName
const char * GetTypeName() const
Definition: TStreamerElement.h:123
TVirtualStreamerInfo::GetClass
virtual TClass * GetClass() const =0
TStreamerInfo.h
kCharStar
@ kCharStar
Definition: TDataType.h:34
kLong_t
@ kLong_t
Definition: TDataType.h:30
kChar_t
@ kChar_t
Definition: TDataType.h:29
TString::Atoi
Int_t Atoi() const
Return integer value of string.
Definition: TString.cxx:1921
TBuffer::kRead
@ kRead
Definition: TBuffer.h:73
TClass::Size
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5518
nlohmann::json
basic_json<> json
Definition: REveElement.hxx:58
TClass::GetRealData
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3382
TBufferJSON::ConvertFromJSON
static TObject * ConvertFromJSON(const char *str)
Read TObject-based class from JSON, produced by ConvertToJSON() method.
Definition: TBufferJSON.cxx:913
kULong_t
@ kULong_t
Definition: TDataType.h:30
TClass::GetActualClass
TClass * GetActualClass(const void *object) const
Return a pointer the the real class of the object.
Definition: TClass.cxx:2565
UShort_t
unsigned short UShort_t
Definition: RtypesCore.h:40
TBufferJSON::ReadULong64
void ReadULong64(ULong64_t &l) final
Reads ULong64_t value from buffer.
Definition: TBufferJSON.cxx:3638
TString::Data
const char * Data() const
Definition: TString.h:369
TEmulatedCollectionProxy.h
TStreamerObjectAny
Definition: TStreamerElement.h:312
TClassEdit::kDeque
@ kDeque
Definition: TClassEdit.h:97
ClassImp
#define ClassImp(name)
Definition: Rtypes.h:364
Form
char * Form(const char *fmt,...)
TBufferJSON::JsonSpecialClass
Int_t JsonSpecialClass(const TClass *cl) const
return non-zero value when class has special handling in JSON it is TCollection (-130),...
Definition: TBufferJSON.cxx:1281
TClassEdit::kVector
@ kVector
Definition: TClassEdit.h:94
ROOT::kNotSTL
@ kNotSTL
Definition: ESTLType.h:29
TStreamerElement.h
TString::Replace
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition: TString.h:682
TBufferJSON::ReadChar
void ReadChar(Char_t &c) final
Reads Char_t value from buffer.
Definition: TBufferJSON.cxx:3560
TDataType::GetType
Int_t GetType() const
Definition: TDataType.h:68
TBufferIO::GetObjectTag
Long64_t GetObjectTag(const void *obj)
Returns tag for specified object from objects map (if exists) Returns 0 if object not included into o...
Definition: TBufferIO.cxx:277
TBufferJSON::ReadFloat
void ReadFloat(Float_t &f) final
Reads Float_t value from buffer.
Definition: TBufferJSON.cxx:3646
TBufferJSON::SetStreamerElementNumber
void SetStreamerElementNumber(TStreamerElement *elem, Int_t comp_type) final
Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions and add/verify next elemen...
Definition: TBufferJSON.cxx:2088
TObject::Info
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:864
Long64_t
long long Long64_t
Definition: RtypesCore.h:73
TObject::Error
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:890
TBufferJSON::ReadStdString
virtual void ReadStdString(std::string *s)=0
ROOT::kSTLend
@ kSTLend
Definition: ESTLType.h:46
TStreamerInfo::kOffsetL
@ kOffsetL
Definition: TStreamerInfo.h:167
TBufferIO::WriteObjectAny
Int_t WriteObjectAny(const void *obj, const TClass *ptrClass, Bool_t cacheReuse=kTRUE) override
Write object to I/O buffer.
Definition: TBufferIO.cxx:492
TBufferJSON::ExportToFile
static Int_t ExportToFile(const char *filename, const TObject *obj, const char *option=nullptr)
Convert object into JSON and store in text file Returns size of the produce file Used in TObject::Sav...
Definition: TBufferJSON.cxx:753
TClassEdit::kMultiMap
@ kMultiMap
Definition: TClassEdit.h:99
TClassEdit::kUnorderedSet
@ kUnorderedSet
Definition: TClassEdit.h:102
TClassEdit::IsStdClass
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
Definition: TClassEdit.cxx:1389
TDataMember.h
Float_t
float Float_t
Definition: RtypesCore.h:57
TObjArray::IndexOf
Int_t IndexOf(const TObject *obj) const
Definition: TObjArray.cxx:605
TBufferJSON::fCompact
Int_t fCompact
! 0 - no any compression, 1 - no spaces in the begin, 2 - no new lines, 3 - no spaces at all
Definition: TBufferJSON.h:322
TMap::GetValue
TObject * GetValue(const char *keyname) const
Returns a pointer to the value associated with keyname as name of the key.
Definition: TMap.cxx:236
TGeant4Unit::s
static constexpr double s
Definition: TGeant4SystemOfUnits.h:162
Int_t
int Int_t
Definition: RtypesCore.h:45
TDataMember
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
TBase64::Decode
static TString Decode(const char *data)
Decode a base64 string date into a generic TString.
Definition: TBase64.cxx:131
TBufferJSON::JsonWriteCollection
void JsonWriteCollection(TCollection *obj, const TClass *objClass)
store content of ROOT collection
Definition: TBufferJSON.cxx:1596
TStreamerInfo::kAny
@ kAny
Definition: TStreamerInfo.h:173
TStreamerString
Definition: TStreamerElement.h:373
kUInt_t
@ kUInt_t
Definition: TDataType.h:30
TClass::GetClassVersion
Version_t GetClassVersion() const
Definition: TClass.h:377
TStreamerInfo::kSTLstring
@ kSTLstring
Definition: TStreamerInfo.h:178
TString::Length
Ssiz_t Length() const
Definition: TString.h:410
TBufferJSON::JsonWriteArrayCompress
R__ALWAYS_INLINE void JsonWriteArrayCompress(const T *vname, Int_t arrsize, const char *typname)
Definition: TBufferJSON.cxx:3030
TRef.h
TClass.h
TBufferIO::MapObject
void MapObject(const TObject *obj, UInt_t offset=1) override
Add object to the fMap container.
Definition: TBufferIO.cxx:163
TList.h
TStreamerInfo::kTObject
@ kTObject
Definition: TStreamerInfo.h:174
TBase64::Encode
static TString Encode(const char *data)
Transform data into a null terminated base64 string.
Definition: TBase64.cxx:107
TRealData::GetThisOffset
Long_t GetThisOffset() const
Definition: TRealData.h:55
kchar
@ kchar
Definition: TDataType.h:31
TClassEdit::kSet
@ kSet
Definition: TClassEdit.h:100
TString::Format
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition: TString.cxx:2311
TMap::Add
void Add(TObject *obj)
This function may not be used (but we need to provide it since it is a pure virtual in TCollection).
Definition: TMap.cxx:54
TStreamerBase::GetClassPointer
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
Definition: TStreamerElement.cxx:672
TBufferJSON::fArraySepar
TString fArraySepar
! depending from compression level, ", " or ","
Definition: TBufferJSON.h:326
TBufferIO::InitMap
void InitMap() override
Create the fMap container and initialize them with the null object.
Definition: TBufferIO.cxx:129
TString
Basic string class.
Definition: TString.h:136
ROOT::kSTLlist
@ kSTLlist
Definition: ESTLType.h:31
TStreamerObjectPointer
Definition: TStreamerElement.h:331
TStreamer.h
Bool_t
bool Bool_t
Definition: RtypesCore.h:63
TIter::GetOption
Option_t * GetOption() const
Definition: TCollection.h:251
TBufferJSON::JsonWriteBasic
void JsonWriteBasic(Char_t value)
converts Char_t to string and add to json value buffer
Definition: TBufferJSON.cxx:3877
TBufferJSON::fMapAsObject
Bool_t fMapAsObject
! when true, std::map will be converted into JSON object
Definition: TBufferJSON.h:323
TObject::InheritsFrom
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:445
v
@ v
Definition: rootcling_impl.cxx:3635
TString::Clear
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1176
b
#define b(i)
Definition: RSha256.hxx:100
TBufferJSON::ReadFastArray
void ReadFastArray(Bool_t *b, Int_t n) final
read array of Bool_t from buffer
Definition: TBufferJSON.cxx:2829
TBufferJSON::ConvertFromJSONChecked
static void * ConvertFromJSONChecked(const char *str, const TClass *expectedClass)
Read objects from JSON, one can reuse existing object.
Definition: TBufferJSON.cxx:979
TBufferJSON::SkipObjectAny
void SkipObjectAny() final
Skip any kind of object from buffer.
Definition: TBufferJSON.cxx:2504
TVirtualStreamerInfo
Abstract Interface class describing Streamer information for one class.
Definition: TVirtualStreamerInfo.h:37
bool
TClonesArray.h
kFloat16_t
@ kFloat16_t
Definition: TDataType.h:33
TBufferJSON::fStack
std::deque< std::unique_ptr< TJSONStackObj > > fStack
! hierarchy of currently streamed element
Definition: TBufferJSON.h:321
TBufferJSON::WriteUChar
void WriteUChar(UChar_t c) final
Writes UChar_t value to buffer.
Definition: TBufferJSON.cxx:3735
TBufferJSON::JsonReadFastArray
R__ALWAYS_INLINE void JsonReadFastArray(T *arr, Int_t arrsize, bool asstring=false)
Template method to read array from the JSON.
Definition: TBufferJSON.cxx:2748
TClassEdit::kList
@ kList
Definition: TClassEdit.h:95
TDataMember::IsBasic
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
Definition: TDataMember.cxx:712
TBufferJSON::ReadFastArrayString
void ReadFastArrayString(Char_t *c, Int_t n) final
read array of Char_t from buffer
Definition: TBufferJSON.cxx:2845
TBufferJSON::ReadULong
void ReadULong(ULong_t &l) final
Reads ULong_t value from buffer.
Definition: TBufferJSON.cxx:3622
TArrayI::Reset
void Reset()
Definition: TArrayI.h:47
TBufferText
Base class for text-based streamers like TBufferJSON or TBufferXML Special actions list will use meth...
Definition: TBufferText.h:20
TROOT.h
TStreamerInfo::kAnyp
@ kAnyp
Definition: TStreamerInfo.h:174
TBufferJSON::WriteArray
void WriteArray(const Bool_t *b, Int_t n) final
Write array of Bool_t to buffer.
Definition: TBufferJSON.cxx:3133
json_TString
@ json_TString
Definition: TBufferJSON.cxx:136
TClassEdit::kMap
@ kMap
Definition: TClassEdit.h:98
TStreamerElement::IsBase
virtual Bool_t IsBase() const
Return kTRUE if the element represent a base class.
Definition: TStreamerElement.cxx:442
TBufferJSON::fOutBuffer
TString fOutBuffer
! main output buffer for json code
Definition: TBufferJSON.h:317
TBufferJSON::ClassMember
void ClassMember(const char *name, const char *typeName=nullptr, Int_t arrsize1=-1, Int_t arrsize2=-1) final
Method indicates name and typename of class member, which should be now streamed in custom streamer F...
Definition: TBufferJSON.cxx:2231
TBufferJSON::fNumericLocale
TString fNumericLocale
! stored value of setlocale(LC_NUMERIC), which should be recovered at the end
Definition: TBufferJSON.h:327
TBufferJSON::WriteCharStar
void WriteCharStar(char *s) final
Writes a char*.
Definition: TBufferJSON.cxx:3867
TBufferJSON::kSkipTypeInfo
@ kSkipTypeInfo
Definition: TBufferJSON.h:48
TBufferJSON::fValue
TString fValue
! buffer for current value
Definition: TBufferJSON.h:319
TBufferJSON::ReadUShort
void ReadUShort(UShort_t &s) final
Reads UShort_t value from buffer.
Definition: TBufferJSON.cxx:3587
TString::Form
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2289
TDataType.h
kDouble32_t
@ kDouble32_t
Definition: TDataType.h:31
TRealData::GetDataMember
TDataMember * GetDataMember() const
Definition: TRealData.h:53
TBufferJSON::DecrementLevel
void DecrementLevel(TVirtualStreamerInfo *) final
Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions and decrease level in json...
Definition: TBufferJSON.cxx:2047
kCounter
@ kCounter
Definition: TDataType.h:34
TBufferJSON::WriteULong64
void WriteULong64(ULong64_t l) final
Writes ULong64_t value to buffer.
Definition: TBufferJSON.cxx:3807
TDataMember::GetArrayDim
Int_t GetArrayDim() const
Return number of array dimensions.
Definition: TDataMember.cxx:545
TBufferJSON::fJsonrCnt
unsigned fJsonrCnt
! counter for all objects, used for referencing
Definition: TBufferJSON.h:320
TClassEdit::kBitSet
@ kBitSet
Definition: TClassEdit.h:106
TClass::GetCollectionType
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition: TClass.cxx:2843
TString::Resize
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1095
malloc
#define malloc
Definition: civetweb.c:1536
TClassTable.h
TBufferJSON::JsonStartObjectWrite
TJSONStackObj * JsonStartObjectWrite(const TClass *obj_class, TStreamerInfo *info=nullptr)
Start object element with typeinfo.
Definition: TBufferJSON.cxx:1180
TClassEdit::kUnorderedMap
@ kUnorderedMap
Definition: TClassEdit.h:104
ROOT::kSTLforwardlist
@ kSTLforwardlist
Definition: ESTLType.h:41
TBase64.h
TBuffer::EMode
EMode
Definition: TBuffer.h:73
TDataType
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
TStreamerInfo::GetElements
TObjArray * GetElements() const
Definition: TStreamerInfo.h:210
TStreamerInfo
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:44
TBufferJSON::IsSkipClassInfo
Bool_t IsSkipClassInfo(const TClass *cl) const
Returns true if class info will be skipped from JSON.
Definition: TBufferJSON.cxx:616
TBufferJSON::WriteULong
void WriteULong(ULong_t l) final
Writes ULong_t value to buffer.
Definition: TBufferJSON.cxx:3789
TClass::New
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4876
h
#define h(i)
Definition: RSha256.hxx:106
TBufferJSON::WriteStdString
virtual void WriteStdString(const std::string *s)=0
decode
#define decode(ptr, otri)
Definition: triangle.c:912
TClass::GetListOfRealData
TList * GetListOfRealData() const
Definition: TClass.h:409
TBufferJSON::WriteObjectClass
void WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse) final
Write object to buffer. Only used from TBuffer.
Definition: TBufferJSON.cxx:2509
TBuffer::IsWriting
Bool_t IsWriting() const
Definition: TBuffer.h:87
TDataMember::GetMaxIndex
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
Definition: TDataMember.cxx:591
TBufferJSON::ReadUChar
void ReadUChar(UChar_t &c) final
Reads UChar_t value from buffer.
Definition: TBufferJSON.cxx:3571
TBufferJSON::SetTypenameTag
void SetTypenameTag(const char *tag="_typename")
Configures _typename tag in JSON structures By default "_typename" field in JSON structures used to s...
Definition: TBufferJSON.cxx:580
TStreamerElement::GetClassPointer
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
Definition: TStreamerElement.cxx:292
TBufferJSON::JsonReadTObjectMembers
void JsonReadTObjectMembers(TObject *obj, void *node=nullptr)
Read TObject data members from JSON.
Definition: TBufferJSON.cxx:1975
kFALSE
const Bool_t kFALSE
Definition: RtypesCore.h:92
TString::Append
TString & Append(const char *cs)
Definition: TString.h:564
TBufferJSON::RestoreObject
void * RestoreObject(const char *str, TClass **cl)
Read object from JSON In class pointer (if specified) read class is returned One must specify expecte...
Definition: TBufferJSON.cxx:948
kUShort_t
@ kUShort_t
Definition: TDataType.h:29
TBufferJSON::AppendOutput
void AppendOutput(const char *line0, const char *line1=nullptr)
Append two string to the output JSON, normally separate by line break.
Definition: TBufferJSON.cxx:1158
Long_t
long Long_t
Definition: RtypesCore.h:54
TBufferJSON::WriteFastArray
void WriteFastArray(const Bool_t *b, Int_t n) final
Write array of Bool_t to buffer.
Definition: TBufferJSON.cxx:3290
TDataMember::GetDataType
TDataType * GetDataType() const
Definition: TDataMember.h:74
TBufferJSON::ReadVersion
Version_t ReadVersion(UInt_t *start=nullptr, UInt_t *bcnt=nullptr, const TClass *cl=nullptr) final
read version value from buffer
Definition: TBufferJSON.cxx:2462
TClassEdit::kUnorderedMultiMap
@ kUnorderedMultiMap
Definition: TClassEdit.h:105
TBufferJSON::ReadTString
void ReadTString(TString &s) final
Reads a TString.
Definition: TBufferJSON.cxx:3678
TArrayI::Set
void Set(Int_t n)
Set size of this array to n ints.
Definition: TArrayI.cxx:105
json_stdstring
@ json_stdstring
Definition: TBufferJSON.cxx:136
TBufferJSON::WorkWithElement
void WorkWithElement(TStreamerElement *elem, Int_t)
This is call-back from streamer which indicates that class member will be streamed Name of element us...
Definition: TBufferJSON.cxx:2101
TBufferJSON::WriteLong
void WriteLong(Long_t l) final
Writes Long_t value to buffer.
Definition: TBufferJSON.cxx:3780
TClonesArray::GetClass
TClass * GetClass() const
Definition: TClonesArray.h:53
TBufferJSON::PushStack
TJSONStackObj * PushStack(Int_t inclevel=0, void *readnode=nullptr)
add new level to the structures stack
Definition: TBufferJSON.cxx:1129
TBufferJSON::ReadLong
void ReadLong(Long_t &l) final
Reads Long_t value from buffer.
Definition: TBufferJSON.cxx:3614
TBufferJSON::ReadArray
Int_t ReadArray(Bool_t *&b) final
Read array of Bool_t from buffer.
Definition: TBufferJSON.cxx:2529
TStreamerElement::GetType
Int_t GetType() const
Definition: TStreamerElement.h:119
TBufferJSON
Class for serializing object to and from JavaScript Object Notation (JSON) format.
Definition: TBufferJSON.h:30
TArrayI.h
gDebug
Int_t gDebug
Definition: TROOT.cxx:590
TBufferJSON::JsonWriteObject
void JsonWriteObject(const void *obj, const TClass *objClass, Bool_t check_map=kTRUE)
Write object to buffer If object was written before, only pointer will be stored If check_map==kFALSE...
Definition: TBufferJSON.cxx:1319
isnan
int isnan(double)
TStreamerInfo::GetClass
TClass * GetClass() const
Definition: TStreamerInfo.h:205
TClass::GetClass
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2925
TRealData.h
TBufferJSON::SetCompact
void SetCompact(int level)
Set level of space/newline/array compression Lower digit of compact parameter define formatting rules...
Definition: TBufferJSON.cxx:556
TBufferJSON::WriteInt
void WriteInt(Int_t i) final
Writes Int_t value to buffer.
Definition: TBufferJSON.cxx:3762
ULong_t
unsigned long ULong_t
Definition: RtypesCore.h:55
TBufferJSON::kSameSuppression
@ kSameSuppression
zero suppression plus compress many similar values together
Definition: TBufferJSON.h:45
json_TArray
@ json_TArray
Definition: TBufferJSON.cxx:136
Short_t
short Short_t
Definition: RtypesCore.h:39
TBufferJSON.h
TBufferJSON::ReadCharP
void ReadCharP(Char_t *c) final
Reads array of characters from buffer.
Definition: TBufferJSON.cxx:3670
TBufferJSON::kMapAsObject
@ kMapAsObject
store std::map, std::unodered_map as JSON object
Definition: TBufferJSON.h:41
TStreamerElement::GetArrayLength
Int_t GetArrayLength() const
Definition: TStreamerElement.h:107
TBufferJSON::StoreObject
TString StoreObject(const void *obj, const TClass *cl)
Store provided object as JSON structure Allows to configure different TBufferJSON properties before c...
Definition: TBufferJSON.cxx:702
TVirtualMutex.h
TBufferJSON::kNoSpaces
@ kNoSpaces
no new lines plus remove all spaces around "," and ":" symbols
Definition: TBufferJSON.h:39
kLong64_t
@ kLong64_t
Definition: TDataType.h:32
TObject::Warning
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:876
kFloat_t
@ kFloat_t
Definition: TDataType.h:31
TClass::IsTObject
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5752
idname
char idname[128]
Definition: THbookFile.cxx:90
TStreamerInfo::kTString
@ kTString
Definition: TStreamerInfo.h:173
kVoid_t
@ kVoid_t
Definition: TDataType.h:35
kOther_t
@ kOther_t
Definition: TDataType.h:32
unsigned int
TStreamerInfo::GetClassVersion
Int_t GetClassVersion() const
Definition: TStreamerInfo.h:208
TStreamerElement::SetMaxIndex
virtual void SetMaxIndex(Int_t dim, Int_t max)
set maximum index for array with dimension dim
Definition: TStreamerElement.cxx:498
TBufferJSON::WriteFloat
void WriteFloat(Float_t f) final
Writes Float_t value to buffer.
Definition: TBufferJSON.cxx:3816
TBufferJSON::WriteClass
void WriteClass(const TClass *cl) final
suppressed function of TBuffer
Definition: TBufferJSON.cxx:2457
TString::Index
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:639
TStreamerInfo::kStreamLoop
@ kStreamLoop
Definition: TStreamerInfo.h:179
TBufferJSON::ReadLong64
void ReadLong64(Long64_t &l) final
Reads Long64_t value from buffer.
Definition: TBufferJSON.cxx:3630
TBufferJSON::Stack
TJSONStackObj * Stack()
Definition: TBufferJSON.h:257
TBuffer::IsReading
Bool_t IsReading() const
Definition: TBuffer.h:86
ULong64_t
unsigned long long ULong64_t
Definition: RtypesCore.h:74
TBufferJSON::JsonReadCollection
void JsonReadCollection(TCollection *obj, const TClass *objClass)
read content of ROOT collection
Definition: TBufferJSON.cxx:1670
TStreamerInfo::kObjectp
@ kObjectp
Definition: TStreamerInfo.h:173
TBufferJSON::fOutput
TString * fOutput
! current output buffer for json code
Definition: TBufferJSON.h:318
Double_t
double Double_t
Definition: RtypesCore.h:59
TBufferJSON::JsonPushValue
void JsonPushValue()
If value exists, push in the current stack for post-processing.
Definition: TBufferJSON.cxx:2520
json_TCollection
@ json_TCollection
Definition: TBufferJSON.cxx:136
TObject::kNotDeleted
@ kNotDeleted
object has not been deleted
Definition: TObject.h:78
TArray
Abstract array base class.
Definition: TArray.h:31
TBufferJSON::JsonWriteConstChar
void JsonWriteConstChar(const char *value, Int_t len=-1, const char *=nullptr)
writes string value, processing all kind of special characters
Definition: TBufferJSON.cxx:4013
TDataMember::IsSTLContainer
Int_t IsSTLContainer()
The return type is defined in TDictionary (kVector, kList, etc.)
Definition: TDataMember.cxx:739
TClassEdit.h
TBufferJSON::WriteCharP
void WriteCharP(const Char_t *c) final
Writes array of characters to buffer.
Definition: TBufferJSON.cxx:3834
TBufferJSON::~TBufferJSON
virtual ~TBufferJSON()
destroy buffer
Definition: TBufferJSON.cxx:499
TBufferJSON::JsonReadArray
R__ALWAYS_INLINE Int_t JsonReadArray(T *value)
Read static array from JSON - not used.
Definition: TBufferJSON.cxx:2634
TStreamerObject
Definition: TStreamerElement.h:293
dummy
static RooMathCoreReg dummy
Definition: RooMathCoreReg.cxx:27
TBufferJSON::fTypeVersionTag
TString fTypeVersionTag
! JSON member used to store class version, default empty
Definition: TBufferJSON.h:329
TRealData
The TRealData class manages the effective list of all data members for a given class.
Definition: TRealData.h:30
TCollection::GetSize
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
TInterpreter.h
TObject::kIsOnHeap
@ kIsOnHeap
object is on heap
Definition: TObject.h:77
TBufferJSON::StreamObject
void StreamObject(void *obj, const std::type_info &typeinfo, const TClass *onFileClass=nullptr) override
stream object to/from buffer
Definition: TBufferText.cxx:465
TClass
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
TBufferJSON::GetInfo
TVirtualStreamerInfo * GetInfo() final
Return current streamer info element.
Definition: TBufferJSON.cxx:2078
TBufferJSON::WriteVersion
UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE) final
Ignored in TBufferJSON.
Definition: TBufferJSON.cxx:2485
TBufferJSON::JsonWriteFastArray
R__ALWAYS_INLINE void JsonWriteFastArray(const T *arr, Int_t arrsize, const char *typname, void(TBufferJSON::*method)(const T *, Int_t, const char *))
Template method to write array of arbitrary dimensions Different methods can be used for store last a...
Definition: TBufferJSON.cxx:3253
UChar_t
unsigned char UChar_t
Definition: RtypesCore.h:38
TDataMember::IsaPointer
Bool_t IsaPointer() const
Return true if data member is a pointer.
Definition: TDataMember.cxx:730
TCollection::SetName
void SetName(const char *name)
Definition: TCollection.h:204
TClass::Destructor
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5233
kBits
@ kBits
Definition: TDataType.h:34
TList::Add
virtual void Add(TObject *obj)
Definition: TList.h:87
TObject
Mother of all ROOT objects.
Definition: TObject.h:37
TBufferJSON::ReadObjectAny
void * ReadObjectAny(const TClass *clCast) final
Read object from buffer. Only used from TBuffer.
Definition: TBufferJSON.cxx:2493
TBufferJSON::ReadUInt
void ReadUInt(UInt_t &i) final
Reads UInt_t value from buffer.
Definition: TBufferJSON.cxx:3606
TString::Capacity
Ssiz_t Capacity() const
Definition: TString.h:357
TStreamerInfo::kTNamed
@ kTNamed
Definition: TStreamerInfo.h:174
TClass::GetBaseClassOffset
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2748
TMap.h
TCollection::Add
virtual void Add(TObject *obj)=0
TStreamerInfo::kBase
@ kBase
Definition: TStreamerInfo.h:167
TBufferText::ConvertDouble
static const char * ConvertDouble(Double_t v, char *buf, unsigned len, Bool_t not_optimize=kFALSE)
convert float to string with configured format
Definition: TBufferText.cxx:849
name
char name[80]
Definition: TGX11.cxx:110
TBufferJSON::JsonStartElement
void JsonStartElement(const TStreamerElement *elem, const TClass *base_class)
Start new class member in JSON structures.
Definition: TBufferJSON.cxx:1214
TDataMember::GetTrueTypeName
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
Definition: TDataMember.cxx:623
TBufferText::ReadBaseClass
virtual void ReadBaseClass(void *start, TStreamerBase *elem)
Read data of base class.
Definition: TBufferText.cxx:691
TBufferJSON::JsonReadObject
void * JsonReadObject(void *obj, const TClass *objClass=nullptr, TClass **readClass=nullptr)
Read object from current JSON node.
Definition: TBufferJSON.cxx:1768
ROOT::Math::Chebyshev::T
double T(double x)
Definition: ChebyshevPol.h:34
d
#define d(i)
Definition: RSha256.hxx:102
TBufferJSON::ReadBaseClass
void ReadBaseClass(void *start, TStreamerBase *elem) final
Read data of base class.
Definition: TBufferJSON.cxx:4054
TBufferJSON::ConvertToJSON
static TString ConvertToJSON(const TObject *obj, Int_t compact=0, const char *member_name=nullptr)
Converts object, inherited from TObject class, to JSON string Lower digit of compact parameter define...
Definition: TBufferJSON.cxx:524
TStreamerBasicType
Definition: TStreamerElement.h:269
TBufferJSON::ReadStaticArray
Int_t ReadStaticArray(Bool_t *b) final
Read array of Bool_t from buffer.
Definition: TBufferJSON.cxx:2643
TIter
Definition: TCollection.h:233
TBufferJSON::WriteDouble
void WriteDouble(Double_t d) final
Writes Double_t value to buffer.
Definition: TBufferJSON.cxx:3825
TBufferJSON::ConvertFromJSONAny
static void * ConvertFromJSONAny(const char *str, TClass **cl=nullptr)
Read object from JSON In class pointer (if specified) read class is returned One must specify expecte...
Definition: TBufferJSON.cxx:936
fFirst
T1 fFirst
Definition: X11Events.mm:86
TBufferJSON::WriteShort
void WriteShort(Short_t s) final
Writes Short_t value to buffer.
Definition: TBufferJSON.cxx:3744
RMakeUnique.hxx
TCollection
Collection abstract base class.
Definition: TCollection.h:63
TBufferJSON::kBase64
@ kBase64
all binary arrays will be compressed with base64 coding, supported by JSROOT
Definition: TBufferJSON.h:46
TClonesArray::ConstructedAt
TObject * ConstructedAt(Int_t idx)
Get an object at index 'idx' that is guaranteed to have been constructed.
Definition: TClonesArray.cxx:366
xmlio::cnt
const char * cnt
Definition: TXMLSetup.cxx:75
TNamed::GetName
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
TMemberStreamer
Definition: TMemberStreamer.h:26
TVirtualStreamerInfo::CanDelete
static Bool_t CanDelete()
static function returning true if ReadBuffer can delete object
Definition: TVirtualStreamerInfo.cxx:78
TStreamerInfo::kObject
@ kObject
Definition: TStreamerInfo.h:173
TStreamerElement::SetArrayDim
virtual void SetArrayDim(Int_t dim)
Set number of array dimensions.
Definition: TStreamerElement.cxx:488
free
#define free
Definition: civetweb.c:1539
TBufferJSON::ReadDouble
void ReadDouble(Double_t &d) final
Reads Double_t value from buffer.
Definition: TBufferJSON.cxx:3658
Class
void Class()
Definition: Class.C:29
TStreamerInfo::kOffsetP
@ kOffsetP
Definition: TStreamerInfo.h:167
TBufferIO::GetMappedObject
void GetMappedObject(UInt_t tag, void *&ptr, TClass *&ClassPtr) const override
Retrieve the object stored in the buffer's object map at 'tag' Set ptr and ClassPtr respectively to t...
Definition: TBufferIO.cxx:260
TClassEdit::kForwardlist
@ kForwardlist
Definition: TClassEdit.h:96
TBufferJSON::PerformPostProcessing
void PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_cl=nullptr)
Function is converts TObject and TString structures to more compact representation.
Definition: TBufferJSON.cxx:2327
TBufferJSON::WriteUInt
void WriteUInt(UInt_t i) final
Writes UInt_t value to buffer.
Definition: TBufferJSON.cxx:3771
TBufferJSON::WriteUShort
void WriteUShort(UShort_t s) final
Writes UShort_t value to buffer.
Definition: TBufferJSON.cxx:3753
kShort_t
@ kShort_t
Definition: TDataType.h:29
TCollection::GetName
virtual const char * GetName() const
Return name of this collection.
Definition: TCollection.cxx:351
TBufferJSON::JsonDisablePostprocessing
void JsonDisablePostprocessing()
disable post-processing of the code
Definition: TBufferJSON.cxx:1272
Char_t
char Char_t
Definition: RtypesCore.h:33
TStreamerInfo::kMissing
@ kMissing
Definition: TStreamerInfo.h:185
kBool_t
@ kBool_t
Definition: TDataType.h:32
TStreamerObjectAnyPointer
Definition: TStreamerElement.h:352
TClonesArray
An array of clone (identical) objects.
Definition: TClonesArray.h:29
TBufferJSON::ReadShort
void ReadShort(Short_t &s) final
Reads Short_t value from buffer.
Definition: TBufferJSON.cxx:3579
TBufferJSON::ClassEnd
void ClassEnd(const TClass *) final
Should be called at the end of custom streamer See TBufferJSON::ClassBegin for more details.
Definition: TBufferJSON.cxx:2189
TStreamerElement::GetArrayDim
Int_t GetArrayDim() const
Definition: TStreamerElement.h:106
TBufferJSON::IncrementLevel
void IncrementLevel(TVirtualStreamerInfo *) final
Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions and indent new level in js...
Definition: TBufferJSON.cxx:2000
TClassEdit::kMultiSet
@ kMultiSet
Definition: TClassEdit.h:101
TStreamerElement
Definition: TStreamerElement.h:33
TBufferJSON::SetSkipClassInfo
void SetSkipClassInfo(const TClass *cl)
Specify class which typename will not be stored in JSON Several classes can be configured To exclude ...
Definition: TBufferJSON.cxx:607
TStreamerBase
Definition: TStreamerElement.h:151
TBufferJSON::WriteBool
void WriteBool(Bool_t b) final
Writes Bool_t value to buffer.
Definition: TBufferJSON.cxx:3717
TClonesArray::SetClass
void SetClass(const char *classname, Int_t size=1000)
see TClonesArray::SetClass(const TClass*)
Definition: TClonesArray.cxx:690
TBufferJSON::PopStack
TJSONStackObj * PopStack()
remove one level from stack
Definition: TBufferJSON.cxx:1147
TList
A doubly linked list.
Definition: TList.h:44
TArray::GetSize
Int_t GetSize() const
Definition: TArray.h:47
TMemberStreamer.h
TObject::SetUniqueID
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition: TObject.cxx:707
TArrayI
Array of integers (32 bits per element).
Definition: TArrayI.h:27
gROOT
#define gROOT
Definition: TROOT.h:406
TBufferJSON::fSemicolon
TString fSemicolon
! depending from compression level, " : " or ":"
Definition: TBufferJSON.h:324
TBufferJSON::SetTypeversionTag
void SetTypeversionTag(const char *tag=nullptr)
Configures _typeversion tag in JSON One can specify name of the JSON tag like "_typeversion" or "$tv"...
Definition: TBufferJSON.cxx:594
int
TBufferText::ConvertFloat
static const char * ConvertFloat(Float_t v, char *buf, unsigned len, Bool_t not_optimize=kFALSE)
convert float to string with configured format
Definition: TBufferText.cxx:833
TBufferJSON::ReadInt
void ReadInt(Int_t &i) final
Reads Int_t value from buffer.
Definition: TBufferJSON.cxx:3595
Error
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition: TError.cxx:187
TError.h
R__ALWAYS_INLINE
#define R__ALWAYS_INLINE
Definition: RConfig.hxx:570
TBufferJSON::JsonWriteMember
TString JsonWriteMember(const void *ptr, TDataMember *member, TClass *memberClass, Int_t arraylen)
Convert single data member to JSON structures Returns string with converted member.
Definition: TBufferJSON.cxx:1009
TMap
TMap implements an associative array of (key,value) pairs using a THashTable for efficient retrieval ...
Definition: TMap.h:40
TBufferJSON::JsonReadBasic
R__ALWAYS_INLINE void JsonReadBasic(T &value)
Template function to read basic value from JSON.
Definition: TBufferJSON.cxx:3544
TDataMember::GetArrayIndex
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
Definition: TDataMember.cxx:567