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