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