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