Logo ROOT   6.16/01
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
16Class for serializing object to and from JavaScript Object Notation (JSON) format.
17It creates such object representation, which can be directly
18used in JavaScript ROOT (JSROOT) for drawing.
19
20TBufferJSON implements TBuffer interface, therefore most of
21ROOT and user classes can be converted into JSON.
22There are certain limitations for classes with custom streamers,
23which should be equipped specially for this purposes (see TCanvas::Streamer()
24as example).
25
26To 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
33To 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~~~
39JSON 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
41persistent 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
81enum { 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
89class TArrayIndexProducer {
90protected:
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
99public:
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
255class TJSONStackObj : public TObject {
256public:
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);
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
414TString 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
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
467TString 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
530TString 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
557Int_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
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
637Int_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
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
740void *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
770void *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
800TString 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
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
920TJSONStackObj *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
934TJSONStackObj *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
947void 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
969void 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
1074void 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 < ROOT::kSTLend)) {
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("unordered_map<") == 0)
1197 pairtype.Replace(0, 14, "pair<");
1198 else if (pairtype.Index("unordered_multimap<") == 0)
1199 pairtype.Replace(0, 19, "pair<");
1200 else if (pairtype.Index("multimap<") == 0)
1201 pairtype.Replace(0, 9, "pair<");
1202 else if (pairtype.Index("map<") == 0)
1203 pairtype.Replace(0, 4, "pair<");
1204 else
1205 pairtype = "TPair";
1206 pairtype = TString("\"") + pairtype + TString("\"");
1207 for (Int_t k = 1; k < stack->fValues.GetLast(); k += 2) {
1208 fValue.Append(separ);
1209 separ = fArraySepar.Data();
1210 // fJsonrCnt++; // do not add entry in the map, can conflict with objects inside values
1211 fValue.Append("{");
1212 fValue.Append("\"$pair\"");
1214 fValue.Append(pairtype.Data());
1216 fValue.Append("\"first\"");
1218 fValue.Append(stack->fValues.At(k)->GetName());
1220 fValue.Append("\"second\"");
1222 fValue.Append(stack->fValues.At(k + 1)->GetName());
1223 fValue.Append("}");
1224 }
1225 } else {
1226 // for most stl containers write just like blob, but skipping first element with size
1227 for (Int_t k = 1; k <= stack->fValues.GetLast(); k++) {
1228 fValue.Append(separ);
1229 separ = fArraySepar.Data();
1230 fValue.Append(stack->fValues.At(k)->GetName());
1231 }
1232 }
1233
1234 fValue.Append("]");
1235 stack->fValues.Delete();
1236 }
1237 }
1238 }
1239
1240 // reuse post-processing code for TObject or TRef
1241 PerformPostProcessing(stack, cl);
1242
1243 if ((special_kind == 0) && ((stack->fValues.GetLast() >= 0) || (fValue.Length() > 0))) {
1244 if (gDebug > 0)
1245 Info("JsonWriteObject", "Create blob value for class %s", cl->GetName());
1246
1247 AppendOutput(fArraySepar.Data(), "\"_blob\"");
1249
1250 const char *separ = "[";
1251
1252 for (Int_t k = 0; k <= stack->fValues.GetLast(); k++) {
1253 AppendOutput(separ);
1254 separ = fArraySepar.Data();
1255 AppendOutput(stack->fValues.At(k)->GetName());
1256 }
1257
1258 if (fValue.Length() > 0) {
1259 AppendOutput(separ);
1261 }
1262
1263 AppendOutput("]");
1264
1265 fValue.Clear();
1266 stack->fValues.Delete();
1267 }
1268
1269 PopStack();
1270
1271 if (special_kind <= 0) {
1272 AppendOutput(0, "}");
1273 }
1274
1275post_process:
1276
1277 if (fPrevOutput) {
1278 fOutput = fPrevOutput;
1279 // for STL containers and TArray object in fValue itself
1280 if ((special_kind <= 0) || (special_kind > json_TArray))
1281 fValue = fObjectOutput;
1282 else if (fObjectOutput.Length() != 0)
1283 Error("JsonWriteObject", "Non-empty object output for special class %s", cl->GetName());
1284 }
1285}
1286
1287////////////////////////////////////////////////////////////////////////////////
1288/// store content of ROOT collection
1289
1291{
1292 AppendOutput(",", "\"name\"");
1294 AppendOutput("\"");
1295 AppendOutput(col->GetName());
1296 AppendOutput("\",", "\"arr\"");
1298
1299 // collection treated as JS Array
1300 AppendOutput("[");
1301
1302 bool islist = col->InheritsFrom(TList::Class());
1303 TMap *map = nullptr;
1304 if (col->InheritsFrom(TMap::Class()))
1305 map = dynamic_cast<TMap *>(col);
1306
1307 TString sopt;
1308 if (islist) {
1309 sopt.Capacity(500);
1310 sopt = "[";
1311 }
1312
1313 TIter iter(col);
1314 TObject *obj;
1315 Bool_t first = kTRUE;
1316 while ((obj = iter()) != nullptr) {
1317 if (!first)
1319
1320 if (map) {
1321 // fJsonrCnt++; // do not account map pair as JSON object
1322 AppendOutput("{", "\"$pair\"");
1324 AppendOutput("\"TPair\"");
1325 AppendOutput(fArraySepar.Data(), "\"first\"");
1327 }
1328
1330
1331 if (map) {
1332 AppendOutput(fArraySepar.Data(), "\"second\"");
1335 AppendOutput("", "}");
1336 }
1337
1338 if (islist) {
1339 if (!first)
1340 sopt.Append(fArraySepar.Data());
1341 sopt.Append("\"");
1342 sopt.Append(iter.GetOption());
1343 sopt.Append("\"");
1344 }
1345
1346 first = kFALSE;
1347 }
1348
1349 AppendOutput("]");
1350
1351 if (islist) {
1352 sopt.Append("]");
1353 AppendOutput(",", "\"opt\"");
1355 AppendOutput(sopt.Data());
1356 }
1357 fValue.Clear();
1358}
1359
1360////////////////////////////////////////////////////////////////////////////////
1361/// read content of ROOT collection
1362
1364{
1365 if (!col)
1366 return;
1367
1368 TList *lst = nullptr;
1369 TMap *map = nullptr;
1370 TClonesArray *clones = nullptr;
1371 if (col->InheritsFrom(TList::Class()))
1372 lst = dynamic_cast<TList *>(col);
1373 else if (col->InheritsFrom(TMap::Class()))
1374 map = dynamic_cast<TMap *>(col);
1375 else if (col->InheritsFrom(TClonesArray::Class()))
1376 clones = dynamic_cast<TClonesArray *>(col);
1377
1378 nlohmann::json *json = Stack()->fNode;
1379
1380 std::string name = json->at("name");
1381 col->SetName(name.c_str());
1382
1383 nlohmann::json &arr = json->at("arr");
1384 int size = arr.size();
1385
1386 for (int n = 0; n < size; ++n) {
1387 nlohmann::json *subelem = &arr.at(n);
1388
1389 if (map)
1390 subelem = &subelem->at("first");
1391
1392 PushStack(0, subelem);
1393
1394 TClass *readClass = nullptr, *objClass = nullptr;
1395 void *subobj = nullptr;
1396
1397 if (clones) {
1398 if (n == 0) {
1399 if (!clones->GetClass() || (clones->GetSize() == 0)) {
1400 clones->SetClass(subelem->at("_typename").get<std::string>().c_str(), size);
1401 } else if (size > clones->GetSize()) {
1402 Error("JsonReadCollection", "TClonesArray size %d smaller than required %d\n", clones->GetSize(), size);
1403 return;
1404 }
1405 }
1406 objClass = clones->GetClass();
1407 subobj = clones->ConstructedAt(n);
1408 }
1409
1410 subobj = JsonReadObject(subobj, objClass, &readClass);
1411
1412 PopStack();
1413
1414 if (clones)
1415 continue;
1416
1417 if (!subobj || !readClass) {
1418 subobj = nullptr;
1419 } else if (readClass->GetBaseClassOffset(TObject::Class()) != 0) {
1420 Error("JsonReadCollection", "Try to add object %s not derived from TObject", readClass->GetName());
1421 subobj = nullptr;
1422 }
1423
1424 TObject *tobj = static_cast<TObject *>(subobj);
1425
1426 if (map) {
1427 PushStack(0, &arr.at(n).at("second"));
1428
1429 readClass = nullptr;
1430 void *subobj2 = JsonReadObject(nullptr, nullptr, &readClass);
1431
1432 PopStack();
1433
1434 if (!subobj2 || !readClass) {
1435 subobj2 = nullptr;
1436 } else if (readClass->GetBaseClassOffset(TObject::Class()) != 0) {
1437 Error("JsonReadCollection", "Try to add object %s not derived from TObject", readClass->GetName());
1438 subobj2 = nullptr;
1439 }
1440
1441 map->Add(tobj, static_cast<TObject *>(subobj2));
1442 } else if (lst) {
1443 std::string opt = json->at("opt").at(n).get<std::string>();
1444 lst->Add(tobj, opt.c_str());
1445 } else {
1446 // generic method, all kinds of TCollection should work
1447 col->Add(tobj);
1448 }
1449 }
1450}
1451
1452////////////////////////////////////////////////////////////////////////////////
1453/// Read object from current JSON node
1454
1455void *TBufferJSON::JsonReadObject(void *obj, const TClass *objClass, TClass **readClass)
1456{
1457 if (readClass)
1458 *readClass = nullptr;
1459
1460 TJSONStackObj *stack = Stack();
1461
1462 Bool_t process_stl = stack->IsStl();
1463 nlohmann::json *json = stack->GetStlNode();
1464
1465 // check if null pointer
1466 if (json->is_null())
1467 return nullptr;
1468
1469 Int_t special_kind = JsonSpecialClass(objClass);
1470
1471 // Extract pointer
1472 if (json->is_object() && (json->size() == 1) && (json->find("$ref") != json->end())) {
1473 unsigned refid = json->at("$ref").get<unsigned>();
1474
1475 void *ref_obj = nullptr;
1476 TClass *ref_cl = nullptr;
1477
1478 GetMappedObject(refid + 1, ref_obj, ref_cl);
1479
1480 if (!ref_obj || !ref_cl) {
1481 Error("JsonReadObject", "Fail to find object for reference %u", refid);
1482 return nullptr;
1483 }
1484
1485 if (readClass)
1486 *readClass = ref_cl;
1487
1488 if (gDebug > 2)
1489 Info("JsonReadObject", "Extract object reference %u %p cl:%s expects:%s", refid, ref_obj, ref_cl->GetName(),
1490 (objClass ? objClass->GetName() : "---"));
1491
1492 return ref_obj;
1493 }
1494
1495 // special case of strings - they do not create JSON object, but just string
1496 if ((special_kind == json_stdstring) || (special_kind == json_TString)) {
1497 if (!obj)
1498 obj = objClass->New();
1499
1500 if (gDebug > 2)
1501 Info("JsonReadObject", "Read string from %s", json->dump().c_str());
1502
1503 if (special_kind == json_stdstring)
1504 *((std::string *)obj) = json->get<std::string>();
1505 else
1506 *((TString *)obj) = json->get<std::string>().c_str();
1507
1508 if (readClass)
1509 *readClass = (TClass *)objClass;
1510
1511 return obj;
1512 }
1513
1514 Bool_t isBase = (stack->fElem && objClass) ? stack->fElem->IsBase() : kFALSE; // base class
1515
1516 if (isBase && (!obj || !objClass)) {
1517 Error("JsonReadObject", "No object when reading base class");
1518 return obj;
1519 }
1520
1521 // from now all operations performed with sub-element,
1522 // stack should be repaired at the end
1523 if (process_stl)
1524 stack = PushStack(0, json);
1525
1526 TClass *jsonClass = nullptr;
1527
1528 if ((special_kind == json_TArray) || ((special_kind > 0) && (special_kind < ROOT::kSTLend))) {
1529
1530 jsonClass = (TClass *)objClass;
1531
1532 if (!obj)
1533 obj = jsonClass->New();
1534
1535 Int_t len = stack->IsJsonArray(json);
1536
1537 stack->PushIntValue(len > 0 ? len : 0);
1538
1539 if (len < 0) // should never happens
1540 Error("JsonReadObject", "Not array when expecting such %s", json->dump().c_str());
1541
1542 if (gDebug > 1)
1543 Info("JsonReadObject", "Reading special kind %d %s ptr %p", special_kind, objClass->GetName(), obj);
1544
1545 } else if (isBase) {
1546 // base class has special handling - no additional level and no extra refid
1547
1548 jsonClass = (TClass *)objClass;
1549
1550 if (gDebug > 1)
1551 Info("JsonReadObject", "Reading baseclass %s ptr %p", objClass->GetName(), obj);
1552 } else {
1553
1554 std::string clname = json->at("_typename").get<std::string>();
1555
1556 jsonClass = clname.empty() ? nullptr : TClass::GetClass(clname.c_str());
1557
1558 if (!jsonClass) {
1559 Error("JsonReadObject", "Cannot find class %s", clname.c_str());
1560 if (process_stl)
1561 PopStack();
1562 return obj;
1563 }
1564
1565 if (objClass && (jsonClass != objClass)) {
1566 Error("JsonReadObject", "Class mismatch between provided %s and in JSON %s", objClass->GetName(),
1567 jsonClass->GetName());
1568 }
1569
1570 if (!obj)
1571 obj = jsonClass->New();
1572
1573 if (gDebug > 1)
1574 Info("JsonReadObject", "Reading object of class %s refid %u ptr %p", clname.c_str(), fJsonrCnt, obj);
1575
1576 if (!special_kind)
1577 special_kind = JsonSpecialClass(jsonClass);
1578
1579 // add new element to the reading map
1580 MapObject(obj, jsonClass, ++fJsonrCnt);
1581 }
1582
1583 // there are two ways to handle custom streamers
1584 // either prepare data before streamer and tweak basic function which are reading values like UInt32_t
1585 // or try re-implement custom streamer here
1586
1587 if ((jsonClass == TObject::Class()) || (jsonClass == TRef::Class())) {
1588 // for TObject we re-implement custom streamer - it is much easier
1589
1591
1592 } else if (special_kind == json_TCollection) {
1593
1594 JsonReadCollection((TCollection *)obj, jsonClass);
1595
1596 } else {
1597
1598 // special handling of STL which coded into arrays
1599 if ((special_kind > 0) && (special_kind < ROOT::kSTLend)) {
1600 stack->fStlIndx = 0;
1601 if ((special_kind == TClassEdit::kMap) || (special_kind == TClassEdit::kMultiMap) ||
1602 (special_kind == TClassEdit::kUnorderedMap) || (special_kind == TClassEdit::kUnorderedMultiMap))
1603 stack->fStlMap = 0;
1604 }
1605
1606 // workaround for missing version in JSON structures
1607 stack->fClVersion = jsonClass->GetClassVersion();
1608
1609 if (gDebug > 3)
1610 Info("JsonReadObject", "Calling streamer of class %s", jsonClass->GetName());
1611
1612 if (isBase && (special_kind == 0))
1613 Error("JsonReadObject", "Should not be used for reading of base class %s", jsonClass->GetName());
1614
1615 jsonClass->Streamer((void *)obj, *this);
1616
1617 stack->fClVersion = 0;
1618
1619 stack->fStlIndx = -1; // reset STL index for itself to prevent looping
1620 stack->fStlMap = -1;
1621 }
1622
1623 // return back stack position
1624 if (process_stl)
1625 PopStack();
1626
1627 if (gDebug > 1)
1628 Info("JsonReadObject", "Reading object of class %s done", jsonClass->GetName());
1629
1630 if (readClass)
1631 *readClass = jsonClass;
1632
1633 return obj;
1634}
1635
1637{
1638 nlohmann::json *json = node ? (nlohmann::json *)node : Stack()->fNode;
1639
1640 UInt_t uid = json->at("fUniqueID").get<unsigned>();
1641 UInt_t bits = json->at("fBits").get<unsigned>();
1642 // UInt32_t pid = json->at("fPID").get<unsigned>(); // ignore PID for the moment
1643
1644 tobj->SetUniqueID(uid);
1645 // there is no method to set all bits directly - do it one by one
1646 for (unsigned n = 0; n < 32; n++)
1647 tobj->SetBit(BIT(n), (bits & BIT(n)) != 0);
1648
1649 if (gDebug > 2)
1650 Info("JsonReadTObjectMembers", "Reading TObject part bits %u kMustCleanup %d", bits, tobj->TestBit(kMustCleanup));
1651}
1652
1653////////////////////////////////////////////////////////////////////////////////
1654/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
1655/// and indent new level in json structure.
1656/// This call indicates, that TStreamerInfo functions starts streaming
1657/// object data of correspondent class
1658
1660{
1661 if (gDebug > 2)
1662 Info("IncrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
1663
1665}
1666
1667////////////////////////////////////////////////////////////////////////////////
1668/// Prepares buffer to stream data of specified class
1669
1671{
1672 if (sinfo)
1673 cl = sinfo->GetClass();
1674
1675 if (!cl)
1676 return;
1677
1678 if (gDebug > 3)
1679 Info("WorkWithClass", "Class: %s", cl->GetName());
1680
1681 TJSONStackObj *stack = Stack();
1682
1683 if (IsReading()) {
1684 stack = PushStack(0, stack->fNode);
1685 } else if (stack && stack->IsStreamerElement() && !stack->fIsObjStarted &&
1686 ((stack->fElem->GetType() == TStreamerInfo::kObject) ||
1687 (stack->fElem->GetType() == TStreamerInfo::kAny))) {
1688
1689 stack->fIsObjStarted = kTRUE;
1690
1691 fJsonrCnt++; // count object, but do not keep reference
1692
1693 stack = PushStack(2);
1694 AppendOutput("{", "\"_typename\"");
1696 AppendOutput("\"");
1697 AppendOutput(cl->GetName());
1698 AppendOutput("\"");
1699 } else {
1700 stack = PushStack(0);
1701 }
1702
1703 stack->fInfo = sinfo;
1704 stack->fIsStreamerInfo = kTRUE;
1705}
1706
1707////////////////////////////////////////////////////////////////////////////////
1708/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
1709/// and decrease level in json structure.
1710
1712{
1713 if (gDebug > 2)
1714 Info("DecrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
1715
1716 TJSONStackObj *stack = Stack();
1717
1718 if (stack->IsStreamerElement()) {
1719
1720 if (IsWriting()) {
1721 if (gDebug > 3)
1722 Info("DecrementLevel", " Perform post-processing elem: %s", stack->fElem->GetName());
1723
1724 PerformPostProcessing(stack);
1725 }
1726
1727 stack = PopStack(); // remove stack of last element
1728 }
1729
1730 if (stack->fInfo != (TStreamerInfo *)info)
1731 Error("DecrementLevel", " Mismatch of streamer info");
1732
1733 PopStack(); // back from data of stack info
1734
1735 if (gDebug > 3)
1736 Info("DecrementLevel", "Class: %s done", (info ? info->GetClass()->GetName() : "custom"));
1737}
1738
1739////////////////////////////////////////////////////////////////////////////////
1740/// Return current streamer info element
1741
1743{
1744 return Stack()->fInfo;
1745}
1746
1747////////////////////////////////////////////////////////////////////////////////
1748/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
1749/// and add/verify next element of json structure
1750/// This calls allows separate data, correspondent to one class member, from another
1751
1753{
1754 if (gDebug > 3)
1755 Info("SetStreamerElementNumber", "Element name %s", elem->GetName());
1756
1757 WorkWithElement(elem, comp_type);
1758}
1759
1760////////////////////////////////////////////////////////////////////////////////
1761/// This is call-back from streamer which indicates
1762/// that class member will be streamed
1763/// Name of element used in JSON
1764
1766{
1767 TJSONStackObj *stack = Stack();
1768 if (!stack) {
1769 Error("WorkWithElement", "stack is empty");
1770 return;
1771 }
1772
1773 if (gDebug > 0)
1774 Info("WorkWithElement", " Start element %s type %d typename %s", elem ? elem->GetName() : "---",
1775 elem ? elem->GetType() : -1, elem ? elem->GetTypeName() : "---");
1776
1777 if (stack->IsStreamerElement()) {
1778 // this is post processing
1779
1780 if (IsWriting()) {
1781 if (gDebug > 3)
1782 Info("WorkWithElement", " Perform post-processing elem: %s", stack->fElem->GetName());
1783 PerformPostProcessing(stack);
1784 }
1785
1786 stack = PopStack(); // go level back
1787 }
1788
1789 fValue.Clear();
1790
1791 if (!stack) {
1792 Error("WorkWithElement", "Lost of stack");
1793 return;
1794 }
1795
1796 TStreamerInfo *info = stack->fInfo;
1797 if (!stack->IsStreamerInfo()) {
1798 Error("WorkWithElement", "Problem in Inc/Dec level");
1799 return;
1800 }
1801
1802 Int_t number = info ? info->GetElements()->IndexOf(elem) : -1;
1803
1804 if (!elem) {
1805 Error("WorkWithElement", "streamer info returns elem = 0");
1806 return;
1807 }
1808
1809 TClass *base_class = elem->IsBase() ? elem->GetClassPointer() : nullptr;
1810
1811 stack = PushStack(0, stack->fNode);
1812 stack->fElem = (TStreamerElement *)elem;
1813 stack->fIsElemOwner = (number < 0);
1814
1815 JsonStartElement(elem, base_class);
1816
1817 if (base_class && IsReading())
1818 stack->fClVersion = base_class->GetClassVersion();
1819
1820 if ((elem->GetType() == TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop) && (elem->GetArrayDim() > 0)) {
1821 // array of array, start handling here
1822 stack->fIndx = new TArrayIndexProducer(elem, -1, fArraySepar.Data());
1823 if (IsWriting())
1824 AppendOutput(stack->fIndx->GetBegin());
1825 }
1826
1827 if (IsReading() && (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20)) {
1828 // reading of such array begins with reading of single Char_t value
1829 // it indicates if array should be read or not
1830 stack->PushIntValue(stack->IsJsonString() || (stack->IsJsonArray() > 0) ? 1 : 0);
1831 }
1832}
1833
1834////////////////////////////////////////////////////////////////////////////////
1835/// Should be called in the beginning of custom class streamer.
1836/// Informs buffer data about class which will be streamed now.
1837///
1838/// ClassBegin(), ClassEnd() and ClassMember() should be used in
1839/// custom class streamers to specify which kind of data are
1840/// now streamed. Such information is used to correctly
1841/// convert class data to JSON. Without that functions calls
1842/// classes with custom streamers cannot be used with TBufferJSON
1843
1845{
1846 WorkWithClass(nullptr, cl);
1847}
1848
1849////////////////////////////////////////////////////////////////////////////////
1850/// Should be called at the end of custom streamer
1851/// See TBufferJSON::ClassBegin for more details
1852
1854{
1855 DecrementLevel(0);
1856}
1857
1858////////////////////////////////////////////////////////////////////////////////
1859/// Method indicates name and typename of class member,
1860/// which should be now streamed in custom streamer
1861/// Following combinations are supported:
1862/// 1. name = "ClassName", typeName = 0 or typename==ClassName
1863/// This is a case, when data of parent class "ClassName" should be streamed.
1864/// For instance, if class directly inherited from TObject, custom
1865/// streamer should include following code:
1866/// ~~~{.cpp}
1867/// b.ClassMember("TObject");
1868/// TObject::Streamer(b);
1869/// ~~~
1870/// 2. Basic data type
1871/// ~~~{.cpp}
1872/// b.ClassMember("fInt","Int_t");
1873/// b >> fInt;
1874/// ~~~
1875/// 3. Array of basic data types
1876/// ~~~{.cpp}
1877/// b.ClassMember("fArr","Int_t", 5);
1878/// b.ReadFastArray(fArr, 5);
1879/// ~~~
1880/// 4. Object as data member
1881/// ~~~{.cpp}
1882/// b.ClassMember("fName","TString");
1883/// fName.Streamer(b);
1884/// ~~~
1885/// 5. Pointer on object as data member
1886/// ~~~{.cpp}
1887/// b.ClassMember("fObj","TObject*");
1888/// b.StreamObject(fObj);
1889/// ~~~
1890///
1891/// arrsize1 and arrsize2 arguments (when specified) indicate first and
1892/// second dimension of array. Can be used for array of basic types.
1893/// See ClassBegin() method for more details.
1894
1895void TBufferJSON::ClassMember(const char *name, const char *typeName, Int_t arrsize1, Int_t arrsize2)
1896{
1897 if (!typeName)
1898 typeName = name;
1899
1900 if (!name || (strlen(name) == 0)) {
1901 Error("ClassMember", "Invalid member name");
1902 return;
1903 }
1904
1905 TString tname = typeName;
1906
1907 Int_t typ_id = -1;
1908
1909 if (strcmp(typeName, "raw:data") == 0)
1910 typ_id = TStreamerInfo::kMissing;
1911
1912 if (typ_id < 0) {
1913 TDataType *dt = gROOT->GetType(typeName);
1914 if (dt && (dt->GetType() > 0) && (dt->GetType() < 20))
1915 typ_id = dt->GetType();
1916 }
1917
1918 if (typ_id < 0)
1919 if (strcmp(name, typeName) == 0) {
1920 TClass *cl = TClass::GetClass(tname.Data());
1921 if (cl)
1922 typ_id = TStreamerInfo::kBase;
1923 }
1924
1925 if (typ_id < 0) {
1926 Bool_t isptr = kFALSE;
1927 if (tname[tname.Length() - 1] == '*') {
1928 tname.Resize(tname.Length() - 1);
1929 isptr = kTRUE;
1930 }
1931 TClass *cl = TClass::GetClass(tname.Data());
1932 if (!cl) {
1933 Error("ClassMember", "Invalid class specifier %s", typeName);
1934 return;
1935 }
1936
1937 if (cl->IsTObject())
1939 else
1940 typ_id = isptr ? TStreamerInfo::kAnyp : TStreamerInfo::kAny;
1941
1942 if ((cl == TString::Class()) && !isptr)
1943 typ_id = TStreamerInfo::kTString;
1944 }
1945
1946 TStreamerElement *elem = nullptr;
1947
1948 if (typ_id == TStreamerInfo::kMissing) {
1949 elem = new TStreamerElement(name, "title", 0, typ_id, "raw:data");
1950 } else if (typ_id == TStreamerInfo::kBase) {
1951 TClass *cl = TClass::GetClass(tname.Data());
1952 if (cl) {
1953 TStreamerBase *b = new TStreamerBase(tname.Data(), "title", 0);
1954 b->SetBaseVersion(cl->GetClassVersion());
1955 elem = b;
1956 }
1957 } else if ((typ_id > 0) && (typ_id < 20)) {
1958 elem = new TStreamerBasicType(name, "title", 0, typ_id, typeName);
1959 } else if ((typ_id == TStreamerInfo::kObject) || (typ_id == TStreamerInfo::kTObject) ||
1960 (typ_id == TStreamerInfo::kTNamed)) {
1961 elem = new TStreamerObject(name, "title", 0, tname.Data());
1962 } else if (typ_id == TStreamerInfo::kObjectp) {
1963 elem = new TStreamerObjectPointer(name, "title", 0, tname.Data());
1964 } else if (typ_id == TStreamerInfo::kAny) {
1965 elem = new TStreamerObjectAny(name, "title", 0, tname.Data());
1966 } else if (typ_id == TStreamerInfo::kAnyp) {
1967 elem = new TStreamerObjectAnyPointer(name, "title", 0, tname.Data());
1968 } else if (typ_id == TStreamerInfo::kTString) {
1969 elem = new TStreamerString(name, "title", 0);
1970 }
1971
1972 if (!elem) {
1973 Error("ClassMember", "Invalid combination name = %s type = %s", name, typeName);
1974 return;
1975 }
1976
1977 if (arrsize1 > 0) {
1978 elem->SetArrayDim(arrsize2 > 0 ? 2 : 1);
1979 elem->SetMaxIndex(0, arrsize1);
1980 if (arrsize2 > 0)
1981 elem->SetMaxIndex(1, arrsize2);
1982 }
1983
1984 // we indicate that there is no streamerinfo
1985 WorkWithElement(elem, -1);
1986}
1987
1988////////////////////////////////////////////////////////////////////////////////
1989/// Function is converts TObject and TString structures to more compact representation
1990
1991void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_cl)
1992{
1993 if (stack->fIsPostProcessed)
1994 return;
1995
1996 const TStreamerElement *elem = stack->fElem;
1997
1998 if (!elem && !obj_cl)
1999 return;
2000
2001 stack->fIsPostProcessed = kTRUE;
2002
2003 // when element was written as separate object, close only braces and exit
2004 if (stack->fIsObjStarted) {
2005 AppendOutput("", "}");
2006 return;
2007 }
2008
2009 Bool_t isTObject(kFALSE), isTRef(kFALSE), isTString(kFALSE), isSTLstring(kFALSE), isOffsetPArray(kFALSE),
2010 isTArray(kFALSE);
2011
2012 if (obj_cl) {
2013 if (obj_cl == TObject::Class())
2014 isTObject = kTRUE;
2015 else if (obj_cl == TRef::Class())
2016 isTRef = kTRUE;
2017 else
2018 return;
2019 } else {
2020 const char *typname = elem->IsBase() ? elem->GetName() : elem->GetTypeName();
2021 isTObject = (elem->GetType() == TStreamerInfo::kTObject) || (strcmp("TObject", typname) == 0);
2022 isTString = elem->GetType() == TStreamerInfo::kTString;
2023 isSTLstring = elem->GetType() == TStreamerInfo::kSTLstring;
2024 isOffsetPArray = (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20);
2025 isTArray = (strncmp("TArray", typname, 6) == 0);
2026 }
2027
2028 if (isTString || isSTLstring) {
2029 // just remove all kind of string length information
2030
2031 if (gDebug > 3)
2032 Info("PerformPostProcessing", "reformat string value = '%s'", fValue.Data());
2033
2034 stack->fValues.Delete();
2035 } else if (isOffsetPArray) {
2036 // basic array with [fN] comment
2037
2038 if ((stack->fValues.GetLast() < 0) && (fValue == "0")) {
2039 fValue = "[]";
2040 } else if ((stack->fValues.GetLast() == 0) && (strcmp(stack->fValues.Last()->GetName(), "1") == 0)) {
2041 stack->fValues.Delete();
2042 } else {
2043 Error("PerformPostProcessing", "Wrong values for kOffsetP element %s", (elem ? elem->GetName() : "---"));
2044 stack->fValues.Delete();
2045 fValue = "[]";
2046 }
2047 } else if (isTObject || isTRef) {
2048 // complex workaround for TObject/TRef streamer
2049 // would be nice if other solution can be found
2050 // Here is not supported TRef on TRef (double reference)
2051
2052 Int_t cnt = stack->fValues.GetLast() + 1;
2053 if (fValue.Length() > 0)
2054 cnt++;
2055
2056 if (cnt < 2 || cnt > 3) {
2057 if (gDebug > 0)
2058 Error("PerformPostProcessing", "When storing TObject/TRef, strange number of items %d", cnt);
2059 AppendOutput(",", "\"dummy\"");
2061 } else {
2062 AppendOutput(",", "\"fUniqueID\"");
2064 AppendOutput(stack->fValues.At(0)->GetName());
2065 AppendOutput(",", "\"fBits\"");
2067 AppendOutput((stack->fValues.GetLast() > 0) ? stack->fValues.At(1)->GetName() : fValue.Data());
2068 if (cnt == 3) {
2069 AppendOutput(",", "\"fPID\"");
2071 AppendOutput((stack->fValues.GetLast() > 1) ? stack->fValues.At(2)->GetName() : fValue.Data());
2072 }
2073
2074 stack->fValues.Delete();
2075 fValue.Clear();
2076 return;
2077 }
2078
2079 } else if (isTArray) {
2080 // for TArray one deletes complete stack
2081 stack->fValues.Delete();
2082 }
2083
2084 if (elem && elem->IsBase() && (fValue.Length() == 0)) {
2085 // here base class data already completely stored
2086 return;
2087 }
2088
2089 if (stack->fValues.GetLast() >= 0) {
2090 // append element blob data just as abstract array, user is responsible to decode it
2091 AppendOutput("[");
2092 for (Int_t n = 0; n <= stack->fValues.GetLast(); n++) {
2093 AppendOutput(stack->fValues.At(n)->GetName());
2095 }
2096 }
2097
2098 if (fValue.Length() == 0) {
2099 AppendOutput("null");
2100 } else {
2102 fValue.Clear();
2103 }
2104
2105 if (stack->fValues.GetLast() >= 0)
2106 AppendOutput("]");
2107}
2108
2109////////////////////////////////////////////////////////////////////////////////
2110/// suppressed function of TBuffer
2111
2113{
2114 return nullptr;
2115}
2116
2117////////////////////////////////////////////////////////////////////////////////
2118/// suppressed function of TBuffer
2119
2121{
2122}
2123
2124////////////////////////////////////////////////////////////////////////////////
2125/// read version value from buffer
2126
2128{
2129 Version_t res = cl ? cl->GetClassVersion() : 0;
2130
2131 if (start)
2132 *start = 0;
2133 if (bcnt)
2134 *bcnt = 0;
2135
2136 if (!cl && Stack()->fClVersion) {
2137 res = Stack()->fClVersion;
2138 Stack()->fClVersion = 0;
2139 }
2140
2141 if (gDebug > 3)
2142 Info("ReadVersion", "Result: %d Class: %s", res, (cl ? cl->GetName() : "---"));
2143
2144 return res;
2145}
2146
2147////////////////////////////////////////////////////////////////////////////////
2148/// Ignored in TBufferJSON
2149
2150UInt_t TBufferJSON::WriteVersion(const TClass * /*cl*/, Bool_t /* useBcnt */)
2151{
2152 return 0;
2153}
2154
2155////////////////////////////////////////////////////////////////////////////////
2156/// Read object from buffer. Only used from TBuffer
2157
2158void *TBufferJSON::ReadObjectAny(const TClass *expectedClass)
2159{
2160 if (gDebug > 2)
2161 Info("ReadObjectAny", "From current JSON node");
2162 void *res = JsonReadObject(nullptr, expectedClass);
2163 return res;
2164}
2165
2166////////////////////////////////////////////////////////////////////////////////
2167/// Skip any kind of object from buffer
2168
2170{
2171}
2172
2173////////////////////////////////////////////////////////////////////////////////
2174/// Write object to buffer. Only used from TBuffer
2175
2176void TBufferJSON::WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse)
2177{
2178 if (gDebug > 3)
2179 Info("WriteObjectClass", "Class %s", (actualClass ? actualClass->GetName() : " null"));
2180
2181 JsonWriteObject(actualObjStart, actualClass, cacheReuse);
2182}
2183
2184////////////////////////////////////////////////////////////////////////////////
2185/// If value exists, push in the current stack for post-processing
2186
2188{
2189 if (fValue.Length() > 0)
2190 Stack()->PushValue(fValue);
2191}
2192
2193////////////////////////////////////////////////////////////////////////////////
2194/// Read array of Bool_t from buffer
2195
2197{
2198 return JsonReadArray(b);
2199}
2200
2201////////////////////////////////////////////////////////////////////////////////
2202/// Read array of Char_t from buffer
2203
2205{
2206 return JsonReadArray(c);
2207}
2208
2209////////////////////////////////////////////////////////////////////////////////
2210/// Read array of UChar_t from buffer
2211
2213{
2214 return JsonReadArray(c);
2215}
2216
2217////////////////////////////////////////////////////////////////////////////////
2218/// Read array of Short_t from buffer
2219
2221{
2222 return JsonReadArray(h);
2223}
2224
2225////////////////////////////////////////////////////////////////////////////////
2226/// Read array of UShort_t from buffer
2227
2229{
2230 return JsonReadArray(h);
2231}
2232
2233////////////////////////////////////////////////////////////////////////////////
2234/// Read array of Int_t from buffer
2235
2237{
2238 return JsonReadArray(i);
2239}
2240
2241////////////////////////////////////////////////////////////////////////////////
2242/// Read array of UInt_t from buffer
2243
2245{
2246 return JsonReadArray(i);
2247}
2248
2249////////////////////////////////////////////////////////////////////////////////
2250/// Read array of Long_t from buffer
2251
2253{
2254 return JsonReadArray(l);
2255}
2256
2257////////////////////////////////////////////////////////////////////////////////
2258/// Read array of ULong_t from buffer
2259
2261{
2262 return JsonReadArray(l);
2263}
2264
2265////////////////////////////////////////////////////////////////////////////////
2266/// Read array of Long64_t from buffer
2267
2269{
2270 return JsonReadArray(l);
2271}
2272
2273////////////////////////////////////////////////////////////////////////////////
2274/// Read array of ULong64_t from buffer
2275
2277{
2278 return JsonReadArray(l);
2279}
2280
2281////////////////////////////////////////////////////////////////////////////////
2282/// Read array of Float_t from buffer
2283
2285{
2286 return JsonReadArray(f);
2287}
2288
2289////////////////////////////////////////////////////////////////////////////////
2290/// Read array of Double_t from buffer
2291
2293{
2294 return JsonReadArray(d);
2295}
2296
2297////////////////////////////////////////////////////////////////////////////////
2298/// Read static array from JSON - not used
2299
2300template <typename T>
2302{
2303 Info("ReadArray", "Not implemented");
2304 return value ? 1 : 0;
2305}
2306
2307////////////////////////////////////////////////////////////////////////////////
2308/// Read array of Bool_t from buffer
2309
2311{
2312 return JsonReadArray(b);
2313}
2314
2315////////////////////////////////////////////////////////////////////////////////
2316/// Read array of Char_t from buffer
2317
2319{
2320 return JsonReadArray(c);
2321}
2322
2323////////////////////////////////////////////////////////////////////////////////
2324/// Read array of UChar_t from buffer
2325
2327{
2328 return JsonReadArray(c);
2329}
2330
2331////////////////////////////////////////////////////////////////////////////////
2332/// Read array of Short_t from buffer
2333
2335{
2336 return JsonReadArray(h);
2337}
2338
2339////////////////////////////////////////////////////////////////////////////////
2340/// Read array of UShort_t from buffer
2341
2343{
2344 return JsonReadArray(h);
2345}
2346
2347////////////////////////////////////////////////////////////////////////////////
2348/// Read array of Int_t from buffer
2349
2351{
2352 return JsonReadArray(i);
2353}
2354
2355////////////////////////////////////////////////////////////////////////////////
2356/// Read array of UInt_t from buffer
2357
2359{
2360 return JsonReadArray(i);
2361}
2362
2363////////////////////////////////////////////////////////////////////////////////
2364/// Read array of Long_t from buffer
2365
2367{
2368 return JsonReadArray(l);
2369}
2370
2371////////////////////////////////////////////////////////////////////////////////
2372/// Read array of ULong_t from buffer
2373
2375{
2376 return JsonReadArray(l);
2377}
2378
2379////////////////////////////////////////////////////////////////////////////////
2380/// Read array of Long64_t from buffer
2381
2383{
2384 return JsonReadArray(l);
2385}
2386
2387////////////////////////////////////////////////////////////////////////////////
2388/// Read array of ULong64_t from buffer
2389
2391{
2392 return JsonReadArray(l);
2393}
2394
2395////////////////////////////////////////////////////////////////////////////////
2396/// Read array of Float_t from buffer
2397
2399{
2400 return JsonReadArray(f);
2401}
2402
2403////////////////////////////////////////////////////////////////////////////////
2404/// Read array of Double_t from buffer
2405
2407{
2408 return JsonReadArray(d);
2409}
2410
2411////////////////////////////////////////////////////////////////////////////////
2412/// Template method to read array from the JSON
2413
2414template <typename T>
2415R__ALWAYS_INLINE void TBufferJSON::JsonReadFastArray(T *arr, Int_t arrsize, bool asstring)
2416{
2417 if (!arr || (arrsize <= 0))
2418 return;
2419 nlohmann::json *json = Stack()->fNode;
2420 if (gDebug > 2)
2421 Info("ReadFastArray", "Reading array sz %d from JSON %s", arrsize, json->dump().substr(0, 30).c_str());
2422 TArrayIndexProducer *indexes = Stack()->MakeReadIndexes();
2423 if (indexes) { /* at least two dims */
2424 TArrayI &indx = indexes->GetIndices();
2425 Int_t lastdim = indx.GetSize() - 1;
2426 if (indexes->TotalLength() != arrsize)
2427 Error("ReadFastArray", "Mismatch %d-dim array sizes %d %d", lastdim + 1, arrsize, (int)indexes->TotalLength());
2428 for (int cnt = 0; cnt < arrsize; ++cnt) {
2429 nlohmann::json *elem = &(json->at(indx[0]));
2430 for (int k = 1; k < lastdim; ++k)
2431 elem = &((*elem)[indx[k]]);
2432 arr[cnt] = asstring ? elem->get<std::string>()[indx[lastdim]] : (*elem)[indx[lastdim]].get<T>();
2433 indexes->NextSeparator();
2434 }
2435 delete indexes;
2436 } else if (asstring) {
2437 std::string str = json->get<std::string>();
2438 for (int cnt = 0; cnt < arrsize; ++cnt)
2439 arr[cnt] = (cnt < (int)str.length()) ? str[cnt] : 0;
2440 } else if (json->is_object() && (json->count("$arr") == 1)) {
2441 if (json->at("len").get<int>() != arrsize)
2442 Error("ReadFastArray", "Mismatch compressed array size %d %d", arrsize, json->at("len").get<int>());
2443 for (int cnt = 0; cnt < arrsize; ++cnt)
2444 arr[cnt] = 0;
2445 int p = 0, id = 0;
2446 std::string idname = "", pname, vname, nname;
2447 while (p < arrsize) {
2448 pname = std::string("p") + idname;
2449 if (json->count(pname) == 1)
2450 p = json->at(pname).get<int>();
2451 vname = std::string("v") + idname;
2452 if (json->count(vname) != 1)
2453 break;
2454 nlohmann::json &v = json->at(vname);
2455 if (v.is_array()) {
2456 for (unsigned sub = 0; sub < v.size(); ++sub)
2457 arr[p++] = v[sub].get<T>();
2458 } else {
2459 nname = std::string("n") + idname;
2460 unsigned ncopy = (json->count(nname) == 1) ? json->at(nname).get<unsigned>() : 1;
2461 for (unsigned sub = 0; sub < ncopy; ++sub)
2462 arr[p++] = v.get<T>();
2463 }
2464 idname = std::to_string(++id);
2465 }
2466 } else {
2467 if ((int)json->size() != arrsize)
2468 Error("ReadFastArray", "Mismatch array sizes %d %d", arrsize, (int)json->size());
2469 for (int cnt = 0; cnt < arrsize; ++cnt)
2470 arr[cnt] = json->at(cnt).get<T>();
2471 }
2472}
2473
2474////////////////////////////////////////////////////////////////////////////////
2475/// read array of Bool_t from buffer
2476
2478{
2480}
2481
2482////////////////////////////////////////////////////////////////////////////////
2483/// read array of Char_t from buffer
2484
2486{
2487 JsonReadFastArray(c, n, true);
2488}
2489
2490////////////////////////////////////////////////////////////////////////////////
2491/// read array of Char_t from buffer
2492
2494{
2495 JsonReadFastArray(c, n, true);
2496}
2497
2498////////////////////////////////////////////////////////////////////////////////
2499/// read array of UChar_t from buffer
2500
2502{
2504}
2505
2506////////////////////////////////////////////////////////////////////////////////
2507/// read array of Short_t from buffer
2508
2510{
2512}
2513
2514////////////////////////////////////////////////////////////////////////////////
2515/// read array of UShort_t from buffer
2516
2518{
2520}
2521
2522////////////////////////////////////////////////////////////////////////////////
2523/// read array of Int_t from buffer
2524
2526{
2527 JsonReadFastArray(i, n);
2528}
2529
2530////////////////////////////////////////////////////////////////////////////////
2531/// read array of UInt_t from buffer
2532
2534{
2535 JsonReadFastArray(i, n);
2536}
2537
2538////////////////////////////////////////////////////////////////////////////////
2539/// read array of Long_t from buffer
2540
2542{
2544}
2545
2546////////////////////////////////////////////////////////////////////////////////
2547/// read array of ULong_t from buffer
2548
2550{
2552}
2553
2554////////////////////////////////////////////////////////////////////////////////
2555/// read array of Long64_t from buffer
2556
2558{
2560}
2561
2562////////////////////////////////////////////////////////////////////////////////
2563/// read array of ULong64_t from buffer
2564
2566{
2568}
2569
2570////////////////////////////////////////////////////////////////////////////////
2571/// read array of Float_t from buffer
2572
2574{
2576}
2577
2578////////////////////////////////////////////////////////////////////////////////
2579/// read array of Double_t from buffer
2580
2582{
2584}
2585
2586////////////////////////////////////////////////////////////////////////////////
2587/// Read an array of 'n' objects from the I/O buffer.
2588/// Stores the objects read starting at the address 'start'.
2589/// The objects in the array are assume to be of class 'cl'.
2590/// Copied code from TBufferFile
2591
2592void TBufferJSON::ReadFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer * /* streamer */,
2593 const TClass * /* onFileClass */)
2594{
2595 if (gDebug > 1)
2596 Info("ReadFastArray", "void* n:%d cl:%s", n, cl->GetName());
2597
2598 // if (streamer) {
2599 // Info("ReadFastArray", "(void*) Calling streamer - not handled correctly");
2600 // streamer->SetOnFileClass(onFileClass);
2601 // (*streamer)(*this, start, 0);
2602 // return;
2603 // }
2604
2605 int objectSize = cl->Size();
2606 char *obj = (char *)start;
2607
2608 TJSONStackObj *stack = Stack();
2609 nlohmann::json *topnode = stack->fNode, *subnode = topnode;
2610 if (stack->fIndx)
2611 subnode = stack->fIndx->ExtractNode(topnode);
2612
2613 TArrayIndexProducer indexes(stack->fElem, n, "");
2614
2615 if (gDebug > 1)
2616 Info("ReadFastArray", "Indexes ndim:%d totallen:%d", indexes.NumDimensions(), indexes.TotalLength());
2617
2618 for (Int_t j = 0; j < n; j++, obj += objectSize) {
2619
2620 stack->fNode = indexes.ExtractNode(subnode);
2621
2622 JsonReadObject(obj, cl);
2623 }
2624
2625 // restore top node - show we use stack here?
2626 stack->fNode = topnode;
2627}
2628
2629////////////////////////////////////////////////////////////////////////////////
2630/// redefined here to avoid warning message from gcc
2631
2632void TBufferJSON::ReadFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc,
2633 TMemberStreamer * /* streamer */, const TClass * /* onFileClass */)
2634{
2635 if (gDebug > 1)
2636 Info("ReadFastArray", "void** n:%d cl:%s prealloc:%s", n, cl->GetName(), (isPreAlloc ? "true" : "false"));
2637
2638 // if (streamer) {
2639 // Info("ReadFastArray", "(void**) Calling streamer - not handled correctly");
2640 // if (isPreAlloc) {
2641 // for (Int_t j = 0; j < n; j++) {
2642 // if (!start[j])
2643 // start[j] = cl->New();
2644 // }
2645 // }
2646 // streamer->SetOnFileClass(onFileClass);
2647 // (*streamer)(*this, (void *)start, 0);
2648 // return;
2649 // }
2650
2651 TJSONStackObj *stack = Stack();
2652 nlohmann::json *topnode = stack->fNode, *subnode = topnode;
2653 if (stack->fIndx)
2654 subnode = stack->fIndx->ExtractNode(topnode);
2655
2656 TArrayIndexProducer indexes(stack->fElem, n, "");
2657
2658 for (Int_t j = 0; j < n; j++) {
2659
2660 stack->fNode = indexes.ExtractNode(subnode);
2661
2662 if (!isPreAlloc) {
2663 void *old = start[j];
2664 start[j] = JsonReadObject(nullptr, cl);
2665 if (old && old != start[j] && TStreamerInfo::CanDelete())
2666 ((TClass *)cl)->Destructor(old, kFALSE); // call delete and destruct
2667 } else {
2668 if (!start[j])
2669 start[j] = ((TClass *)cl)->New();
2670 JsonReadObject(start[j], cl);
2671 }
2672 }
2673
2674 stack->fNode = topnode;
2675}
2676
2677template <typename T>
2678R__ALWAYS_INLINE void TBufferJSON::JsonWriteArrayCompress(const T *vname, Int_t arrsize, const char *typname)
2679{
2680 if ((fCompact < 10) || (arrsize < 6)) {
2681 fValue.Append("[");
2682 for (Int_t indx = 0; indx < arrsize; indx++) {
2683 if (indx > 0)
2685 JsonWriteBasic(vname[indx]);
2686 }
2687 fValue.Append("]");
2688 } else {
2689 fValue.Append("{");
2690 fValue.Append(TString::Format("\"$arr\":\"%s\"%s\"len\":%d", typname, fArraySepar.Data(), arrsize));
2691 Int_t aindx(0), bindx(arrsize);
2692 while ((aindx < arrsize) && (vname[aindx] == 0))
2693 aindx++;
2694 while ((aindx < bindx) && (vname[bindx - 1] == 0))
2695 bindx--;
2696 if (aindx < bindx) {
2697 TString suffix("");
2698 Int_t p(aindx), suffixcnt(-1), lastp(0);
2699 while (p < bindx) {
2700 if (vname[p] == 0) {
2701 p++;
2702 continue;
2703 }
2704 Int_t p0(p++), pp(0), nsame(1);
2705 if (fCompact < 20) {
2706 pp = bindx;
2707 p = bindx + 1;
2708 nsame = 0;
2709 }
2710 for (; p <= bindx; ++p) {
2711 if ((p < bindx) && (vname[p] == vname[p - 1])) {
2712 nsame++;
2713 continue;
2714 }
2715 if (vname[p - 1] == 0) {
2716 if (nsame > 9) {
2717 nsame = 0;
2718 break;
2719 }
2720 } else if (nsame > 5) {
2721 if (pp) {
2722 p = pp;
2723 nsame = 0;
2724 } else
2725 pp = p;
2726 break;
2727 }
2728 pp = p;
2729 nsame = 1;
2730 }
2731 if (pp <= p0)
2732 continue;
2733 if (++suffixcnt > 0)
2734 suffix.Form("%d", suffixcnt);
2735 if (p0 != lastp)
2736 fValue.Append(TString::Format("%s\"p%s\":%d", fArraySepar.Data(), suffix.Data(), p0));
2737 lastp = pp; /* remember cursor, it may be the same */
2738 fValue.Append(TString::Format("%s\"v%s\":", fArraySepar.Data(), suffix.Data()));
2739 if ((nsame > 1) || (pp - p0 == 1)) {
2740 JsonWriteBasic(vname[p0]);
2741 if (nsame > 1)
2742 fValue.Append(TString::Format("%s\"n%s\":%d", fArraySepar.Data(), suffix.Data(), nsame));
2743 } else {
2744 fValue.Append("[");
2745 for (Int_t indx = p0; indx < pp; indx++) {
2746 if (indx > p0)
2748 JsonWriteBasic(vname[indx]);
2749 }
2750 fValue.Append("]");
2751 }
2752 }
2753 }
2754 fValue.Append("}");
2755 }
2756}
2757
2758////////////////////////////////////////////////////////////////////////////////
2759/// Write array of Bool_t to buffer
2760
2762{
2763 JsonPushValue();
2764 JsonWriteArrayCompress(b, n, "Bool");
2765}
2766
2767////////////////////////////////////////////////////////////////////////////////
2768/// Write array of Char_t to buffer
2769
2771{
2772 JsonPushValue();
2773 JsonWriteArrayCompress(c, n, "Int8");
2774}
2775
2776////////////////////////////////////////////////////////////////////////////////
2777/// Write array of UChar_t to buffer
2778
2780{
2781 JsonPushValue();
2782 JsonWriteArrayCompress(c, n, "Uint8");
2783}
2784
2785////////////////////////////////////////////////////////////////////////////////
2786/// Write array of Short_t to buffer
2787
2789{
2790 JsonPushValue();
2791 JsonWriteArrayCompress(h, n, "Int16");
2792}
2793
2794////////////////////////////////////////////////////////////////////////////////
2795/// Write array of UShort_t to buffer
2796
2798{
2799 JsonPushValue();
2800 JsonWriteArrayCompress(h, n, "Uint16");
2801}
2802
2803////////////////////////////////////////////////////////////////////////////////
2804/// Write array of Int_ to buffer
2805
2807{
2808 JsonPushValue();
2809 JsonWriteArrayCompress(i, n, "Int32");
2810}
2811
2812////////////////////////////////////////////////////////////////////////////////
2813/// Write array of UInt_t to buffer
2814
2816{
2817 JsonPushValue();
2818 JsonWriteArrayCompress(i, n, "Uint32");
2819}
2820
2821////////////////////////////////////////////////////////////////////////////////
2822/// Write array of Long_t to buffer
2823
2825{
2826 JsonPushValue();
2827 JsonWriteArrayCompress(l, n, "Int64");
2828}
2829
2830////////////////////////////////////////////////////////////////////////////////
2831/// Write array of ULong_t to buffer
2832
2834{
2835 JsonPushValue();
2836 JsonWriteArrayCompress(l, n, "Uint64");
2837}
2838
2839////////////////////////////////////////////////////////////////////////////////
2840/// Write array of Long64_t to buffer
2841
2843{
2844 JsonPushValue();
2845 JsonWriteArrayCompress(l, n, "Int64");
2846}
2847
2848////////////////////////////////////////////////////////////////////////////////
2849/// Write array of ULong64_t to buffer
2850
2852{
2853 JsonPushValue();
2854 JsonWriteArrayCompress(l, n, "Uint64");
2855}
2856
2857////////////////////////////////////////////////////////////////////////////////
2858/// Write array of Float_t to buffer
2859
2861{
2862 JsonPushValue();
2863 JsonWriteArrayCompress(f, n, "Float32");
2864}
2865
2866////////////////////////////////////////////////////////////////////////////////
2867/// Write array of Double_t to buffer
2868
2870{
2871 JsonPushValue();
2872 JsonWriteArrayCompress(d, n, "Float64");
2873}
2874
2875////////////////////////////////////////////////////////////////////////////////
2876/// Template method to write array of arbitrary dimensions
2877/// Different methods can be used for store last array dimension -
2878/// either JsonWriteArrayCompress<T>() or JsonWriteConstChar()
2879
2880template <typename T>
2881R__ALWAYS_INLINE void TBufferJSON::JsonWriteFastArray(const T *arr, Int_t arrsize, const char *typname,
2882 void (TBufferJSON::*method)(const T *, Int_t, const char *))
2883{
2884 JsonPushValue();
2885 if (arrsize <= 0) { /*fJsonrCnt++;*/
2886 fValue.Append("[]");
2887 return;
2888 }
2889
2890 TStreamerElement *elem = Stack()->fElem;
2891 if (elem && (elem->GetArrayDim() > 1) && (elem->GetArrayLength() == arrsize)) {
2892 TArrayI indexes(elem->GetArrayDim() - 1);
2893 indexes.Reset(0);
2894 Int_t cnt = 0, shift = 0, len = elem->GetMaxIndex(indexes.GetSize());
2895 while (cnt >= 0) {
2896 if (indexes[cnt] >= elem->GetMaxIndex(cnt)) {
2897 fValue.Append("]");
2898 indexes[cnt--] = 0;
2899 if (cnt >= 0)
2900 indexes[cnt]++;
2901 continue;
2902 }
2903 fValue.Append(indexes[cnt] == 0 ? "[" : fArraySepar.Data());
2904 if (++cnt == indexes.GetSize()) {
2905 (*this.*method)((arr + shift), len, typname);
2906 indexes[--cnt]++;
2907 shift += len;
2908 }
2909 }
2910 } else {
2911 (*this.*method)(arr, arrsize, typname);
2912 }
2913}
2914
2915////////////////////////////////////////////////////////////////////////////////
2916/// Write array of Bool_t to buffer
2917
2919{
2920 JsonWriteFastArray(b, n, "Bool", &TBufferJSON::JsonWriteArrayCompress<Bool_t>);
2921}
2922
2923////////////////////////////////////////////////////////////////////////////////
2924/// Write array of Char_t to buffer
2925
2927{
2929}
2930
2931////////////////////////////////////////////////////////////////////////////////
2932/// Write array of Char_t to buffer
2933
2935{
2937}
2938
2939////////////////////////////////////////////////////////////////////////////////
2940/// Write array of UChar_t to buffer
2941
2943{
2944 JsonWriteFastArray(c, n, "Uint8", &TBufferJSON::JsonWriteArrayCompress<UChar_t>);
2945}
2946
2947////////////////////////////////////////////////////////////////////////////////
2948/// Write array of Short_t to buffer
2949
2951{
2952 JsonWriteFastArray(h, n, "Int16", &TBufferJSON::JsonWriteArrayCompress<Short_t>);
2953}
2954
2955////////////////////////////////////////////////////////////////////////////////
2956/// Write array of UShort_t to buffer
2957
2959{
2960 JsonWriteFastArray(h, n, "Uint16", &TBufferJSON::JsonWriteArrayCompress<UShort_t>);
2961}
2962
2963////////////////////////////////////////////////////////////////////////////////
2964/// Write array of Int_t to buffer
2965
2967{
2968 JsonWriteFastArray(i, n, "Int32", &TBufferJSON::JsonWriteArrayCompress<Int_t>);
2969}
2970
2971////////////////////////////////////////////////////////////////////////////////
2972/// Write array of UInt_t to buffer
2973
2975{
2976 JsonWriteFastArray(i, n, "Uint32", &TBufferJSON::JsonWriteArrayCompress<UInt_t>);
2977}
2978
2979////////////////////////////////////////////////////////////////////////////////
2980/// Write array of Long_t to buffer
2981
2983{
2984 JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long_t>);
2985}
2986
2987////////////////////////////////////////////////////////////////////////////////
2988/// Write array of ULong_t to buffer
2989
2991{
2992 JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong_t>);
2993}
2994
2995////////////////////////////////////////////////////////////////////////////////
2996/// Write array of Long64_t to buffer
2997
2999{
3000 JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long64_t>);
3001}
3002
3003////////////////////////////////////////////////////////////////////////////////
3004/// Write array of ULong64_t to buffer
3005
3007{
3008 JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong64_t>);
3009}
3010
3011////////////////////////////////////////////////////////////////////////////////
3012/// Write array of Float_t to buffer
3013
3015{
3016 JsonWriteFastArray(f, n, "Float32", &TBufferJSON::JsonWriteArrayCompress<Float_t>);
3017}
3018
3019////////////////////////////////////////////////////////////////////////////////
3020/// Write array of Double_t to buffer
3021
3023{
3024 JsonWriteFastArray(d, n, "Float64", &TBufferJSON::JsonWriteArrayCompress<Double_t>);
3025}
3026
3027////////////////////////////////////////////////////////////////////////////////
3028/// Recall TBuffer function to avoid gcc warning message
3029
3030void TBufferJSON::WriteFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer * /* streamer */)
3031{
3032 if (gDebug > 2)
3033 Info("WriteFastArray", "void *start cl:%s n:%d", cl ? cl->GetName() : "---", n);
3034
3035 // if (streamer) {
3036 // JsonDisablePostprocessing();
3037 // (*streamer)(*this, start, 0);
3038 // return;
3039 // }
3040
3041 if (n < 0) {
3042 // special handling of empty StreamLoop
3043 AppendOutput("null");
3045 } else {
3046
3047 char *obj = (char *)start;
3048 if (!n)
3049 n = 1;
3050 int size = cl->Size();
3051
3052 TArrayIndexProducer indexes(Stack()->fElem, n, fArraySepar.Data());
3053
3054 if (indexes.IsArray()) {
3056 AppendOutput(indexes.GetBegin());
3057 }
3058
3059 for (Int_t j = 0; j < n; j++, obj += size) {
3060
3061 if (j > 0)
3062 AppendOutput(indexes.NextSeparator());
3063
3064 JsonWriteObject(obj, cl, kFALSE);
3065
3066 if (indexes.IsArray() && (fValue.Length() > 0)) {
3068 fValue.Clear();
3069 }
3070 }
3071
3072 if (indexes.IsArray())
3073 AppendOutput(indexes.GetEnd());
3074 }
3075
3076 if (Stack()->fIndx)
3077 AppendOutput(Stack()->fIndx->NextSeparator());
3078}
3079
3080////////////////////////////////////////////////////////////////////////////////
3081/// Recall TBuffer function to avoid gcc warning message
3082
3083Int_t TBufferJSON::WriteFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc,
3084 TMemberStreamer * /* streamer */)
3085{
3086 if (gDebug > 2)
3087 Info("WriteFastArray", "void **startp cl:%s n:%d", cl->GetName(), n);
3088
3089 // if (streamer) {
3090 // JsonDisablePostprocessing();
3091 // (*streamer)(*this, (void *)start, 0);
3092 // return 0;
3093 // }
3094
3095 if (n <= 0)
3096 return 0;
3097
3098 Int_t res = 0;
3099
3100 TArrayIndexProducer indexes(Stack()->fElem, n, fArraySepar.Data());
3101
3102 if (indexes.IsArray()) {
3104 AppendOutput(indexes.GetBegin());
3105 }
3106
3107 for (Int_t j = 0; j < n; j++) {
3108
3109 if (j > 0)
3110 AppendOutput(indexes.NextSeparator());
3111
3112 if (!isPreAlloc) {
3113 res |= WriteObjectAny(start[j], cl);
3114 } else {
3115 if (!start[j])
3116 start[j] = ((TClass *)cl)->New();
3117 // ((TClass*)cl)->Streamer(start[j],*this);
3118 JsonWriteObject(start[j], cl, kFALSE);
3119 }
3120
3121 if (indexes.IsArray() && (fValue.Length() > 0)) {
3123 fValue.Clear();
3124 }
3125 }
3126
3127 if (indexes.IsArray())
3128 AppendOutput(indexes.GetEnd());
3129
3130 if (Stack()->fIndx)
3131 AppendOutput(Stack()->fIndx->NextSeparator());
3132
3133 return res;
3134}
3135
3136////////////////////////////////////////////////////////////////////////////////
3137/// stream object to/from buffer
3138
3139void TBufferJSON::StreamObject(void *obj, const TClass *cl, const TClass * /* onfileClass */)
3140{
3141 if (gDebug > 3)
3142 Info("StreamObject", "Class: %s", (cl ? cl->GetName() : "none"));
3143
3144 if (IsWriting())
3145 JsonWriteObject(obj, cl);
3146 else
3147 JsonReadObject(obj, cl);
3148}
3149
3150////////////////////////////////////////////////////////////////////////////////
3151/// Template function to read basic value from JSON
3152
3153template <typename T>
3155{
3156 value = Stack()->GetStlNode()->get<T>();
3157}
3158
3159////////////////////////////////////////////////////////////////////////////////
3160/// Reads Bool_t value from buffer
3161
3163{
3164 JsonReadBasic(val);
3165}
3166
3167////////////////////////////////////////////////////////////////////////////////
3168/// Reads Char_t value from buffer
3169
3171{
3172 if (Stack()->fValues.GetLast() >= 0)
3173 val = (Char_t)Stack()->PopIntValue();
3174 else
3175 val = Stack()->GetStlNode()->get<Char_t>();
3176}
3177
3178////////////////////////////////////////////////////////////////////////////////
3179/// Reads UChar_t value from buffer
3180
3182{
3183 JsonReadBasic(val);
3184}
3185
3186////////////////////////////////////////////////////////////////////////////////
3187/// Reads Short_t value from buffer
3188
3190{
3191 JsonReadBasic(val);
3192}
3193
3194////////////////////////////////////////////////////////////////////////////////
3195/// Reads UShort_t value from buffer
3196
3198{
3199 JsonReadBasic(val);
3200}
3201
3202////////////////////////////////////////////////////////////////////////////////
3203/// Reads Int_t value from buffer
3204
3206{
3207 if (Stack()->fValues.GetLast() >= 0)
3208 val = Stack()->PopIntValue();
3209 else
3210 JsonReadBasic(val);
3211}
3212
3213////////////////////////////////////////////////////////////////////////////////
3214/// Reads UInt_t value from buffer
3215
3217{
3218 JsonReadBasic(val);
3219}
3220
3221////////////////////////////////////////////////////////////////////////////////
3222/// Reads Long_t value from buffer
3223
3225{
3226 JsonReadBasic(val);
3227}
3228
3229////////////////////////////////////////////////////////////////////////////////
3230/// Reads ULong_t value from buffer
3231
3233{
3234 JsonReadBasic(val);
3235}
3236
3237////////////////////////////////////////////////////////////////////////////////
3238/// Reads Long64_t value from buffer
3239
3241{
3242 JsonReadBasic(val);
3243}
3244
3245////////////////////////////////////////////////////////////////////////////////
3246/// Reads ULong64_t value from buffer
3247
3249{
3250 JsonReadBasic(val);
3251}
3252
3253////////////////////////////////////////////////////////////////////////////////
3254/// Reads Float_t value from buffer
3255
3257{
3258 nlohmann::json *json = Stack()->GetStlNode();
3259 if (json->is_null())
3260 val = std::numeric_limits<Float_t>::quiet_NaN();
3261 else
3262 val = json->get<Float_t>();
3263}
3264
3265////////////////////////////////////////////////////////////////////////////////
3266/// Reads Double_t value from buffer
3267
3269{
3270 nlohmann::json *json = Stack()->GetStlNode();
3271 if (json->is_null())
3272 val = std::numeric_limits<Double_t>::quiet_NaN();
3273 else
3274 val = json->get<Double_t>();
3275}
3276
3277////////////////////////////////////////////////////////////////////////////////
3278/// Reads array of characters from buffer
3279
3281{
3282 Error("ReadCharP", "Not implemented");
3283}
3284
3285////////////////////////////////////////////////////////////////////////////////
3286/// Reads a TString
3287
3289{
3290 std::string str;
3291 JsonReadBasic(str);
3292 val = str.c_str();
3293}
3294
3295////////////////////////////////////////////////////////////////////////////////
3296/// Reads a std::string
3297
3298void TBufferJSON::ReadStdString(std::string *val)
3299{
3300 JsonReadBasic(*val);
3301}
3302
3303////////////////////////////////////////////////////////////////////////////////
3304/// Reads a char* string
3305
3307{
3308 std::string str;
3309 JsonReadBasic(str);
3310
3311 if (s) {
3312 delete[] s;
3313 s = nullptr;
3314 }
3315
3316 std::size_t nch = str.length();
3317 if (nch > 0) {
3318 s = new char[nch + 1];
3319 memcpy(s, str.c_str(), nch);
3320 s[nch] = 0;
3321 }
3322}
3323
3324////////////////////////////////////////////////////////////////////////////////
3325/// Writes Bool_t value to buffer
3326
3328{
3329 JsonPushValue();
3331}
3332
3333////////////////////////////////////////////////////////////////////////////////
3334/// Writes Char_t value to buffer
3335
3337{
3338 JsonPushValue();
3340}
3341
3342////////////////////////////////////////////////////////////////////////////////
3343/// Writes UChar_t value to buffer
3344
3346{
3347 JsonPushValue();
3349}
3350
3351////////////////////////////////////////////////////////////////////////////////
3352/// Writes Short_t value to buffer
3353
3355{
3356 JsonPushValue();
3358}
3359
3360////////////////////////////////////////////////////////////////////////////////
3361/// Writes UShort_t value to buffer
3362
3364{
3365 JsonPushValue();
3367}
3368
3369////////////////////////////////////////////////////////////////////////////////
3370/// Writes Int_t value to buffer
3371
3373{
3374 JsonPushValue();
3375 JsonWriteBasic(i);
3376}
3377
3378////////////////////////////////////////////////////////////////////////////////
3379/// Writes UInt_t value to buffer
3380
3382{
3383 JsonPushValue();
3384 JsonWriteBasic(i);
3385}
3386
3387////////////////////////////////////////////////////////////////////////////////
3388/// Writes Long_t value to buffer
3389
3391{
3392 JsonPushValue();
3394}
3395
3396////////////////////////////////////////////////////////////////////////////////
3397/// Writes ULong_t value to buffer
3398
3400{
3401 JsonPushValue();
3403}
3404
3405////////////////////////////////////////////////////////////////////////////////
3406/// Writes Long64_t value to buffer
3407
3409{
3410 JsonPushValue();
3412}
3413
3414////////////////////////////////////////////////////////////////////////////////
3415/// Writes ULong64_t value to buffer
3416
3418{
3419 JsonPushValue();
3421}
3422
3423////////////////////////////////////////////////////////////////////////////////
3424/// Writes Float_t value to buffer
3425
3427{
3428 JsonPushValue();
3430}
3431
3432////////////////////////////////////////////////////////////////////////////////
3433/// Writes Double_t value to buffer
3434
3436{
3437 JsonPushValue();
3439}
3440
3441////////////////////////////////////////////////////////////////////////////////
3442/// Writes array of characters to buffer
3443
3445{
3446 JsonPushValue();
3447
3449}
3450
3451////////////////////////////////////////////////////////////////////////////////
3452/// Writes a TString
3453
3455{
3456 JsonPushValue();
3457
3458 JsonWriteConstChar(s.Data(), s.Length());
3459}
3460
3461////////////////////////////////////////////////////////////////////////////////
3462/// Writes a std::string
3463
3464void TBufferJSON::WriteStdString(const std::string *s)
3465{
3466 JsonPushValue();
3467
3468 if (s)
3469 JsonWriteConstChar(s->c_str(), s->length());
3470 else
3471 JsonWriteConstChar("", 0);
3472}
3473
3474////////////////////////////////////////////////////////////////////////////////
3475/// Writes a char*
3476
3478{
3479 JsonPushValue();
3480
3482}
3483
3484////////////////////////////////////////////////////////////////////////////////
3485/// converts Char_t to string and add to json value buffer
3486
3488{
3489 char buf[50];
3490 snprintf(buf, sizeof(buf), "%d", value);
3491 fValue.Append(buf);
3492}
3493
3494////////////////////////////////////////////////////////////////////////////////
3495/// converts Short_t to string and add to json value buffer
3496
3498{
3499 char buf[50];
3500 snprintf(buf, sizeof(buf), "%hd", value);
3501 fValue.Append(buf);
3502}
3503
3504////////////////////////////////////////////////////////////////////////////////
3505/// converts Int_t to string and add to json value buffer
3506
3508{
3509 char buf[50];
3510 snprintf(buf, sizeof(buf), "%d", value);
3511 fValue.Append(buf);
3512}
3513
3514////////////////////////////////////////////////////////////////////////////////
3515/// converts Long_t to string and add to json value buffer
3516
3518{
3519 char buf[50];
3520 snprintf(buf, sizeof(buf), "%ld", value);
3521 fValue.Append(buf);
3522}
3523
3524////////////////////////////////////////////////////////////////////////////////
3525/// converts Long64_t to string and add to json value buffer
3526
3528{
3529 fValue.Append(std::to_string(value).c_str());
3530}
3531
3532////////////////////////////////////////////////////////////////////////////////
3533/// converts Float_t to string and add to json value buffer
3534
3536{
3537 if (std::isinf(value)) {
3538 fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3539 } else if (std::isnan(value)) {
3540 fValue.Append("null");
3541 } else {
3542 char buf[200];
3543 ConvertFloat(value, buf, sizeof(buf));
3544 fValue.Append(buf);
3545 }
3546}
3547
3548////////////////////////////////////////////////////////////////////////////////
3549/// converts Double_t to string and add to json value buffer
3550
3552{
3553 if (std::isinf(value)) {
3554 fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3555 } else if (std::isnan(value)) {
3556 fValue.Append("null");
3557 } else {
3558 char buf[200];
3559 ConvertDouble(value, buf, sizeof(buf));
3560 fValue.Append(buf);
3561 }
3562}
3563
3564////////////////////////////////////////////////////////////////////////////////
3565/// converts Bool_t to string and add to json value buffer
3566
3568{
3569 fValue.Append(value ? "true" : "false");
3570}
3571
3572////////////////////////////////////////////////////////////////////////////////
3573/// converts UChar_t to string and add to json value buffer
3574
3576{
3577 char buf[50];
3578 snprintf(buf, sizeof(buf), "%u", value);
3579 fValue.Append(buf);
3580}
3581
3582////////////////////////////////////////////////////////////////////////////////
3583/// converts UShort_t to string and add to json value buffer
3584
3586{
3587 char buf[50];
3588 snprintf(buf, sizeof(buf), "%hu", value);
3589 fValue.Append(buf);
3590}
3591
3592////////////////////////////////////////////////////////////////////////////////
3593/// converts UInt_t to string and add to json value buffer
3594
3596{
3597 char buf[50];
3598 snprintf(buf, sizeof(buf), "%u", value);
3599 fValue.Append(buf);
3600}
3601
3602////////////////////////////////////////////////////////////////////////////////
3603/// converts ULong_t to string and add to json value buffer
3604
3606{
3607 char buf[50];
3608 snprintf(buf, sizeof(buf), "%lu", value);
3609 fValue.Append(buf);
3610}
3611
3612////////////////////////////////////////////////////////////////////////////////
3613/// converts ULong64_t to string and add to json value buffer
3614
3616{
3617 fValue.Append(std::to_string(value).c_str());
3618}
3619
3620////////////////////////////////////////////////////////////////////////////////
3621/// writes string value, processing all kind of special characters
3622
3623void TBufferJSON::JsonWriteConstChar(const char *value, Int_t len, const char * /* typname */)
3624{
3625 if (!value) {
3626
3627 fValue.Append("\"\"");
3628
3629 } else {
3630
3631 fValue.Append("\"");
3632
3633 if (len < 0)
3634 len = strlen(value);
3635
3636 for (Int_t n = 0; n < len; n++) {
3637 char c = value[n];
3638 if (c == 0)
3639 break;
3640 switch (c) {
3641 case '\n': fValue.Append("\\n"); break;
3642 case '\t': fValue.Append("\\t"); break;
3643 case '\"': fValue.Append("\\\""); break;
3644 case '\\': fValue.Append("\\\\"); break;
3645 case '\b': fValue.Append("\\b"); break;
3646 case '\f': fValue.Append("\\f"); break;
3647 case '\r': fValue.Append("\\r"); break;
3648 case '/': fValue.Append("\\/"); break;
3649 default:
3650 if ((c > 31) && (c < 127))
3651 fValue.Append(c);
3652 else
3653 fValue.Append(TString::Format("\\u%04x", (unsigned)c));
3654 }
3655 }
3656
3657 fValue.Append("\"");
3658 }
3659}
3660
3661////////////////////////////////////////////////////////////////////////////////
3662/// Read data of base class.
3663
3665{
3666 if (elem->GetClassPointer() == TObject::Class()) {
3668 } else {
3669 TBufferText::ReadBaseClass(start, elem);
3670 }
3671}
void Class()
Definition: Class.C:29
SVector< double, 2 > v
Definition: Dict.h:5
PyObject * fValue
#define R__ALWAYS_INLINE
Definition: RConfig.hxx:556
#define d(i)
Definition: RSha256.hxx:102
#define b(i)
Definition: RSha256.hxx:100
#define f(i)
Definition: RSha256.hxx:104
#define c(i)
Definition: RSha256.hxx:101
#define h(i)
Definition: RSha256.hxx:106
static RooMathCoreReg dummy
unsigned short UShort_t
Definition: RtypesCore.h:36
int Int_t
Definition: RtypesCore.h:41
short Version_t
Definition: RtypesCore.h:61
unsigned char UChar_t
Definition: RtypesCore.h:34
char Char_t
Definition: RtypesCore.h:29
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
unsigned long ULong_t
Definition: RtypesCore.h:51
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
short Short_t
Definition: RtypesCore.h:35
double Double_t
Definition: RtypesCore.h:55
long long Long64_t
Definition: RtypesCore.h:69
unsigned long long ULong64_t
Definition: RtypesCore.h:70
float Float_t
Definition: RtypesCore.h:53
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define BIT(n)
Definition: Rtypes.h:82
#define ClassImp(name)
Definition: Rtypes.h:363
R__EXTERN Int_t gDebug
Definition: Rtypes.h:90
@ json_stdstring
Definition: TBufferJSON.cxx:81
@ json_TCollection
Definition: TBufferJSON.cxx:81
@ json_TString
Definition: TBufferJSON.cxx:81
@ json_TArray
Definition: TBufferJSON.cxx:81
@ kNoType_t
Definition: TDataType.h:33
@ kFloat_t
Definition: TDataType.h:31
@ kULong64_t
Definition: TDataType.h:32
@ kInt_t
Definition: TDataType.h:30
@ kchar
Definition: TDataType.h:31
@ kLong_t
Definition: TDataType.h:30
@ kDouble32_t
Definition: TDataType.h:31
@ kShort_t
Definition: TDataType.h:29
@ kBool_t
Definition: TDataType.h:32
@ kBits
Definition: TDataType.h:34
@ kULong_t
Definition: TDataType.h:30
@ kLong64_t
Definition: TDataType.h:32
@ kVoid_t
Definition: TDataType.h:35
@ kUShort_t
Definition: TDataType.h:29
@ kDouble_t
Definition: TDataType.h:31
@ kCharStar
Definition: TDataType.h:34
@ kChar_t
Definition: TDataType.h:29
@ kUChar_t
Definition: TDataType.h:29
@ kCounter
Definition: TDataType.h:34
@ kUInt_t
Definition: TDataType.h:30
@ kFloat16_t
Definition: TDataType.h:33
@ kOther_t
Definition: TDataType.h:32
void Error(const char *location, const char *msgfmt,...)
char idname[128]
Definition: THbookFile.cxx:88
int isnan(double)
#define gROOT
Definition: TROOT.h:410
char * Form(const char *fmt,...)
#define free
Definition: civetweb.c:1539
#define snprintf
Definition: civetweb.c:1540
#define malloc
Definition: civetweb.c:1536
Array of integers (32 bits per element).
Definition: TArrayI.h:27
void Set(Int_t n)
Set size of this array to n ints.
Definition: TArrayI.cxx:105
void Reset()
Definition: TArrayI.h:47
Abstract array base class.
Definition: TArray.h:31
Int_t GetSize() const
Definition: TArray.h:47
virtual void GetMappedObject(UInt_t tag, void *&ptr, TClass *&ClassPtr) const
Retrieve the object stored in the buffer's object map at 'tag' Set ptr and ClassPtr respectively to t...
Definition: TBufferIO.cxx:260
virtual void MapObject(const TObject *obj, UInt_t offset=1)
Add object to the fMap container.
Definition: TBufferIO.cxx:163
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 Int_t WriteObjectAny(const void *obj, const TClass *ptrClass, Bool_t cacheReuse=kTRUE)
Write object to I/O buffer.
Definition: TBufferIO.cxx:492
virtual void InitMap()
Create the fMap container and initialize them with the null object.
Definition: TBufferIO.cxx:129
Class for serializing object to and from JavaScript Object Notation (JSON) format.
Definition: TBufferJSON.h:27
virtual void WriteLong64(Long64_t l)
Writes Long64_t value to buffer.
R__ALWAYS_INLINE void JsonWriteArrayCompress(const T *vname, Int_t arrsize, const char *typname)
virtual TClass * ReadClass(const TClass *cl=nullptr, UInt_t *objTag=nullptr)
suppressed function of TBuffer
void JsonWriteBasic(Char_t value)
converts Char_t to string and add to json value buffer
void JsonWriteCollection(TCollection *obj, const TClass *objClass)
store content of ROOT collection
virtual void WriteStdString(const std::string *s)
Writes a std::string.
TString fSemicolon
! depending from compression level, " : " or ":"
Definition: TBufferJSON.h:286
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 WriteUShort(UShort_t s)
Writes UShort_t value to buffer.
virtual void WriteUInt(UInt_t i)
Writes UInt_t value to buffer.
virtual Version_t ReadVersion(UInt_t *start=nullptr, UInt_t *bcnt=nullptr, const TClass *cl=nullptr)
read version value from buffer
void JsonStartElement(const TStreamerElement *elem, const TClass *base_class=nullptr)
Start new class member in JSON structures.
static TObject * ConvertFromJSON(const char *str)
Read TObject-based class from JSON, produced by ConvertToJSON() method.
virtual void ReadLong(Long_t &l)
Reads Long_t value from buffer.
TString fValue
! buffer for current value
Definition: TBufferJSON.h:282
std::deque< TJSONStackObj * > fStack
! hierarchy of currently streamed element
Definition: TBufferJSON.h:284
TJSONStackObj * Stack()
Definition: TBufferJSON.h:222
virtual void WriteChar(Char_t c)
Writes Char_t value to buffer.
virtual void ClassBegin(const TClass *, Version_t=-1)
Should be called in the beginning of custom class streamer.
virtual void WriteDouble(Double_t d)
Writes Double_t value to buffer.
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...
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)
Ignored in TBufferJSON.
void PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_cl=nullptr)
Function is converts TObject and TString structures to more compact representation.
virtual void ReadUInt(UInt_t &i)
Reads UInt_t value from buffer.
virtual void WriteInt(Int_t i)
Writes Int_t value to buffer.
virtual void ReadFastArrayString(Char_t *c, Int_t n)
read array of Char_t from buffer
virtual void ReadShort(Short_t &s)
Reads Short_t value from buffer.
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...
R__ALWAYS_INLINE Int_t JsonReadArray(T *value)
Read static array from JSON - not used.
TString fNumericLocale
! stored value of setlocale(LC_NUMERIC), which should be recovered at the end
Definition: TBufferJSON.h:288
virtual Int_t ReadArray(Bool_t *&b)
Read array of Bool_t from buffer.
TJSONStackObj * PushStack(Int_t inclevel=0, void *readnode=nullptr)
add new level to the structures stack
TBufferJSON(TBuffer::EMode mode=TBuffer::kWrite)
Creates buffer object to serialize data into json.
void JsonDisablePostprocessing()
disable post-processing of the code
void WorkWithElement(TStreamerElement *elem, Int_t)
This is call-back from streamer which indicates that class member will be streamed Name of element us...
virtual void ReadDouble(Double_t &d)
Reads Double_t value from buffer.
virtual void ReadLong64(Long64_t &l)
Reads Long64_t value from buffer.
unsigned fJsonrCnt
! counter for all objects, used for referencing
Definition: TBufferJSON.h:283
void JsonReadCollection(TCollection *obj, const TClass *objClass)
read content of ROOT collection
virtual void ReadStdString(std::string *s)
Reads a std::string.
virtual ~TBufferJSON()
destroy buffer
virtual void ReadUChar(UChar_t &c)
Reads UChar_t value from buffer.
void JsonPushValue()
If value exists, push in the current stack for post-processing.
virtual void ReadCharP(Char_t *c)
Reads array of characters from buffer.
virtual void ReadFastArray(Bool_t *b, Int_t n)
read array of Bool_t from buffer
virtual void ReadULong64(ULong64_t &l)
Reads ULong64_t value from buffer.
virtual void ReadInt(Int_t &i)
Reads Int_t value from buffer.
virtual void WriteULong64(ULong64_t l)
Writes ULong64_t value to buffer.
virtual void WriteTString(const TString &s)
Writes a TString.
virtual void WriteUChar(UChar_t c)
Writes UChar_t value to buffer.
virtual void WriteClass(const TClass *cl)
suppressed function of TBuffer
virtual void ReadBool(Bool_t &b)
Reads Bool_t value from buffer.
TString * fOutput
! current output buffer for json code
Definition: TBufferJSON.h:281
virtual void StreamObject(void *obj, const TClass *cl, const TClass *onFileClass=nullptr)
stream object to/from buffer
static void * ConvertFromJSONAny(const char *str, TClass **cl=nullptr)
Read object from JSON, produced by ConvertToJSON() method.
virtual void ReadUShort(UShort_t &s)
Reads UShort_t value from 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 ClassEnd(const TClass *)
Should be called at the end of custom streamer See TBufferJSON::ClassBegin for more details.
virtual void ReadBaseClass(void *start, TStreamerBase *elem)
Read data of base class.
virtual void ReadTString(TString &s)
Reads a TString.
static void * ConvertFromJSONChecked(const char *str, const TClass *expectedClass)
Read objects from JSON, one can reuse existing object.
virtual void WriteCharStar(char *s)
Writes a char*.
virtual void WriteULong(ULong_t l)
Writes ULong_t value to buffer.
virtual void WriteBool(Bool_t b)
Writes Bool_t value to buffer.
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 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 ReadChar(Char_t &c)
Reads Char_t value from buffer.
TString fArraySepar
! depending from compression level, ", " or ","
Definition: TBufferJSON.h:287
R__ALWAYS_INLINE void JsonReadFastArray(T *arr, Int_t arrsize, bool asstring=false)
Template method to read array from the JSON.
virtual void DecrementLevel(TVirtualStreamerInfo *)
Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions and decrease level in json...
virtual void WriteCharP(const Char_t *c)
Writes array of characters to buffer.
virtual void WriteFastArray(const Bool_t *b, Int_t n)
Write array of Bool_t to buffer.
virtual void WriteFastArrayString(const Char_t *c, Int_t n)
Write array of Char_t to buffer.
void AppendOutput(const char *line0, const char *line1=nullptr)
Append two string to the output JSON, normally separate by line break.
TString fOutBuffer
! main output buffer for json code
Definition: TBufferJSON.h:280
TJSONStackObj * PopStack()
remove one level from stack
virtual void WriteArray(const Bool_t *b, Int_t n)
Write array of Bool_t to buffer.
virtual void ReadFloat(Float_t &f)
Reads Float_t value from buffer.
virtual void ReadCharStar(char *&s)
Reads a char* string.
virtual void ReadULong(ULong_t &l)
Reads ULong_t value from buffer.
Int_t JsonSpecialClass(const TClass *cl) const
return non-zero value when class has special handling in JSON it is TCollection (-130),...
virtual Int_t ReadStaticArray(Bool_t *b)
Read array of Bool_t from buffer.
virtual void WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse)
Write object to buffer. Only used from TBuffer.
void SetCompact(int level)
virtual void WriteShort(Short_t s)
Writes Short_t value to buffer.
virtual void * ReadObjectAny(const TClass *clCast)
Read object from buffer. Only used from TBuffer.
void JsonWriteConstChar(const char *value, Int_t len=-1, const char *=nullptr)
writes string value, processing all kind of special characters
virtual void IncrementLevel(TVirtualStreamerInfo *)
Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions and indent new level in js...
void JsonReadTObjectMembers(TObject *obj, void *node=nullptr)
virtual TVirtualStreamerInfo * GetInfo()
Return current streamer info element.
virtual void SetStreamerElementNumber(TStreamerElement *elem, Int_t comp_type)
Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions and add/verify next elemen...
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 SkipObjectAny()
Skip any kind of object from buffer.
void * JsonReadObject(void *obj, const TClass *objClass=nullptr, TClass **readClass=nullptr)
Read object from current JSON node.
void WorkWithClass(TStreamerInfo *info, const TClass *cl=nullptr)
Prepares buffer to stream data of specified class.
virtual void WriteFloat(Float_t f)
Writes Float_t value to buffer.
R__ALWAYS_INLINE void JsonReadBasic(T &value)
Template function to read basic value from JSON.
virtual void WriteLong(Long_t l)
Writes Long_t value to buffer.
Base class for text-based streamers like TBufferJSON or TBufferXML Special actions list will use meth...
Definition: TBufferText.h:21
static const char * ConvertFloat(Float_t v, char *buf, unsigned len, Bool_t not_optimize=kFALSE)
convert float to string with configured format
static const char * ConvertDouble(Double_t v, char *buf, unsigned len, Bool_t not_optimize=kFALSE)
convert float to string with configured format
virtual void ReadBaseClass(void *start, TStreamerBase *elem)
Read data of base class.
@ kRead
Definition: TBuffer.h:70
Bool_t IsWriting() const
Definition: TBuffer.h:84
Bool_t IsReading() const
Definition: TBuffer.h:83
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition: TClass.cxx:2803
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4824
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5181
TList * GetListOfRealData() const
Definition: TClass.h:423
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5466
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5700
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2708
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=0) const
Definition: TClass.h:566
Version_t GetClassVersion() const
Definition: TClass.h:391
TClass * GetActualClass(const void *object) const
Return a pointer the the real class of the object.
Definition: TClass.cxx:2525
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3332
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:2885
An array of clone (identical) objects.
Definition: TClonesArray.h:32
TClass * GetClass() const
Definition: TClonesArray.h:56
void SetClass(const char *classname, Int_t size=1000)
see TClonesArray::SetClass(const TClass*)
TObject * ConstructedAt(Int_t idx)
Get an object at index 'idx' that is guaranteed to have been constructed.
Collection abstract base class.
Definition: TCollection.h:63
virtual const char * GetName() const
Return name of this collection.
void SetName(const char *name)
Definition: TCollection.h:204
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
virtual void Add(TObject *obj)=0
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
Int_t GetArrayDim() const
Return number of array dimensions.
Int_t GetUnitSize() const
Get the sizeof the underlying type of the data member (i.e.
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
Int_t IsSTLContainer()
The return type is defined in TDictionary (kVector, kList, etc.)
Bool_t IsaPointer() const
Return true if data member is a pointer.
TDataType * GetDataType() const
Definition: TDataMember.h:74
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
Int_t GetType() const
Definition: TDataType.h:68
Option_t * GetOption() const
Definition: TCollection.h:251
A doubly linked list.
Definition: TList.h:44
virtual void Add(TObject *obj)
Definition: TList.h:87
TMap implements an associative array of (key,value) pairs using a THashTable for efficient retrieval ...
Definition: TMap.h:40
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
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 const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
An array of TObjects.
Definition: TObjArray.h:37
Int_t IndexOf(const TObject *obj) const
Definition: TObjArray.cxx:589
void Add(TObject *obj)
Definition: TObjArray.h:73
TObject * Last() const
Return the object in the last filled slot. Returns 0 if no entries.
Definition: TObjArray.cxx:505
Int_t GetLast() const
Return index of last object in array.
Definition: TObjArray.cxx:561
virtual TObject * Remove(TObject *obj)
Remove object from array.
Definition: TObjArray.cxx:703
Collectable string class.
Definition: TObjString.h:28
TString & String()
Definition: TObjString.h:49
Mother of all ROOT objects.
Definition: TObject.h:37
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:443
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition: TObject.cxx:705
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition: TObject.h:60
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
The TRealData class manages the effective list of all data members for a given class.
Definition: TRealData.h:30
TDataMember * GetDataMember() const
Definition: TRealData.h:53
Long_t GetThisOffset() const
Definition: TRealData.h:55
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
Int_t GetType() const
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
virtual void SetArrayDim(Int_t dim)
Set number of array dimensions.
Int_t GetArrayDim() const
Int_t GetArrayLength() const
Int_t GetMaxIndex(Int_t i) const
const char * GetTypeName() const
virtual Bool_t IsBase() const
Return kTRUE if the element represent a base class.
virtual void SetMaxIndex(Int_t dim, Int_t max)
set maximum index for array with dimension dim
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:43
TObjArray * GetElements() const
TClass * GetClass() const
Basic string class.
Definition: TString.h:131
Ssiz_t Length() const
Definition: TString.h:405
Int_t Atoi() const
Return integer value of string.
Definition: TString.cxx:1896
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1151
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition: TString.h:677
const char * Data() const
Definition: TString.h:364
Ssiz_t Capacity() const
Definition: TString.h:352
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1070
TString & Append(const char *cs)
Definition: TString.h:559
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
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
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2264
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
Abstract Interface class describing Streamer information for one class.
static Bool_t CanDelete()
static function returning true if ReadBuffer can delete object
virtual TClass * GetClass() const =0
a class to store JSON values
Definition: json.hpp:1040
size_type size() const noexcept
returns the number of elements
Definition: json.hpp:5063
constexpr bool is_string() const noexcept
return whether value is a string
Definition: json.hpp:2963
basic_json get() const
get special-case overload
Definition: json.hpp:3173
reference at(size_type idx)
access specified array element with bounds checking
Definition: json.hpp:3531
static basic_json parse(T(&array)[N], const parser_callback_t cb=nullptr)
deserialize from an array
Definition: json.hpp:6284
constexpr bool is_null() const noexcept
return whether value is null
Definition: json.hpp:2760
constexpr bool is_array() const noexcept
return whether value is an array
Definition: json.hpp:2941
constexpr bool is_object() const noexcept
return whether value is an object
Definition: json.hpp:2919
const Int_t n
Definition: legend1.C:16
double T(double x)
Definition: ChebyshevPol.h:34
@ kSTLend
Definition: ESTLType.h:46
@ kSTLvector
Definition: ESTLType.h:30
@ kSTLlist
Definition: ESTLType.h:31
@ kSTLforwardlist
Definition: ESTLType.h:41
@ kNotSTL
Definition: ESTLType.h:29
@ kUnorderedMultiSet
Definition: TClassEdit.h:103
@ kUnorderedMultiMap
Definition: TClassEdit.h:105
@ kForwardlist
Definition: TClassEdit.h:96
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
static constexpr double s
Definition: first.py:1
basic_json<> json
default JSON class
Definition: json.hpp:12912
const char * cnt
Definition: TXMLSetup.cxx:74
auto * l
Definition: textangle.C:4