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 "TError.h"
109#include "TBase64.h"
110#include "TROOT.h"
111#include "TClass.h"
112#include "TClassTable.h"
113#include "TClassEdit.h"
114#include "TDataType.h"
115#include "TRealData.h"
116#include "TDataMember.h"
117#include "TMap.h"
118#include "TRef.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) && !IsSkipClassInfo(cl)) {
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 if (obj || (jsonClass->GetBaseClassOffset(objClass) != 0)) {
1894 if (jsonClass->GetBaseClassOffset(objClass) < 0)
1895 Error("JsonReadObject", "Not possible to read %s and casting to %s pointer as the two classes are unrelated",
1896 jsonClass->GetName(), objClass->GetName());
1897 else
1898 Error("JsonReadObject", "Reading %s and casting to %s pointer is currently not supported",
1899 jsonClass->GetName(), objClass->GetName());
1900 if (process_stl)
1901 PopStack();
1902 return obj;
1903 }
1904 }
1905
1906 if (!obj)
1907 obj = jsonClass->New();
1908
1909 if (gDebug > 1)
1910 Info("JsonReadObject", "Reading object of class %s refid %u ptr %p", jsonClass->GetName(), fJsonrCnt, obj);
1911
1912 if (!special_kind)
1913 special_kind = JsonSpecialClass(jsonClass);
1914
1915 // add new element to the reading map
1916 MapObject(obj, jsonClass, ++fJsonrCnt);
1917 }
1918
1919 // there are two ways to handle custom streamers
1920 // either prepare data before streamer and tweak basic function which are reading values like UInt32_t
1921 // or try re-implement custom streamer here
1922
1923 if ((jsonClass == TObject::Class()) || (jsonClass == TRef::Class())) {
1924 // for TObject we re-implement custom streamer - it is much easier
1925
1927
1928 } else if (special_kind == json_TCollection) {
1929
1930 JsonReadCollection((TCollection *)obj, jsonClass);
1931
1932 } else {
1933
1934 Bool_t do_read = kTRUE;
1935
1936 // special handling of STL which coded into arrays
1937 if ((special_kind > 0) && (special_kind < ROOT::kSTLend))
1938 do_read = stack->AssignStl(jsonClass, map_convert, fTypeNameTag.Data());
1939
1940 // if provided - use class version from JSON
1941 stack->fClVersion = jsonClassVersion ? jsonClassVersion : jsonClass->GetClassVersion();
1942
1943 if (gDebug > 3)
1944 Info("JsonReadObject", "Calling streamer of class %s", jsonClass->GetName());
1945
1946 if (isBase && (special_kind == 0))
1947 Error("JsonReadObject", "Should not be used for reading of base class %s", jsonClass->GetName());
1948
1949 if (do_read)
1950 jsonClass->Streamer((void *)obj, *this);
1951
1952 stack->fClVersion = 0;
1953
1954 stack->ClearStl(); // reset STL index for itself to prevent looping
1955 }
1956
1957 // return back stack position
1958 if (process_stl)
1959 PopStack();
1960
1961 if (gDebug > 1)
1962 Info("JsonReadObject", "Reading object of class %s done", jsonClass->GetName());
1963
1964 if (readClass)
1965 *readClass = jsonClass;
1966
1967 return obj;
1968}
1969
1970////////////////////////////////////////////////////////////////////////////////
1971/// Read TObject data members from JSON.
1972/// Do not call TObject::Streamer() to avoid special tweaking of TBufferJSON interface
1973
1975{
1976 nlohmann::json *json = node ? (nlohmann::json *)node : Stack()->fNode;
1977
1978 UInt_t uid = json->at("fUniqueID").get<unsigned>();
1979 UInt_t bits = json->at("fBits").get<unsigned>();
1980 // UInt32_t pid = json->at("fPID").get<unsigned>(); // ignore PID for the moment
1981
1982 tobj->SetUniqueID(uid);
1983
1984 static auto tobj_fbits_offset = TObject::Class()->GetDataMemberOffset("fBits");
1985
1986 // there is no method to set all bits directly - do it differently
1987 if (tobj_fbits_offset > 0) {
1988 UInt_t *fbits = (UInt_t *) ((char* ) tobj + tobj_fbits_offset);
1989 *fbits = (*fbits & (TObject::kIsOnHeap | TObject::kNotDeleted)) | bits;
1990 }
1991}
1992
1993////////////////////////////////////////////////////////////////////////////////
1994/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
1995/// and indent new level in json structure.
1996/// This call indicates, that TStreamerInfo functions starts streaming
1997/// object data of correspondent class
1998
2000{
2001 if (gDebug > 2)
2002 Info("IncrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
2003
2005}
2006
2007////////////////////////////////////////////////////////////////////////////////
2008/// Prepares buffer to stream data of specified class
2009
2011{
2012 if (sinfo)
2013 cl = sinfo->GetClass();
2014
2015 if (!cl)
2016 return;
2017
2018 if (gDebug > 3)
2019 Info("WorkWithClass", "Class: %s", cl->GetName());
2020
2021 TJSONStackObj *stack = Stack();
2022
2023 if (IsReading()) {
2024 stack = PushStack(0, stack->fNode);
2025 } else if (stack && stack->IsStreamerElement() && !stack->fIsObjStarted &&
2026 ((stack->fElem->GetType() == TStreamerInfo::kObject) ||
2027 (stack->fElem->GetType() == TStreamerInfo::kAny))) {
2028
2029 stack->fIsObjStarted = kTRUE;
2030
2031 fJsonrCnt++; // count object, but do not keep reference
2032
2033 stack = JsonStartObjectWrite(cl, sinfo);
2034 } else {
2035 stack = PushStack(0);
2036 }
2037
2038 stack->fInfo = sinfo;
2039 stack->fIsStreamerInfo = kTRUE;
2040}
2041
2042////////////////////////////////////////////////////////////////////////////////
2043/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
2044/// and decrease level in json structure.
2045
2047{
2048 if (gDebug > 2)
2049 Info("DecrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
2050
2051 TJSONStackObj *stack = Stack();
2052
2053 if (stack->IsStreamerElement()) {
2054
2055 if (IsWriting()) {
2056 if (gDebug > 3)
2057 Info("DecrementLevel", " Perform post-processing elem: %s", stack->fElem->GetName());
2058
2059 PerformPostProcessing(stack);
2060 }
2061
2062 stack = PopStack(); // remove stack of last element
2063 }
2064
2065 if (stack->fInfo != (TStreamerInfo *)info)
2066 Error("DecrementLevel", " Mismatch of streamer info");
2067
2068 PopStack(); // back from data of stack info
2069
2070 if (gDebug > 3)
2071 Info("DecrementLevel", "Class: %s done", (info ? info->GetClass()->GetName() : "custom"));
2072}
2073
2074////////////////////////////////////////////////////////////////////////////////
2075/// Return current streamer info element
2076
2078{
2079 return Stack()->fInfo;
2080}
2081
2082////////////////////////////////////////////////////////////////////////////////
2083/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
2084/// and add/verify next element of json structure
2085/// This calls allows separate data, correspondent to one class member, from another
2086
2088{
2089 if (gDebug > 3)
2090 Info("SetStreamerElementNumber", "Element name %s", elem->GetName());
2091
2092 WorkWithElement(elem, comp_type);
2093}
2094
2095////////////////////////////////////////////////////////////////////////////////
2096/// This is call-back from streamer which indicates
2097/// that class member will be streamed
2098/// Name of element used in JSON
2099
2101{
2102 TJSONStackObj *stack = Stack();
2103 if (!stack) {
2104 Error("WorkWithElement", "stack is empty");
2105 return;
2106 }
2107
2108 if (gDebug > 0)
2109 Info("WorkWithElement", " Start element %s type %d typename %s", elem ? elem->GetName() : "---",
2110 elem ? elem->GetType() : -1, elem ? elem->GetTypeName() : "---");
2111
2112 if (stack->IsStreamerElement()) {
2113 // this is post processing
2114
2115 if (IsWriting()) {
2116 if (gDebug > 3)
2117 Info("WorkWithElement", " Perform post-processing elem: %s", stack->fElem->GetName());
2118 PerformPostProcessing(stack);
2119 }
2120
2121 stack = PopStack(); // go level back
2122 }
2123
2124 fValue.Clear();
2125
2126 if (!stack) {
2127 Error("WorkWithElement", "Lost of stack");
2128 return;
2129 }
2130
2131 TStreamerInfo *info = stack->fInfo;
2132 if (!stack->IsStreamerInfo()) {
2133 Error("WorkWithElement", "Problem in Inc/Dec level");
2134 return;
2135 }
2136
2137 Int_t number = info ? info->GetElements()->IndexOf(elem) : -1;
2138
2139 if (!elem) {
2140 Error("WorkWithElement", "streamer info returns elem = nullptr");
2141 return;
2142 }
2143
2144 TClass *base_class = elem->IsBase() ? elem->GetClassPointer() : nullptr;
2145
2146 stack = PushStack(0, stack->fNode);
2147 stack->fElem = elem;
2148 stack->fIsElemOwner = (number < 0);
2149
2150 JsonStartElement(elem, base_class);
2151
2152 if (base_class && IsReading())
2153 stack->fClVersion = base_class->GetClassVersion();
2154
2155 if ((elem->GetType() == TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop) && (elem->GetArrayDim() > 0)) {
2156 // array of array, start handling here
2157 stack->fIndx = std::make_unique<TArrayIndexProducer>(elem, -1, fArraySepar.Data());
2158 if (IsWriting())
2159 AppendOutput(stack->fIndx->GetBegin());
2160 }
2161
2162 if (IsReading() && (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20)) {
2163 // reading of such array begins with reading of single Char_t value
2164 // it indicates if array should be read or not
2165 stack->PushIntValue(stack->IsJsonString() || (stack->IsJsonArray() > 0) ? 1 : 0);
2166 }
2167}
2168
2169////////////////////////////////////////////////////////////////////////////////
2170/// Should be called in the beginning of custom class streamer.
2171/// Informs buffer data about class which will be streamed now.
2172///
2173/// ClassBegin(), ClassEnd() and ClassMember() should be used in
2174/// custom class streamers to specify which kind of data are
2175/// now streamed. Such information is used to correctly
2176/// convert class data to JSON. Without that functions calls
2177/// classes with custom streamers cannot be used with TBufferJSON
2178
2180{
2181 WorkWithClass(nullptr, cl);
2182}
2183
2184////////////////////////////////////////////////////////////////////////////////
2185/// Should be called at the end of custom streamer
2186/// See TBufferJSON::ClassBegin for more details
2187
2189{
2190 DecrementLevel(0);
2191}
2192
2193////////////////////////////////////////////////////////////////////////////////
2194/// Method indicates name and typename of class member,
2195/// which should be now streamed in custom streamer
2196/// Following combinations are supported:
2197/// 1. name = "ClassName", typeName = 0 or typename==ClassName
2198/// This is a case, when data of parent class "ClassName" should be streamed.
2199/// For instance, if class directly inherited from TObject, custom
2200/// streamer should include following code:
2201/// ~~~{.cpp}
2202/// b.ClassMember("TObject");
2203/// TObject::Streamer(b);
2204/// ~~~
2205/// 2. Basic data type
2206/// ~~~{.cpp}
2207/// b.ClassMember("fInt","Int_t");
2208/// b >> fInt;
2209/// ~~~
2210/// 3. Array of basic data types
2211/// ~~~{.cpp}
2212/// b.ClassMember("fArr","Int_t", 5);
2213/// b.ReadFastArray(fArr, 5);
2214/// ~~~
2215/// 4. Object as data member
2216/// ~~~{.cpp}
2217/// b.ClassMember("fName","TString");
2218/// fName.Streamer(b);
2219/// ~~~
2220/// 5. Pointer on object as data member
2221/// ~~~{.cpp}
2222/// b.ClassMember("fObj","TObject*");
2223/// b.StreamObject(fObj);
2224/// ~~~
2225///
2226/// arrsize1 and arrsize2 arguments (when specified) indicate first and
2227/// second dimension of array. Can be used for array of basic types.
2228/// See ClassBegin() method for more details.
2229
2230void TBufferJSON::ClassMember(const char *name, const char *typeName, Int_t arrsize1, Int_t arrsize2)
2231{
2232 if (!typeName)
2233 typeName = name;
2234
2235 if (!name || (strlen(name) == 0)) {
2236 Error("ClassMember", "Invalid member name");
2237 return;
2238 }
2239
2240 TString tname = typeName;
2241
2242 Int_t typ_id = -1;
2243
2244 if (strcmp(typeName, "raw:data") == 0)
2245 typ_id = TStreamerInfo::kMissing;
2246
2247 if (typ_id < 0) {
2248 TDataType *dt = gROOT->GetType(typeName);
2249 if (dt && (dt->GetType() > 0) && (dt->GetType() < 20))
2250 typ_id = dt->GetType();
2251 }
2252
2253 if (typ_id < 0)
2254 if (strcmp(name, typeName) == 0) {
2255 TClass *cl = TClass::GetClass(tname.Data());
2256 if (cl)
2257 typ_id = TStreamerInfo::kBase;
2258 }
2259
2260 if (typ_id < 0) {
2261 Bool_t isptr = kFALSE;
2262 if (tname[tname.Length() - 1] == '*') {
2263 tname.Resize(tname.Length() - 1);
2264 isptr = kTRUE;
2265 }
2266 TClass *cl = TClass::GetClass(tname.Data());
2267 if (!cl) {
2268 Error("ClassMember", "Invalid class specifier %s", typeName);
2269 return;
2270 }
2271
2272 if (cl->IsTObject())
2274 else
2275 typ_id = isptr ? TStreamerInfo::kAnyp : TStreamerInfo::kAny;
2276
2277 if ((cl == TString::Class()) && !isptr)
2278 typ_id = TStreamerInfo::kTString;
2279 }
2280
2281 TStreamerElement *elem = nullptr;
2282
2283 if (typ_id == TStreamerInfo::kMissing) {
2284 elem = new TStreamerElement(name, "title", 0, typ_id, "raw:data");
2285 } else if (typ_id == TStreamerInfo::kBase) {
2286 TClass *cl = TClass::GetClass(tname.Data());
2287 if (cl) {
2288 TStreamerBase *b = new TStreamerBase(tname.Data(), "title", 0);
2289 b->SetBaseVersion(cl->GetClassVersion());
2290 elem = b;
2291 }
2292 } else if ((typ_id > 0) && (typ_id < 20)) {
2293 elem = new TStreamerBasicType(name, "title", 0, typ_id, typeName);
2294 } else if ((typ_id == TStreamerInfo::kObject) || (typ_id == TStreamerInfo::kTObject) ||
2295 (typ_id == TStreamerInfo::kTNamed)) {
2296 elem = new TStreamerObject(name, "title", 0, tname.Data());
2297 } else if (typ_id == TStreamerInfo::kObjectp) {
2298 elem = new TStreamerObjectPointer(name, "title", 0, tname.Data());
2299 } else if (typ_id == TStreamerInfo::kAny) {
2300 elem = new TStreamerObjectAny(name, "title", 0, tname.Data());
2301 } else if (typ_id == TStreamerInfo::kAnyp) {
2302 elem = new TStreamerObjectAnyPointer(name, "title", 0, tname.Data());
2303 } else if (typ_id == TStreamerInfo::kTString) {
2304 elem = new TStreamerString(name, "title", 0);
2305 }
2306
2307 if (!elem) {
2308 Error("ClassMember", "Invalid combination name = %s type = %s", name, typeName);
2309 return;
2310 }
2311
2312 if (arrsize1 > 0) {
2313 elem->SetArrayDim(arrsize2 > 0 ? 2 : 1);
2314 elem->SetMaxIndex(0, arrsize1);
2315 if (arrsize2 > 0)
2316 elem->SetMaxIndex(1, arrsize2);
2317 }
2318
2319 // we indicate that there is no streamerinfo
2320 WorkWithElement(elem, -1);
2321}
2322
2323////////////////////////////////////////////////////////////////////////////////
2324/// Function is converts TObject and TString structures to more compact representation
2325
2326void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_cl)
2327{
2328 if (stack->fIsPostProcessed)
2329 return;
2330
2331 const TStreamerElement *elem = stack->fElem;
2332
2333 if (!elem && !obj_cl)
2334 return;
2335
2336 stack->fIsPostProcessed = kTRUE;
2337
2338 // when element was written as separate object, close only braces and exit
2339 if (stack->fIsObjStarted) {
2340 AppendOutput("", "}");
2341 return;
2342 }
2343
2344 Bool_t isTObject(kFALSE), isTRef(kFALSE), isTString(kFALSE), isSTLstring(kFALSE), isOffsetPArray(kFALSE),
2345 isTArray(kFALSE);
2346
2347 if (obj_cl) {
2348 if (obj_cl == TObject::Class())
2349 isTObject = kTRUE;
2350 else if (obj_cl == TRef::Class())
2351 isTRef = kTRUE;
2352 else
2353 return;
2354 } else {
2355 const char *typname = elem->IsBase() ? elem->GetName() : elem->GetTypeName();
2356 isTObject = (elem->GetType() == TStreamerInfo::kTObject) || (strcmp("TObject", typname) == 0);
2357 isTString = elem->GetType() == TStreamerInfo::kTString;
2358 isSTLstring = elem->GetType() == TStreamerInfo::kSTLstring;
2359 isOffsetPArray = (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20);
2360 isTArray = (strncmp("TArray", typname, 6) == 0);
2361 }
2362
2363 if (isTString || isSTLstring) {
2364 // just remove all kind of string length information
2365
2366 if (gDebug > 3)
2367 Info("PerformPostProcessing", "reformat string value = '%s'", fValue.Data());
2368
2369 stack->fValues.clear();
2370 } else if (isOffsetPArray) {
2371 // basic array with [fN] comment
2372
2373 if (stack->fValues.empty() && (fValue == "0")) {
2374 fValue = "[]";
2375 } else if ((stack->fValues.size() == 1) && (stack->fValues[0] == "1")) {
2376 stack->fValues.clear();
2377 } else {
2378 Error("PerformPostProcessing", "Wrong values for kOffsetP element %s", (elem ? elem->GetName() : "---"));
2379 stack->fValues.clear();
2380 fValue = "[]";
2381 }
2382 } else if (isTObject || isTRef) {
2383 // complex workaround for TObject/TRef streamer
2384 // would be nice if other solution can be found
2385 // Here is not supported TRef on TRef (double reference)
2386
2387 Int_t cnt = stack->fValues.size();
2388 if (fValue.Length() > 0)
2389 cnt++;
2390
2391 if (cnt < 2 || cnt > 3) {
2392 if (gDebug > 0)
2393 Error("PerformPostProcessing", "When storing TObject/TRef, strange number of items %d", cnt);
2394 AppendOutput(stack->NextMemberSeparator(), "\"dummy\"");
2396 } else {
2397 AppendOutput(stack->NextMemberSeparator(), "\"fUniqueID\"");
2399 AppendOutput(stack->fValues[0].c_str());
2400 AppendOutput(stack->NextMemberSeparator(), "\"fBits\"");
2402 auto tbits = std::atol((stack->fValues.size() > 1) ? stack->fValues[1].c_str() : fValue.Data());
2403 AppendOutput(std::to_string(tbits & ~TObject::kNotDeleted & ~TObject::kIsOnHeap).c_str());
2404 if (cnt == 3) {
2405 AppendOutput(stack->NextMemberSeparator(), "\"fPID\"");
2407 AppendOutput((stack->fValues.size() > 2) ? stack->fValues[2].c_str() : fValue.Data());
2408 }
2409
2410 stack->fValues.clear();
2411 fValue.Clear();
2412 return;
2413 }
2414
2415 } else if (isTArray) {
2416 // for TArray one deletes complete stack
2417 stack->fValues.clear();
2418 }
2419
2420 if (elem && elem->IsBase() && (fValue.Length() == 0)) {
2421 // here base class data already completely stored
2422 return;
2423 }
2424
2425 if (!stack->fValues.empty()) {
2426 // append element blob data just as abstract array, user is responsible to decode it
2427 AppendOutput("[");
2428 for (auto &blob: stack->fValues) {
2429 AppendOutput(blob.c_str());
2431 }
2432 }
2433
2434 if (fValue.Length() == 0) {
2435 AppendOutput("null");
2436 } else {
2438 fValue.Clear();
2439 }
2440
2441 if (!stack->fValues.empty())
2442 AppendOutput("]");
2443}
2444
2445////////////////////////////////////////////////////////////////////////////////
2446/// suppressed function of TBuffer
2447
2449{
2450 return nullptr;
2451}
2452
2453////////////////////////////////////////////////////////////////////////////////
2454/// suppressed function of TBuffer
2455
2457
2458////////////////////////////////////////////////////////////////////////////////
2459/// read version value from buffer
2460
2462{
2463 Version_t res = cl ? cl->GetClassVersion() : 0;
2464
2465 if (start)
2466 *start = 0;
2467 if (bcnt)
2468 *bcnt = 0;
2469
2470 if (!cl && Stack()->fClVersion) {
2471 res = Stack()->fClVersion;
2472 Stack()->fClVersion = 0;
2473 }
2474
2475 if (gDebug > 3)
2476 Info("ReadVersion", "Result: %d Class: %s", res, (cl ? cl->GetName() : "---"));
2477
2478 return res;
2479}
2480
2481////////////////////////////////////////////////////////////////////////////////
2482/// Ignored in TBufferJSON
2483
2484UInt_t TBufferJSON::WriteVersion(const TClass * /*cl*/, Bool_t /* useBcnt */)
2485{
2486 return 0;
2487}
2488
2489////////////////////////////////////////////////////////////////////////////////
2490/// Read object from buffer. Only used from TBuffer
2491
2492void *TBufferJSON::ReadObjectAny(const TClass *expectedClass)
2493{
2494 if (gDebug > 2)
2495 Info("ReadObjectAny", "From current JSON node");
2496 void *res = JsonReadObject(nullptr, expectedClass);
2497 return res;
2498}
2499
2500////////////////////////////////////////////////////////////////////////////////
2501/// Skip any kind of object from buffer
2502
2504
2505////////////////////////////////////////////////////////////////////////////////
2506/// Write object to buffer. Only used from TBuffer
2507
2508void TBufferJSON::WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse)
2509{
2510 if (gDebug > 3)
2511 Info("WriteObjectClass", "Class %s", (actualClass ? actualClass->GetName() : " null"));
2512
2513 JsonWriteObject(actualObjStart, actualClass, cacheReuse);
2514}
2515
2516////////////////////////////////////////////////////////////////////////////////
2517/// If value exists, push in the current stack for post-processing
2518
2520{
2521 if (fValue.Length() > 0)
2522 Stack()->PushValue(fValue);
2523}
2524
2525////////////////////////////////////////////////////////////////////////////////
2526/// Read array of Bool_t from buffer
2527
2529{
2530 return JsonReadArray(b);
2531}
2532
2533////////////////////////////////////////////////////////////////////////////////
2534/// Read array of Char_t from buffer
2535
2537{
2538 return JsonReadArray(c);
2539}
2540
2541////////////////////////////////////////////////////////////////////////////////
2542/// Read array of UChar_t from buffer
2543
2545{
2546 return JsonReadArray(c);
2547}
2548
2549////////////////////////////////////////////////////////////////////////////////
2550/// Read array of Short_t from buffer
2551
2553{
2554 return JsonReadArray(h);
2555}
2556
2557////////////////////////////////////////////////////////////////////////////////
2558/// Read array of UShort_t from buffer
2559
2561{
2562 return JsonReadArray(h);
2563}
2564
2565////////////////////////////////////////////////////////////////////////////////
2566/// Read array of Int_t from buffer
2567
2569{
2570 return JsonReadArray(i);
2571}
2572
2573////////////////////////////////////////////////////////////////////////////////
2574/// Read array of UInt_t from buffer
2575
2577{
2578 return JsonReadArray(i);
2579}
2580
2581////////////////////////////////////////////////////////////////////////////////
2582/// Read array of Long_t from buffer
2583
2585{
2586 return JsonReadArray(l);
2587}
2588
2589////////////////////////////////////////////////////////////////////////////////
2590/// Read array of ULong_t from buffer
2591
2593{
2594 return JsonReadArray(l);
2595}
2596
2597////////////////////////////////////////////////////////////////////////////////
2598/// Read array of Long64_t from buffer
2599
2601{
2602 return JsonReadArray(l);
2603}
2604
2605////////////////////////////////////////////////////////////////////////////////
2606/// Read array of ULong64_t from buffer
2607
2609{
2610 return JsonReadArray(l);
2611}
2612
2613////////////////////////////////////////////////////////////////////////////////
2614/// Read array of Float_t from buffer
2615
2617{
2618 return JsonReadArray(f);
2619}
2620
2621////////////////////////////////////////////////////////////////////////////////
2622/// Read array of Double_t from buffer
2623
2625{
2626 return JsonReadArray(d);
2627}
2628
2629////////////////////////////////////////////////////////////////////////////////
2630/// Read static array from JSON - not used
2631
2632template <typename T>
2634{
2635 Info("ReadArray", "Not implemented");
2636 return value ? 1 : 0;
2637}
2638
2639////////////////////////////////////////////////////////////////////////////////
2640/// Read array of Bool_t from buffer
2641
2643{
2644 return JsonReadArray(b);
2645}
2646
2647////////////////////////////////////////////////////////////////////////////////
2648/// Read array of Char_t from buffer
2649
2651{
2652 return JsonReadArray(c);
2653}
2654
2655////////////////////////////////////////////////////////////////////////////////
2656/// Read array of UChar_t from buffer
2657
2659{
2660 return JsonReadArray(c);
2661}
2662
2663////////////////////////////////////////////////////////////////////////////////
2664/// Read array of Short_t from buffer
2665
2667{
2668 return JsonReadArray(h);
2669}
2670
2671////////////////////////////////////////////////////////////////////////////////
2672/// Read array of UShort_t from buffer
2673
2675{
2676 return JsonReadArray(h);
2677}
2678
2679////////////////////////////////////////////////////////////////////////////////
2680/// Read array of Int_t from buffer
2681
2683{
2684 return JsonReadArray(i);
2685}
2686
2687////////////////////////////////////////////////////////////////////////////////
2688/// Read array of UInt_t from buffer
2689
2691{
2692 return JsonReadArray(i);
2693}
2694
2695////////////////////////////////////////////////////////////////////////////////
2696/// Read array of Long_t from buffer
2697
2699{
2700 return JsonReadArray(l);
2701}
2702
2703////////////////////////////////////////////////////////////////////////////////
2704/// Read array of ULong_t from buffer
2705
2707{
2708 return JsonReadArray(l);
2709}
2710
2711////////////////////////////////////////////////////////////////////////////////
2712/// Read array of Long64_t from buffer
2713
2715{
2716 return JsonReadArray(l);
2717}
2718
2719////////////////////////////////////////////////////////////////////////////////
2720/// Read array of ULong64_t from buffer
2721
2723{
2724 return JsonReadArray(l);
2725}
2726
2727////////////////////////////////////////////////////////////////////////////////
2728/// Read array of Float_t from buffer
2729
2731{
2732 return JsonReadArray(f);
2733}
2734
2735////////////////////////////////////////////////////////////////////////////////
2736/// Read array of Double_t from buffer
2737
2739{
2740 return JsonReadArray(d);
2741}
2742
2743////////////////////////////////////////////////////////////////////////////////
2744/// Template method to read array from the JSON
2745
2746template <typename T>
2747R__ALWAYS_INLINE void TBufferJSON::JsonReadFastArray(T *arr, Int_t arrsize, bool asstring)
2748{
2749 if (!arr || (arrsize <= 0))
2750 return;
2751 nlohmann::json *json = Stack()->fNode;
2752 if (gDebug > 2)
2753 Info("ReadFastArray", "Reading array sz %d from JSON %s", arrsize, json->dump().substr(0, 30).c_str());
2754 auto indexes = Stack()->MakeReadIndexes();
2755 if (indexes) { /* at least two dims */
2756 TArrayI &indx = indexes->GetIndices();
2757 Int_t lastdim = indx.GetSize() - 1;
2758 if (indexes->TotalLength() != arrsize)
2759 Error("ReadFastArray", "Mismatch %d-dim array sizes %d %d", lastdim + 1, arrsize, (int)indexes->TotalLength());
2760 for (int cnt = 0; cnt < arrsize; ++cnt) {
2761 nlohmann::json *elem = &(json->at(indx[0]));
2762 for (int k = 1; k < lastdim; ++k)
2763 elem = &((*elem)[indx[k]]);
2764 arr[cnt] = asstring ? elem->get<std::string>()[indx[lastdim]] : (*elem)[indx[lastdim]].get<T>();
2765 indexes->NextSeparator();
2766 }
2767 } else if (asstring) {
2768 std::string str = json->get<std::string>();
2769 for (int cnt = 0; cnt < arrsize; ++cnt)
2770 arr[cnt] = (cnt < (int)str.length()) ? str[cnt] : 0;
2771 } else if (json->is_object() && (json->count("$arr") == 1)) {
2772 if (json->at("len").get<int>() != arrsize)
2773 Error("ReadFastArray", "Mismatch compressed array size %d %d", arrsize, json->at("len").get<int>());
2774
2775 for (int cnt = 0; cnt < arrsize; ++cnt)
2776 arr[cnt] = 0;
2777
2778 if (json->count("b") == 1) {
2779 auto base64 = json->at("b").get<std::string>();
2780
2781 int offset = (json->count("o") == 1) ? json->at("o").get<int>() : 0;
2782
2783 // TODO: provide TBase64::Decode with direct write into target buffer
2784 auto decode = TBase64::Decode(base64.c_str());
2785
2786 if (arrsize * (long) sizeof(T) < (offset + decode.Length())) {
2787 Error("ReadFastArray", "Base64 data %ld larger than target array size %ld", (long) decode.Length() + offset, (long) (arrsize*sizeof(T)));
2788 } else if ((sizeof(T) > 1) && (decode.Length() % sizeof(T) != 0)) {
2789 Error("ReadFastArray", "Base64 data size %ld not matches with element size %ld", (long) decode.Length(), (long) sizeof(T));
2790 } else {
2791 memcpy((char *) arr + offset, decode.Data(), decode.Length());
2792 }
2793 return;
2794 }
2795
2796 int p = 0, id = 0;
2797 std::string idname = "", pname, vname, nname;
2798 while (p < arrsize) {
2799 pname = std::string("p") + idname;
2800 if (json->count(pname) == 1)
2801 p = json->at(pname).get<int>();
2802 vname = std::string("v") + idname;
2803 if (json->count(vname) != 1)
2804 break;
2805 nlohmann::json &v = json->at(vname);
2806 if (v.is_array()) {
2807 for (unsigned sub = 0; sub < v.size(); ++sub)
2808 arr[p++] = v[sub].get<T>();
2809 } else {
2810 nname = std::string("n") + idname;
2811 unsigned ncopy = (json->count(nname) == 1) ? json->at(nname).get<unsigned>() : 1;
2812 for (unsigned sub = 0; sub < ncopy; ++sub)
2813 arr[p++] = v.get<T>();
2814 }
2815 idname = std::to_string(++id);
2816 }
2817 } else {
2818 if ((int)json->size() != arrsize)
2819 Error("ReadFastArray", "Mismatch array sizes %d %d", arrsize, (int)json->size());
2820 for (int cnt = 0; cnt < arrsize; ++cnt)
2821 arr[cnt] = json->at(cnt).get<T>();
2822 }
2823}
2824
2825////////////////////////////////////////////////////////////////////////////////
2826/// read array of Bool_t from buffer
2827
2829{
2831}
2832
2833////////////////////////////////////////////////////////////////////////////////
2834/// read array of Char_t from buffer
2835
2837{
2838 JsonReadFastArray(c, n, true);
2839}
2840
2841////////////////////////////////////////////////////////////////////////////////
2842/// read array of Char_t from buffer
2843
2845{
2846 JsonReadFastArray(c, n, true);
2847}
2848
2849////////////////////////////////////////////////////////////////////////////////
2850/// read array of UChar_t from buffer
2851
2853{
2855}
2856
2857////////////////////////////////////////////////////////////////////////////////
2858/// read array of Short_t from buffer
2859
2861{
2863}
2864
2865////////////////////////////////////////////////////////////////////////////////
2866/// read array of UShort_t from buffer
2867
2869{
2871}
2872
2873////////////////////////////////////////////////////////////////////////////////
2874/// read array of Int_t from buffer
2875
2877{
2878 JsonReadFastArray(i, n);
2879}
2880
2881////////////////////////////////////////////////////////////////////////////////
2882/// read array of UInt_t from buffer
2883
2885{
2886 JsonReadFastArray(i, n);
2887}
2888
2889////////////////////////////////////////////////////////////////////////////////
2890/// read array of Long_t from buffer
2891
2893{
2895}
2896
2897////////////////////////////////////////////////////////////////////////////////
2898/// read array of ULong_t from buffer
2899
2901{
2903}
2904
2905////////////////////////////////////////////////////////////////////////////////
2906/// read array of Long64_t from buffer
2907
2909{
2911}
2912
2913////////////////////////////////////////////////////////////////////////////////
2914/// read array of ULong64_t from buffer
2915
2917{
2919}
2920
2921////////////////////////////////////////////////////////////////////////////////
2922/// read array of Float_t from buffer
2923
2925{
2927}
2928
2929////////////////////////////////////////////////////////////////////////////////
2930/// read array of Double_t from buffer
2931
2933{
2935}
2936
2937////////////////////////////////////////////////////////////////////////////////
2938/// Read an array of 'n' objects from the I/O buffer.
2939/// Stores the objects read starting at the address 'start'.
2940/// The objects in the array are assume to be of class 'cl'.
2941/// Copied code from TBufferFile
2942
2943void TBufferJSON::ReadFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer * /* streamer */,
2944 const TClass * /* onFileClass */)
2945{
2946 if (gDebug > 1)
2947 Info("ReadFastArray", "void* n:%d cl:%s", n, cl->GetName());
2948
2949 // if (streamer) {
2950 // Info("ReadFastArray", "(void*) Calling streamer - not handled correctly");
2951 // streamer->SetOnFileClass(onFileClass);
2952 // (*streamer)(*this, start, 0);
2953 // return;
2954 // }
2955
2956 int objectSize = cl->Size();
2957 char *obj = (char *)start;
2958
2959 TJSONStackObj *stack = Stack();
2960 nlohmann::json *topnode = stack->fNode, *subnode = topnode;
2961 if (stack->fIndx)
2962 subnode = stack->fIndx->ExtractNode(topnode);
2963
2964 TArrayIndexProducer indexes(stack->fElem, n, "");
2965
2966 if (gDebug > 1)
2967 Info("ReadFastArray", "Indexes ndim:%d totallen:%d", indexes.NumDimensions(), indexes.TotalLength());
2968
2969 for (Int_t j = 0; j < n; j++, obj += objectSize) {
2970
2971 stack->fNode = indexes.ExtractNode(subnode);
2972
2973 JsonReadObject(obj, cl);
2974 }
2975
2976 // restore top node - show we use stack here?
2977 stack->fNode = topnode;
2978}
2979
2980////////////////////////////////////////////////////////////////////////////////
2981/// redefined here to avoid warning message from gcc
2982
2983void TBufferJSON::ReadFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc,
2984 TMemberStreamer * /* streamer */, const TClass * /* onFileClass */)
2985{
2986 if (gDebug > 1)
2987 Info("ReadFastArray", "void** n:%d cl:%s prealloc:%s", n, cl->GetName(), (isPreAlloc ? "true" : "false"));
2988
2989 // if (streamer) {
2990 // Info("ReadFastArray", "(void**) Calling streamer - not handled correctly");
2991 // if (isPreAlloc) {
2992 // for (Int_t j = 0; j < n; j++) {
2993 // if (!start[j])
2994 // start[j] = cl->New();
2995 // }
2996 // }
2997 // streamer->SetOnFileClass(onFileClass);
2998 // (*streamer)(*this, (void *)start, 0);
2999 // return;
3000 // }
3001
3002 TJSONStackObj *stack = Stack();
3003 nlohmann::json *topnode = stack->fNode, *subnode = topnode;
3004 if (stack->fIndx)
3005 subnode = stack->fIndx->ExtractNode(topnode);
3006
3007 TArrayIndexProducer indexes(stack->fElem, n, "");
3008
3009 for (Int_t j = 0; j < n; j++) {
3010
3011 stack->fNode = indexes.ExtractNode(subnode);
3012
3013 if (!isPreAlloc) {
3014 void *old = start[j];
3015 start[j] = JsonReadObject(nullptr, cl);
3016 if (old && old != start[j] && TStreamerInfo::CanDelete())
3017 (const_cast<TClass *>(cl))->Destructor(old, kFALSE); // call delete and destruct
3018 } else {
3019 if (!start[j])
3020 start[j] = (const_cast<TClass *>(cl))->New();
3021 JsonReadObject(start[j], cl);
3022 }
3023 }
3024
3025 stack->fNode = topnode;
3026}
3027
3028template <typename T>
3029R__ALWAYS_INLINE void TBufferJSON::JsonWriteArrayCompress(const T *vname, Int_t arrsize, const char *typname)
3030{
3031 bool is_base64 = Stack()->fBase64 || (fArrayCompact == kBase64);
3032
3033 if (!is_base64 && ((fArrayCompact == 0) || (arrsize < 6))) {
3034 fValue.Append("[");
3035 for (Int_t indx = 0; indx < arrsize; indx++) {
3036 if (indx > 0)
3038 JsonWriteBasic(vname[indx]);
3039 }
3040 fValue.Append("]");
3041 } else if (is_base64 && !arrsize) {
3042 fValue.Append("[]");
3043 } else {
3044 fValue.Append("{");
3045 fValue.Append(TString::Format("\"$arr\":\"%s\"%s\"len\":%d", typname, fArraySepar.Data(), arrsize));
3046 Int_t aindx(0), bindx(arrsize);
3047 while ((aindx < arrsize) && (vname[aindx] == 0))
3048 aindx++;
3049 while ((aindx < bindx) && (vname[bindx - 1] == 0))
3050 bindx--;
3051
3052 if (is_base64) {
3053 // small initial offset makes no sense - JSON code is large then size gain
3054 if ((aindx * sizeof(T) < 5) && (aindx < bindx))
3055 aindx = 0;
3056
3057 if ((aindx > 0) && (aindx < bindx))
3058 fValue.Append(TString::Format("%s\"o\":%ld", fArraySepar.Data(), (long) (aindx * (int) sizeof(T))));
3059
3061 fValue.Append("\"b\":\"");
3062
3063 if (aindx < bindx)
3064 fValue.Append(TBase64::Encode((const char *) (vname + aindx), (bindx - aindx) * sizeof(T)));
3065
3066 fValue.Append("\"");
3067 } else if (aindx < bindx) {
3068 TString suffix("");
3069 Int_t p(aindx), suffixcnt(-1), lastp(0);
3070 while (p < bindx) {
3071 if (vname[p] == 0) {
3072 p++;
3073 continue;
3074 }
3075 Int_t p0(p++), pp(0), nsame(1);
3077 pp = bindx;
3078 p = bindx + 1;
3079 nsame = 0;
3080 }
3081 for (; p <= bindx; ++p) {
3082 if ((p < bindx) && (vname[p] == vname[p - 1])) {
3083 nsame++;
3084 continue;
3085 }
3086 if (vname[p - 1] == 0) {
3087 if (nsame > 9) {
3088 nsame = 0;
3089 break;
3090 }
3091 } else if (nsame > 5) {
3092 if (pp) {
3093 p = pp;
3094 nsame = 0;
3095 } else
3096 pp = p;
3097 break;
3098 }
3099 pp = p;
3100 nsame = 1;
3101 }
3102 if (pp <= p0)
3103 continue;
3104 if (++suffixcnt > 0)
3105 suffix.Form("%d", suffixcnt);
3106 if (p0 != lastp)
3107 fValue.Append(TString::Format("%s\"p%s\":%d", fArraySepar.Data(), suffix.Data(), p0));
3108 lastp = pp; /* remember cursor, it may be the same */
3109 fValue.Append(TString::Format("%s\"v%s\":", fArraySepar.Data(), suffix.Data()));
3110 if ((nsame > 1) || (pp - p0 == 1)) {
3111 JsonWriteBasic(vname[p0]);
3112 if (nsame > 1)
3113 fValue.Append(TString::Format("%s\"n%s\":%d", fArraySepar.Data(), suffix.Data(), nsame));
3114 } else {
3115 fValue.Append("[");
3116 for (Int_t indx = p0; indx < pp; indx++) {
3117 if (indx > p0)
3119 JsonWriteBasic(vname[indx]);
3120 }
3121 fValue.Append("]");
3122 }
3123 }
3124 }
3125 fValue.Append("}");
3126 }
3127}
3128
3129////////////////////////////////////////////////////////////////////////////////
3130/// Write array of Bool_t to buffer
3131
3133{
3134 JsonPushValue();
3135 JsonWriteArrayCompress(b, n, "Bool");
3136}
3137
3138////////////////////////////////////////////////////////////////////////////////
3139/// Write array of Char_t to buffer
3140
3142{
3143 JsonPushValue();
3144 JsonWriteArrayCompress(c, n, "Int8");
3145}
3146
3147////////////////////////////////////////////////////////////////////////////////
3148/// Write array of UChar_t to buffer
3149
3151{
3152 JsonPushValue();
3153 JsonWriteArrayCompress(c, n, "Uint8");
3154}
3155
3156////////////////////////////////////////////////////////////////////////////////
3157/// Write array of Short_t to buffer
3158
3160{
3161 JsonPushValue();
3162 JsonWriteArrayCompress(h, n, "Int16");
3163}
3164
3165////////////////////////////////////////////////////////////////////////////////
3166/// Write array of UShort_t to buffer
3167
3169{
3170 JsonPushValue();
3171 JsonWriteArrayCompress(h, n, "Uint16");
3172}
3173
3174////////////////////////////////////////////////////////////////////////////////
3175/// Write array of Int_ to buffer
3176
3178{
3179 JsonPushValue();
3180 JsonWriteArrayCompress(i, n, "Int32");
3181}
3182
3183////////////////////////////////////////////////////////////////////////////////
3184/// Write array of UInt_t to buffer
3185
3187{
3188 JsonPushValue();
3189 JsonWriteArrayCompress(i, n, "Uint32");
3190}
3191
3192////////////////////////////////////////////////////////////////////////////////
3193/// Write array of Long_t to buffer
3194
3196{
3197 JsonPushValue();
3198 JsonWriteArrayCompress(l, n, "Int64");
3199}
3200
3201////////////////////////////////////////////////////////////////////////////////
3202/// Write array of ULong_t to buffer
3203
3205{
3206 JsonPushValue();
3207 JsonWriteArrayCompress(l, n, "Uint64");
3208}
3209
3210////////////////////////////////////////////////////////////////////////////////
3211/// Write array of Long64_t to buffer
3212
3214{
3215 JsonPushValue();
3216 JsonWriteArrayCompress(l, n, "Int64");
3217}
3218
3219////////////////////////////////////////////////////////////////////////////////
3220/// Write array of ULong64_t to buffer
3221
3223{
3224 JsonPushValue();
3225 JsonWriteArrayCompress(l, n, "Uint64");
3226}
3227
3228////////////////////////////////////////////////////////////////////////////////
3229/// Write array of Float_t to buffer
3230
3232{
3233 JsonPushValue();
3234 JsonWriteArrayCompress(f, n, "Float32");
3235}
3236
3237////////////////////////////////////////////////////////////////////////////////
3238/// Write array of Double_t to buffer
3239
3241{
3242 JsonPushValue();
3243 JsonWriteArrayCompress(d, n, "Float64");
3244}
3245
3246////////////////////////////////////////////////////////////////////////////////
3247/// Template method to write array of arbitrary dimensions
3248/// Different methods can be used for store last array dimension -
3249/// either JsonWriteArrayCompress<T>() or JsonWriteConstChar()
3250
3251template <typename T>
3252R__ALWAYS_INLINE void TBufferJSON::JsonWriteFastArray(const T *arr, Int_t arrsize, const char *typname,
3253 void (TBufferJSON::*method)(const T *, Int_t, const char *))
3254{
3255 JsonPushValue();
3256 if (arrsize <= 0) { /*fJsonrCnt++;*/
3257 fValue.Append("[]");
3258 return;
3259 }
3260
3261 TStreamerElement *elem = Stack()->fElem;
3262 if (elem && (elem->GetArrayDim() > 1) && (elem->GetArrayLength() == arrsize)) {
3263 TArrayI indexes(elem->GetArrayDim() - 1);
3264 indexes.Reset(0);
3265 Int_t cnt = 0, shift = 0, len = elem->GetMaxIndex(indexes.GetSize());
3266 while (cnt >= 0) {
3267 if (indexes[cnt] >= elem->GetMaxIndex(cnt)) {
3268 fValue.Append("]");
3269 indexes[cnt--] = 0;
3270 if (cnt >= 0)
3271 indexes[cnt]++;
3272 continue;
3273 }
3274 fValue.Append(indexes[cnt] == 0 ? "[" : fArraySepar.Data());
3275 if (++cnt == indexes.GetSize()) {
3276 (*this.*method)((arr + shift), len, typname);
3277 indexes[--cnt]++;
3278 shift += len;
3279 }
3280 }
3281 } else {
3282 (*this.*method)(arr, arrsize, typname);
3283 }
3284}
3285
3286////////////////////////////////////////////////////////////////////////////////
3287/// Write array of Bool_t to buffer
3288
3290{
3291 JsonWriteFastArray(b, n, "Bool", &TBufferJSON::JsonWriteArrayCompress<Bool_t>);
3292}
3293
3294////////////////////////////////////////////////////////////////////////////////
3295/// Write array of Char_t to buffer
3296
3298{
3300}
3301
3302////////////////////////////////////////////////////////////////////////////////
3303/// Write array of Char_t to buffer
3304
3306{
3308}
3309
3310////////////////////////////////////////////////////////////////////////////////
3311/// Write array of UChar_t to buffer
3312
3314{
3315 JsonWriteFastArray(c, n, "Uint8", &TBufferJSON::JsonWriteArrayCompress<UChar_t>);
3316}
3317
3318////////////////////////////////////////////////////////////////////////////////
3319/// Write array of Short_t to buffer
3320
3322{
3323 JsonWriteFastArray(h, n, "Int16", &TBufferJSON::JsonWriteArrayCompress<Short_t>);
3324}
3325
3326////////////////////////////////////////////////////////////////////////////////
3327/// Write array of UShort_t to buffer
3328
3330{
3331 JsonWriteFastArray(h, n, "Uint16", &TBufferJSON::JsonWriteArrayCompress<UShort_t>);
3332}
3333
3334////////////////////////////////////////////////////////////////////////////////
3335/// Write array of Int_t to buffer
3336
3338{
3339 JsonWriteFastArray(i, n, "Int32", &TBufferJSON::JsonWriteArrayCompress<Int_t>);
3340}
3341
3342////////////////////////////////////////////////////////////////////////////////
3343/// Write array of UInt_t to buffer
3344
3346{
3347 JsonWriteFastArray(i, n, "Uint32", &TBufferJSON::JsonWriteArrayCompress<UInt_t>);
3348}
3349
3350////////////////////////////////////////////////////////////////////////////////
3351/// Write array of Long_t to buffer
3352
3354{
3355 JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long_t>);
3356}
3357
3358////////////////////////////////////////////////////////////////////////////////
3359/// Write array of ULong_t to buffer
3360
3362{
3363 JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong_t>);
3364}
3365
3366////////////////////////////////////////////////////////////////////////////////
3367/// Write array of Long64_t to buffer
3368
3370{
3371 JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long64_t>);
3372}
3373
3374////////////////////////////////////////////////////////////////////////////////
3375/// Write array of ULong64_t to buffer
3376
3378{
3379 JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong64_t>);
3380}
3381
3382////////////////////////////////////////////////////////////////////////////////
3383/// Write array of Float_t to buffer
3384
3386{
3387 JsonWriteFastArray(f, n, "Float32", &TBufferJSON::JsonWriteArrayCompress<Float_t>);
3388}
3389
3390////////////////////////////////////////////////////////////////////////////////
3391/// Write array of Double_t to buffer
3392
3394{
3395 JsonWriteFastArray(d, n, "Float64", &TBufferJSON::JsonWriteArrayCompress<Double_t>);
3396}
3397
3398////////////////////////////////////////////////////////////////////////////////
3399/// Recall TBuffer function to avoid gcc warning message
3400
3401void TBufferJSON::WriteFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer * /* streamer */)
3402{
3403 if (gDebug > 2)
3404 Info("WriteFastArray", "void *start cl:%s n:%d", cl ? cl->GetName() : "---", n);
3405
3406 // if (streamer) {
3407 // JsonDisablePostprocessing();
3408 // (*streamer)(*this, start, 0);
3409 // return;
3410 // }
3411
3412 if (n < 0) {
3413 // special handling of empty StreamLoop
3414 AppendOutput("null");
3416 } else {
3417
3418 char *obj = (char *)start;
3419 if (!n)
3420 n = 1;
3421 int size = cl->Size();
3422
3423 TArrayIndexProducer indexes(Stack()->fElem, n, fArraySepar.Data());
3424
3425 if (indexes.IsArray()) {
3427 AppendOutput(indexes.GetBegin());
3428 }
3429
3430 for (Int_t j = 0; j < n; j++, obj += size) {
3431
3432 if (j > 0)
3433 AppendOutput(indexes.NextSeparator());
3434
3435 JsonWriteObject(obj, cl, kFALSE);
3436
3437 if (indexes.IsArray() && (fValue.Length() > 0)) {
3439 fValue.Clear();
3440 }
3441 }
3442
3443 if (indexes.IsArray())
3444 AppendOutput(indexes.GetEnd());
3445 }
3446
3447 if (Stack()->fIndx)
3448 AppendOutput(Stack()->fIndx->NextSeparator());
3449}
3450
3451////////////////////////////////////////////////////////////////////////////////
3452/// Recall TBuffer function to avoid gcc warning message
3453
3454Int_t TBufferJSON::WriteFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc,
3455 TMemberStreamer * /* streamer */)
3456{
3457 if (gDebug > 2)
3458 Info("WriteFastArray", "void **startp cl:%s n:%d", cl->GetName(), n);
3459
3460 // if (streamer) {
3461 // JsonDisablePostprocessing();
3462 // (*streamer)(*this, (void *)start, 0);
3463 // return 0;
3464 // }
3465
3466 if (n <= 0)
3467 return 0;
3468
3469 Int_t res = 0;
3470
3471 TArrayIndexProducer indexes(Stack()->fElem, n, fArraySepar.Data());
3472
3473 if (indexes.IsArray()) {
3475 AppendOutput(indexes.GetBegin());
3476 }
3477
3478 for (Int_t j = 0; j < n; j++) {
3479
3480 if (j > 0)
3481 AppendOutput(indexes.NextSeparator());
3482
3483 if (!isPreAlloc) {
3484 res |= WriteObjectAny(start[j], cl);
3485 } else {
3486 if (!start[j])
3487 start[j] = (const_cast<TClass *>(cl))->New();
3488 // ((TClass*)cl)->Streamer(start[j],*this);
3489 JsonWriteObject(start[j], cl, kFALSE);
3490 }
3491
3492 if (indexes.IsArray() && (fValue.Length() > 0)) {
3494 fValue.Clear();
3495 }
3496 }
3497
3498 if (indexes.IsArray())
3499 AppendOutput(indexes.GetEnd());
3500
3501 if (Stack()->fIndx)
3502 AppendOutput(Stack()->fIndx->NextSeparator());
3503
3504 return res;
3505}
3506
3507////////////////////////////////////////////////////////////////////////////////
3508/// stream object to/from buffer
3509
3510void TBufferJSON::StreamObject(void *obj, const TClass *cl, const TClass * /* onfileClass */)
3511{
3512 if (gDebug > 3)
3513 Info("StreamObject", "Class: %s", (cl ? cl->GetName() : "none"));
3514
3515 if (IsWriting())
3516 JsonWriteObject(obj, cl);
3517 else
3518 JsonReadObject(obj, cl);
3519}
3520
3521////////////////////////////////////////////////////////////////////////////////
3522/// Template function to read basic value from JSON
3523
3524template <typename T>
3526{
3527 value = Stack()->GetStlNode()->get<T>();
3528}
3529
3530////////////////////////////////////////////////////////////////////////////////
3531/// Reads Bool_t value from buffer
3532
3534{
3535 JsonReadBasic(val);
3536}
3537
3538////////////////////////////////////////////////////////////////////////////////
3539/// Reads Char_t value from buffer
3540
3542{
3543 if (!Stack()->fValues.empty())
3544 val = (Char_t)Stack()->PopIntValue();
3545 else
3546 val = Stack()->GetStlNode()->get<Char_t>();
3547}
3548
3549////////////////////////////////////////////////////////////////////////////////
3550/// Reads UChar_t value from buffer
3551
3553{
3554 JsonReadBasic(val);
3555}
3556
3557////////////////////////////////////////////////////////////////////////////////
3558/// Reads Short_t value from buffer
3559
3561{
3562 JsonReadBasic(val);
3563}
3564
3565////////////////////////////////////////////////////////////////////////////////
3566/// Reads UShort_t value from buffer
3567
3569{
3570 JsonReadBasic(val);
3571}
3572
3573////////////////////////////////////////////////////////////////////////////////
3574/// Reads Int_t value from buffer
3575
3577{
3578 if (!Stack()->fValues.empty())
3579 val = Stack()->PopIntValue();
3580 else
3581 JsonReadBasic(val);
3582}
3583
3584////////////////////////////////////////////////////////////////////////////////
3585/// Reads UInt_t value from buffer
3586
3588{
3589 JsonReadBasic(val);
3590}
3591
3592////////////////////////////////////////////////////////////////////////////////
3593/// Reads Long_t value from buffer
3594
3596{
3597 JsonReadBasic(val);
3598}
3599
3600////////////////////////////////////////////////////////////////////////////////
3601/// Reads ULong_t value from buffer
3602
3604{
3605 JsonReadBasic(val);
3606}
3607
3608////////////////////////////////////////////////////////////////////////////////
3609/// Reads Long64_t value from buffer
3610
3612{
3613 JsonReadBasic(val);
3614}
3615
3616////////////////////////////////////////////////////////////////////////////////
3617/// Reads ULong64_t value from buffer
3618
3620{
3621 JsonReadBasic(val);
3622}
3623
3624////////////////////////////////////////////////////////////////////////////////
3625/// Reads Float_t value from buffer
3626
3628{
3629 nlohmann::json *json = Stack()->GetStlNode();
3630 if (json->is_null())
3631 val = std::numeric_limits<Float_t>::quiet_NaN();
3632 else
3633 val = json->get<Float_t>();
3634}
3635
3636////////////////////////////////////////////////////////////////////////////////
3637/// Reads Double_t value from buffer
3638
3640{
3641 nlohmann::json *json = Stack()->GetStlNode();
3642 if (json->is_null())
3643 val = std::numeric_limits<Double_t>::quiet_NaN();
3644 else
3645 val = json->get<Double_t>();
3646}
3647
3648////////////////////////////////////////////////////////////////////////////////
3649/// Reads array of characters from buffer
3650
3652{
3653 Error("ReadCharP", "Not implemented");
3654}
3655
3656////////////////////////////////////////////////////////////////////////////////
3657/// Reads a TString
3658
3660{
3661 std::string str;
3662 JsonReadBasic(str);
3663 val = str.c_str();
3664}
3665
3666////////////////////////////////////////////////////////////////////////////////
3667/// Reads a std::string
3668
3669void TBufferJSON::ReadStdString(std::string *val)
3670{
3671 JsonReadBasic(*val);
3672}
3673
3674////////////////////////////////////////////////////////////////////////////////
3675/// Reads a char* string
3676
3678{
3679 std::string str;
3680 JsonReadBasic(str);
3681
3682 if (s) {
3683 delete[] s;
3684 s = nullptr;
3685 }
3686
3687 std::size_t nch = str.length();
3688 if (nch > 0) {
3689 s = new char[nch + 1];
3690 memcpy(s, str.c_str(), nch);
3691 s[nch] = 0;
3692 }
3693}
3694
3695////////////////////////////////////////////////////////////////////////////////
3696/// Writes Bool_t value to buffer
3697
3699{
3700 JsonPushValue();
3702}
3703
3704////////////////////////////////////////////////////////////////////////////////
3705/// Writes Char_t value to buffer
3706
3708{
3709 JsonPushValue();
3711}
3712
3713////////////////////////////////////////////////////////////////////////////////
3714/// Writes UChar_t value to buffer
3715
3717{
3718 JsonPushValue();
3720}
3721
3722////////////////////////////////////////////////////////////////////////////////
3723/// Writes Short_t value to buffer
3724
3726{
3727 JsonPushValue();
3729}
3730
3731////////////////////////////////////////////////////////////////////////////////
3732/// Writes UShort_t value to buffer
3733
3735{
3736 JsonPushValue();
3738}
3739
3740////////////////////////////////////////////////////////////////////////////////
3741/// Writes Int_t value to buffer
3742
3744{
3745 JsonPushValue();
3746 JsonWriteBasic(i);
3747}
3748
3749////////////////////////////////////////////////////////////////////////////////
3750/// Writes UInt_t value to buffer
3751
3753{
3754 JsonPushValue();
3755 JsonWriteBasic(i);
3756}
3757
3758////////////////////////////////////////////////////////////////////////////////
3759/// Writes Long_t value to buffer
3760
3762{
3763 JsonPushValue();
3765}
3766
3767////////////////////////////////////////////////////////////////////////////////
3768/// Writes ULong_t value to buffer
3769
3771{
3772 JsonPushValue();
3774}
3775
3776////////////////////////////////////////////////////////////////////////////////
3777/// Writes Long64_t value to buffer
3778
3780{
3781 JsonPushValue();
3783}
3784
3785////////////////////////////////////////////////////////////////////////////////
3786/// Writes ULong64_t value to buffer
3787
3789{
3790 JsonPushValue();
3792}
3793
3794////////////////////////////////////////////////////////////////////////////////
3795/// Writes Float_t value to buffer
3796
3798{
3799 JsonPushValue();
3801}
3802
3803////////////////////////////////////////////////////////////////////////////////
3804/// Writes Double_t value to buffer
3805
3807{
3808 JsonPushValue();
3810}
3811
3812////////////////////////////////////////////////////////////////////////////////
3813/// Writes array of characters to buffer
3814
3816{
3817 JsonPushValue();
3818
3820}
3821
3822////////////////////////////////////////////////////////////////////////////////
3823/// Writes a TString
3824
3826{
3827 JsonPushValue();
3828
3829 JsonWriteConstChar(s.Data(), s.Length());
3830}
3831
3832////////////////////////////////////////////////////////////////////////////////
3833/// Writes a std::string
3834
3835void TBufferJSON::WriteStdString(const std::string *s)
3836{
3837 JsonPushValue();
3838
3839 if (s)
3840 JsonWriteConstChar(s->c_str(), s->length());
3841 else
3842 JsonWriteConstChar("", 0);
3843}
3844
3845////////////////////////////////////////////////////////////////////////////////
3846/// Writes a char*
3847
3849{
3850 JsonPushValue();
3851
3853}
3854
3855////////////////////////////////////////////////////////////////////////////////
3856/// converts Char_t to string and add to json value buffer
3857
3859{
3860 char buf[50];
3861 snprintf(buf, sizeof(buf), "%d", value);
3862 fValue.Append(buf);
3863}
3864
3865////////////////////////////////////////////////////////////////////////////////
3866/// converts Short_t to string and add to json value buffer
3867
3869{
3870 char buf[50];
3871 snprintf(buf, sizeof(buf), "%hd", value);
3872 fValue.Append(buf);
3873}
3874
3875////////////////////////////////////////////////////////////////////////////////
3876/// converts Int_t to string and add to json value buffer
3877
3879{
3880 char buf[50];
3881 snprintf(buf, sizeof(buf), "%d", value);
3882 fValue.Append(buf);
3883}
3884
3885////////////////////////////////////////////////////////////////////////////////
3886/// converts Long_t to string and add to json value buffer
3887
3889{
3890 char buf[50];
3891 snprintf(buf, sizeof(buf), "%ld", value);
3892 fValue.Append(buf);
3893}
3894
3895////////////////////////////////////////////////////////////////////////////////
3896/// converts Long64_t to string and add to json value buffer
3897
3899{
3900 fValue.Append(std::to_string(value).c_str());
3901}
3902
3903////////////////////////////////////////////////////////////////////////////////
3904/// converts Float_t to string and add to json value buffer
3905
3907{
3908 if (std::isinf(value)) {
3909 fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3910 } else if (std::isnan(value)) {
3911 fValue.Append("null");
3912 } else {
3913 char buf[200];
3914 ConvertFloat(value, buf, sizeof(buf));
3915 fValue.Append(buf);
3916 }
3917}
3918
3919////////////////////////////////////////////////////////////////////////////////
3920/// converts Double_t to string and add to json value buffer
3921
3923{
3924 if (std::isinf(value)) {
3925 fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3926 } else if (std::isnan(value)) {
3927 fValue.Append("null");
3928 } else {
3929 char buf[200];
3930 ConvertDouble(value, buf, sizeof(buf));
3931 fValue.Append(buf);
3932 }
3933}
3934
3935////////////////////////////////////////////////////////////////////////////////
3936/// converts Bool_t to string and add to json value buffer
3937
3939{
3940 fValue.Append(value ? "true" : "false");
3941}
3942
3943////////////////////////////////////////////////////////////////////////////////
3944/// converts UChar_t to string and add to json value buffer
3945
3947{
3948 char buf[50];
3949 snprintf(buf, sizeof(buf), "%u", value);
3950 fValue.Append(buf);
3951}
3952
3953////////////////////////////////////////////////////////////////////////////////
3954/// converts UShort_t to string and add to json value buffer
3955
3957{
3958 char buf[50];
3959 snprintf(buf, sizeof(buf), "%hu", value);
3960 fValue.Append(buf);
3961}
3962
3963////////////////////////////////////////////////////////////////////////////////
3964/// converts UInt_t to string and add to json value buffer
3965
3967{
3968 char buf[50];
3969 snprintf(buf, sizeof(buf), "%u", value);
3970 fValue.Append(buf);
3971}
3972
3973////////////////////////////////////////////////////////////////////////////////
3974/// converts ULong_t to string and add to json value buffer
3975
3977{
3978 char buf[50];
3979 snprintf(buf, sizeof(buf), "%lu", value);
3980 fValue.Append(buf);
3981}
3982
3983////////////////////////////////////////////////////////////////////////////////
3984/// converts ULong64_t to string and add to json value buffer
3985
3987{
3988 fValue.Append(std::to_string(value).c_str());
3989}
3990
3991////////////////////////////////////////////////////////////////////////////////
3992/// writes string value, processing all kind of special characters
3993
3994void TBufferJSON::JsonWriteConstChar(const char *value, Int_t len, const char * /* typname */)
3995{
3996 if (!value) {
3997
3998 fValue.Append("\"\"");
3999
4000 } else {
4001
4002 fValue.Append("\"");
4003
4004 if (len < 0)
4005 len = strlen(value);
4006
4007 for (Int_t n = 0; n < len; n++) {
4008 char c = value[n];
4009 if (c == 0)
4010 break;
4011 switch (c) {
4012 case '\n': fValue.Append("\\n"); break;
4013 case '\t': fValue.Append("\\t"); break;
4014 case '\"': fValue.Append("\\\""); break;
4015 case '\\': fValue.Append("\\\\"); break;
4016 case '\b': fValue.Append("\\b"); break;
4017 case '\f': fValue.Append("\\f"); break;
4018 case '\r': fValue.Append("\\r"); break;
4019 case '/': fValue.Append("\\/"); break;
4020 default:
4021 if ((c > 31) && (c < 127))
4022 fValue.Append(c);
4023 else
4024 fValue.Append(TString::Format("\\u%04x", (unsigned)c));
4025 }
4026 }
4027
4028 fValue.Append("\"");
4029 }
4030}
4031
4032////////////////////////////////////////////////////////////////////////////////
4033/// Read data of base class.
4034
4036{
4037 if (elem->GetClassPointer() == TObject::Class()) {
4039 } else {
4040 TBufferText::ReadBaseClass(start, elem);
4041 }
4042}
void Class()
Definition: Class.C:29
#define R__ALWAYS_INLINE
Definition: RConfig.hxx:570
#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:38
int Int_t
Definition: RtypesCore.h:43
short Version_t
Definition: RtypesCore.h:63
unsigned char UChar_t
Definition: RtypesCore.h:36
char Char_t
Definition: RtypesCore.h:31
const Bool_t kFALSE
Definition: RtypesCore.h:90
unsigned long ULong_t
Definition: RtypesCore.h:53
long Long_t
Definition: RtypesCore.h:52
bool Bool_t
Definition: RtypesCore.h:61
short Short_t
Definition: RtypesCore.h:37
double Double_t
Definition: RtypesCore.h:57
R__EXTERN Int_t gDebug
Definition: RtypesCore.h:117
long long Long64_t
Definition: RtypesCore.h:71
unsigned long long ULong64_t
Definition: RtypesCore.h:72
float Float_t
Definition: RtypesCore.h:55
const Bool_t kTRUE
Definition: RtypesCore.h:89
#define ClassImp(name)
Definition: Rtypes.h:361
@ 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:406
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:131
static TString Encode(const char *data)
Transform data into a null terminated base64 string.
Definition: TBase64.cxx:107
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...
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
@ 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
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:80
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition: TClass.cxx:2866
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4941
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5363
TList * GetListOfRealData() const
Definition: TClass.h:450
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5667
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5901
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2771
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2877
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=0) const
Definition: TClass.h:602
Version_t GetClassVersion() const
Definition: TClass.h:417
TClass * GetActualClass(const void *object) const
Return a pointer the the real class of the object.
Definition: TClass.cxx:2588
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3471
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:2948
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:76
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:54
TObject * GetValue(const char *keyname) const
Returns a pointer to the value associated with keyname as name of the key.
Definition: TMap.cxx:236
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Int_t IndexOf(const TObject *obj) const
Definition: TObjArray.cxx:605
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:877
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:891
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:865
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:46
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<> json
default JSON class
Definition: REveElement.hxx:88
const char * cnt
Definition: TXMLSetup.cxx:74
auto * l
Definition: textangle.C:4
#define decode(ptr, otri)
Definition: triangle.c:912