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