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/// compact parameter defines compactness of produced JSON (from 0 to 3)
729/// arraylen (when specified) is array length for this data member, //[fN] case
730
732{
733 if (!ptr || !member)
734 return TString("null");
735
736 Bool_t stlstring = !strcmp(member->GetTrueTypeName(), "string");
737
738 Int_t isstl = member->IsSTLContainer();
739
740 TClass *mcl = member->IsBasic() ? nullptr : gROOT->GetClass(member->GetTypeName());
741
742 if (mcl && (mcl != TString::Class()) && !stlstring && !isstl && (mcl->GetBaseClassOffset(TArray::Class()) != 0) &&
743 (arraylen <= 0) && (member->GetArrayDim() == 0))
745
746 TBufferJSON buf;
747
748 buf.SetCompact(compact);
749
750 return buf.JsonWriteMember(ptr, member, mcl, arraylen);
751}
752
753////////////////////////////////////////////////////////////////////////////////
754/// Convert object into JSON and store in text file
755/// Returns size of the produce file
756/// Used in TObject::SaveAs()
757
758Int_t TBufferJSON::ExportToFile(const char *filename, const TObject *obj, const char *option)
759{
760 if (!obj || !filename || (*filename == 0))
761 return 0;
762
763 Int_t compact = strstr(filename, ".json.gz") ? 3 : 0;
764 if (option && (*option >= '0') && (*option <= '3'))
766
768
769 std::ofstream ofs(filename);
770
771 if (strstr(filename, ".json.gz")) {
772 const char *objbuf = json.Data();
773 Long_t objlen = json.Length();
774
775 unsigned long objcrc = R__crc32(0, NULL, 0);
776 objcrc = R__crc32(objcrc, (const unsigned char *)objbuf, objlen);
777
778 // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
779 Int_t buflen = 10 + objlen + 8;
780 if (buflen < 512)
781 buflen = 512;
782
783 char *buffer = (char *)malloc(buflen);
784 if (!buffer)
785 return 0; // failure
786
787 char *bufcur = buffer;
788
789 *bufcur++ = 0x1f; // first byte of ZIP identifier
790 *bufcur++ = 0x8b; // second byte of ZIP identifier
791 *bufcur++ = 0x08; // compression method
792 *bufcur++ = 0x00; // FLAG - empty, no any file names
793 *bufcur++ = 0; // empty timestamp
794 *bufcur++ = 0; //
795 *bufcur++ = 0; //
796 *bufcur++ = 0; //
797 *bufcur++ = 0; // XFL (eXtra FLags)
798 *bufcur++ = 3; // OS 3 means Unix
799 // strcpy(bufcur, "item.json");
800 // bufcur += strlen("item.json")+1;
801
802 char dummy[8];
803 memcpy(dummy, bufcur - 6, 6);
804
805 // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
806 unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, (char *)objbuf, objlen);
807
808 memcpy(bufcur - 6, dummy, 6);
809
810 bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
811
812 *bufcur++ = objcrc & 0xff; // CRC32
813 *bufcur++ = (objcrc >> 8) & 0xff;
814 *bufcur++ = (objcrc >> 16) & 0xff;
815 *bufcur++ = (objcrc >> 24) & 0xff;
816
817 *bufcur++ = objlen & 0xff; // original data length
818 *bufcur++ = (objlen >> 8) & 0xff; // original data length
819 *bufcur++ = (objlen >> 16) & 0xff; // original data length
820 *bufcur++ = (objlen >> 24) & 0xff; // original data length
821
822 ofs.write(buffer, bufcur - buffer);
823
824 free(buffer);
825 } else {
826 ofs << json.Data();
827 }
828
829 ofs.close();
830
831 return json.Length();
832}
833
834////////////////////////////////////////////////////////////////////////////////
835/// Convert object into JSON and store in text file
836/// Returns size of the produce file
837
838Int_t TBufferJSON::ExportToFile(const char *filename, const void *obj, const TClass *cl, const char *option)
839{
840 if (!obj || !cl || !filename || (*filename == 0))
841 return 0;
842
843 Int_t compact = strstr(filename, ".json.gz") ? 3 : 0;
844 if (option && (*option >= '0') && (*option <= '3'))
846
848
849 std::ofstream ofs(filename);
850
851 if (strstr(filename, ".json.gz")) {
852 const char *objbuf = json.Data();
853 Long_t objlen = json.Length();
854
855 unsigned long objcrc = R__crc32(0, NULL, 0);
856 objcrc = R__crc32(objcrc, (const unsigned char *)objbuf, objlen);
857
858 // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
859 Int_t buflen = 10 + objlen + 8;
860 if (buflen < 512)
861 buflen = 512;
862
863 char *buffer = (char *)malloc(buflen);
864 if (!buffer)
865 return 0; // failure
866
867 char *bufcur = buffer;
868
869 *bufcur++ = 0x1f; // first byte of ZIP identifier
870 *bufcur++ = 0x8b; // second byte of ZIP identifier
871 *bufcur++ = 0x08; // compression method
872 *bufcur++ = 0x00; // FLAG - empty, no any file names
873 *bufcur++ = 0; // empty timestamp
874 *bufcur++ = 0; //
875 *bufcur++ = 0; //
876 *bufcur++ = 0; //
877 *bufcur++ = 0; // XFL (eXtra FLags)
878 *bufcur++ = 3; // OS 3 means Unix
879 // strcpy(bufcur, "item.json");
880 // bufcur += strlen("item.json")+1;
881
882 char dummy[8];
883 memcpy(dummy, bufcur - 6, 6);
884
885 // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
886 unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, (char *)objbuf, objlen);
887
888 memcpy(bufcur - 6, dummy, 6);
889
890 bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
891
892 *bufcur++ = objcrc & 0xff; // CRC32
893 *bufcur++ = (objcrc >> 8) & 0xff;
894 *bufcur++ = (objcrc >> 16) & 0xff;
895 *bufcur++ = (objcrc >> 24) & 0xff;
896
897 *bufcur++ = objlen & 0xff; // original data length
898 *bufcur++ = (objlen >> 8) & 0xff; // original data length
899 *bufcur++ = (objlen >> 16) & 0xff; // original data length
900 *bufcur++ = (objlen >> 24) & 0xff; // original data length
901
902 ofs.write(buffer, bufcur - buffer);
903
904 free(buffer);
905 } else {
906 ofs << json.Data();
907 }
908
909 ofs.close();
910
911 return json.Length();
912}
913
914////////////////////////////////////////////////////////////////////////////////
915/// Read TObject-based class from JSON, produced by ConvertToJSON() method.
916/// If object does not inherit from TObject class, return 0.
917
919{
920 TClass *cl = nullptr;
921 void *obj = ConvertFromJSONAny(str, &cl);
922
923 if (!cl || !obj)
924 return nullptr;
925
927
928 if (delta < 0) {
929 cl->Destructor(obj);
930 return nullptr;
931 }
932
933 return (TObject *)(((char *)obj) + delta);
934}
935
936////////////////////////////////////////////////////////////////////////////////
937/// Read object from JSON
938/// In class pointer (if specified) read class is returned
939/// One must specify expected object class, if it is TArray or STL container
940
941void *TBufferJSON::ConvertFromJSONAny(const char *str, TClass **cl)
942{
944
945 return buf.RestoreObject(str, cl);
946}
947
948////////////////////////////////////////////////////////////////////////////////
949/// Read object from JSON
950/// In class pointer (if specified) read class is returned
951/// One must specify expected object class, if it is TArray or STL container
952
954{
955 if (!IsReading())
956 return nullptr;
957
958 nlohmann::json docu = nlohmann::json::parse(json_str);
959
960 if (docu.is_null() || (!docu.is_object() && !docu.is_array()))
961 return nullptr;
962
963 TClass *objClass = nullptr;
964
965 if (cl) {
966 objClass = *cl; // this is class which suppose to created when reading JSON
967 *cl = nullptr;
968 }
969
970 InitMap();
971
972 PushStack(0, &docu);
973
974 void *obj = JsonReadObject(nullptr, objClass, cl);
975
976 PopStack();
977
978 return obj;
979}
980
981////////////////////////////////////////////////////////////////////////////////
982/// Read objects from JSON, one can reuse existing object
983
985{
986 if (!expectedClass)
987 return nullptr;
988
989 TClass *resClass = const_cast<TClass *>(expectedClass);
990
991 void *res = ConvertFromJSONAny(str, &resClass);
992
993 if (!res || !resClass)
994 return nullptr;
995
996 if (resClass == expectedClass)
997 return res;
998
999 Int_t offset = resClass->GetBaseClassOffset(expectedClass);
1000 if (offset < 0) {
1001 ::Error("TBufferJSON::ConvertFromJSONChecked", "expected class %s is not base for read class %s",
1002 expectedClass->GetName(), resClass->GetName());
1003 resClass->Destructor(res);
1004 return nullptr;
1005 }
1006
1007 return (char *)res - offset;
1008}
1009
1010////////////////////////////////////////////////////////////////////////////////
1011/// Convert single data member to JSON structures
1012/// Returns string with converted member
1013
1015{
1016 if (!member)
1017 return "null";
1018
1019 if (gDebug > 2)
1020 Info("JsonWriteMember", "Write member %s type %s ndim %d", member->GetName(), member->GetTrueTypeName(),
1021 member->GetArrayDim());
1022
1023 Int_t tid = member->GetDataType() ? member->GetDataType()->GetType() : kNoType_t;
1024 if (strcmp(member->GetTrueTypeName(), "const char*") == 0)
1025 tid = kCharStar;
1026 else if (!member->IsBasic() || (tid == kOther_t) || (tid == kVoid_t))
1027 tid = kNoType_t;
1028
1029 if (!ptr)
1030 return (tid == kCharStar) ? "\"\"" : "null";
1031
1032 PushStack(0);
1033 fValue.Clear();
1034
1035 if (tid != kNoType_t) {
1036
1038
1039 Int_t shift = 1;
1040
1041 if (indx.IsArray() && (tid == kChar_t))
1042 shift = indx.ReduceDimension();
1043
1044 char *ppp = (char *)ptr;
1045
1046 if (indx.IsArray())
1047 fOutBuffer.Append(indx.GetBegin());
1048
1049 do {
1050 fValue.Clear();
1051
1052 switch (tid) {
1053 case kChar_t:
1054 if (shift > 1)
1055 JsonWriteConstChar((Char_t *)ppp, shift);
1056 else
1057 JsonWriteBasic(*((Char_t *)ppp));
1058 break;
1059 case kShort_t: JsonWriteBasic(*((Short_t *)ppp)); break;
1060 case kInt_t: JsonWriteBasic(*((Int_t *)ppp)); break;
1061 case kLong_t: JsonWriteBasic(*((Long_t *)ppp)); break;
1062 case kFloat_t: JsonWriteBasic(*((Float_t *)ppp)); break;
1063 case kCounter: JsonWriteBasic(*((Int_t *)ppp)); break;
1064 case kCharStar: JsonWriteConstChar((Char_t *)ppp); break;
1065 case kDouble_t: JsonWriteBasic(*((Double_t *)ppp)); break;
1066 case kDouble32_t: JsonWriteBasic(*((Double_t *)ppp)); break;
1067 case kchar: JsonWriteBasic(*((char *)ppp)); break;
1068 case kUChar_t: JsonWriteBasic(*((UChar_t *)ppp)); break;
1069 case kUShort_t: JsonWriteBasic(*((UShort_t *)ppp)); break;
1070 case kUInt_t: JsonWriteBasic(*((UInt_t *)ppp)); break;
1071 case kULong_t: JsonWriteBasic(*((ULong_t *)ppp)); break;
1072 case kBits: JsonWriteBasic(*((UInt_t *)ppp)); break;
1073 case kLong64_t: JsonWriteBasic(*((Long64_t *)ppp)); break;
1074 case kULong64_t: JsonWriteBasic(*((ULong64_t *)ppp)); break;
1075 case kBool_t: JsonWriteBasic(*((Bool_t *)ppp)); break;
1076 case kFloat16_t: JsonWriteBasic(*((Float_t *)ppp)); break;
1077 case kOther_t:
1078 case kVoid_t: break;
1079 }
1080
1082 if (indx.IsArray())
1083 fOutBuffer.Append(indx.NextSeparator());
1084
1085 ppp += shift * member->GetUnitSize();
1086
1087 } while (!indx.IsDone());
1088
1090
1091 } else if (memberClass == TString::Class()) {
1092 TString *str = (TString *)ptr;
1093 JsonWriteConstChar(str ? str->Data() : nullptr);
1094 } else if ((member->IsSTLContainer() == ROOT::kSTLvector) || (member->IsSTLContainer() == ROOT::kSTLlist) ||
1095 (member->IsSTLContainer() == ROOT::kSTLforwardlist)) {
1096
1097 if (memberClass)
1098 memberClass->Streamer((void *)ptr, *this);
1099 else
1100 fValue = "[]";
1101
1102 if (fValue == "0")
1103 fValue = "[]";
1104
1105 } else if (memberClass && memberClass->GetBaseClassOffset(TArray::Class()) == 0) {
1106 TArray *arr = (TArray *)ptr;
1107 if (arr && (arr->GetSize() > 0)) {
1108 arr->Streamer(*this);
1109 // WriteFastArray(arr->GetArray(), arr->GetSize());
1110 if (Stack()->fValues.size() > 1) {
1111 Warning("TBufferJSON", "When streaming TArray, more than 1 object in the stack, use second item");
1112 fValue = Stack()->fValues[1].c_str();
1113 }
1114 } else
1115 fValue = "[]";
1116 } else if (memberClass && !strcmp(memberClass->GetName(), "string")) {
1117 // here value contains quotes, stack can be ignored
1118 memberClass->Streamer((void *)ptr, *this);
1119 }
1120 PopStack();
1121
1122 if (fValue.Length())
1123 return fValue;
1124
1125 if (!memberClass || (member->GetArrayDim() > 0) || (arraylen > 0))
1126 return "<not supported>";
1127
1129}
1130
1131////////////////////////////////////////////////////////////////////////////////
1132/// add new level to the structures stack
1133
1135{
1136 auto next = new TJSONStackObj();
1137 next->fLevel = inclevel;
1138 if (IsReading()) {
1139 next->fNode = (nlohmann::json *)readnode;
1140 } else if (fStack.size() > 0) {
1141 auto prev = Stack();
1142 next->fLevel += prev->fLevel;
1143 next->fMemberPtr = prev->fMemberPtr;
1144 }
1145 fStack.emplace_back(next);
1146 return next;
1147}
1148
1149////////////////////////////////////////////////////////////////////////////////
1150/// remove one level from stack
1151
1153{
1154 if (fStack.size() > 0)
1155 fStack.pop_back();
1156
1157 return fStack.size() > 0 ? fStack.back().get() : nullptr;
1158}
1159
1160////////////////////////////////////////////////////////////////////////////////
1161/// Append two string to the output JSON, normally separate by line break
1162
1163void TBufferJSON::AppendOutput(const char *line0, const char *line1)
1164{
1165 if (line0)
1167
1168 if (line1) {
1169 if (fCompact < 2)
1170 fOutput->Append("\n");
1171
1172 if (strlen(line1) > 0) {
1173 if (fCompact < 1) {
1174 if (Stack()->fLevel > 0)
1175 fOutput->Append(' ', Stack()->fLevel);
1176 }
1177 fOutput->Append(line1);
1178 }
1179 }
1180}
1181
1182////////////////////////////////////////////////////////////////////////////////
1183/// Start object element with typeinfo
1184
1186{
1187 auto stack = PushStack(2);
1188
1189 // new object started - assign own member counter
1190 stack->fMemberPtr = &stack->fMemberCnt;
1191
1192 if ((fTypeNameTag.Length() > 0) && !IsSkipClassInfo(obj_class)) {
1193 // stack->fMemberCnt = 1; // default value, comment out here
1194 AppendOutput("{", "\"");
1196 AppendOutput("\"");
1198 AppendOutput("\"");
1199 AppendOutput(obj_class->GetName());
1200 AppendOutput("\"");
1201 if (fTypeVersionTag.Length() > 0) {
1202 AppendOutput(stack->NextMemberSeparator(), "\"");
1204 AppendOutput("\"");
1206 AppendOutput(TString::Format("%d", (int)(info ? info->GetClassVersion() : obj_class->GetClassVersion())));
1207 }
1208 } else {
1209 stack->fMemberCnt = 0; // exclude typename
1210 AppendOutput("{");
1211 }
1212
1213 return stack;
1214}
1215
1216////////////////////////////////////////////////////////////////////////////////
1217/// Start new class member in JSON structures
1218
1220{
1221 const char *elem_name = nullptr;
1223
1224 switch (special_kind) {
1225 case 0:
1226 if (base_class) return;
1227 elem_name = elem->GetName();
1228 if (strcmp(elem_name,"fLineStyle") == 0)
1229 if ((strcmp(elem->GetTypeName(),"TString") == 0) && (strcmp(elem->GetFullName(),"fLineStyle[30]") == 0)) {
1230 auto st1 = fStack.at(fStack.size() - 2).get();
1231 if (st1->IsStreamerInfo() && st1->fInfo && (strcmp(st1->fInfo->GetName(),"TStyle") == 0))
1232 elem_name = "fLineStyles";
1233 }
1234 break;
1235 case TClassEdit::kVector: elem_name = "fVector"; break;
1236 case TClassEdit::kList: elem_name = "fList"; break;
1237 case TClassEdit::kForwardlist: elem_name = "fForwardlist"; break;
1238 case TClassEdit::kDeque: elem_name = "fDeque"; break;
1239 case TClassEdit::kMap: elem_name = "fMap"; break;
1240 case TClassEdit::kMultiMap: elem_name = "fMultiMap"; break;
1241 case TClassEdit::kSet: elem_name = "fSet"; break;
1242 case TClassEdit::kMultiSet: elem_name = "fMultiSet"; break;
1243 case TClassEdit::kUnorderedSet: elem_name = "fUnorderedSet"; break;
1244 case TClassEdit::kUnorderedMultiSet: elem_name = "fUnorderedMultiSet"; break;
1245 case TClassEdit::kUnorderedMap: elem_name = "fUnorderedMap"; break;
1246 case TClassEdit::kUnorderedMultiMap: elem_name = "fUnorderedMultiMap"; break;
1247 case TClassEdit::kBitSet: elem_name = "fBitSet"; break;
1248 case json_TArray: elem_name = "fArray"; break;
1249 case json_TString:
1250 case json_stdstring: elem_name = "fString"; break;
1251 }
1252
1253 if (!elem_name)
1254 return;
1255
1256 if (IsReading()) {
1257 nlohmann::json *json = Stack()->fNode;
1258
1259 if (json->count(elem_name) != 1) {
1260 Error("JsonStartElement", "Missing JSON structure for element %s", elem_name);
1261 } else {
1262 Stack()->fNode = &((*json)[elem_name]);
1263 if (special_kind == json_TArray) {
1264 Int_t len = Stack()->IsJsonArray();
1265 Stack()->PushIntValue(len > 0 ? len : 0);
1266 if (len < 0)
1267 Error("JsonStartElement", "Missing array when reading TArray class for element %s", elem->GetName());
1268 }
1269 if ((gDebug > 1) && base_class)
1270 Info("JsonStartElement", "Reading baseclass %s from element %s", base_class->GetName(), elem_name);
1271 }
1272
1273 } else {
1274 AppendOutput(Stack()->NextMemberSeparator(), "\"");
1276 AppendOutput("\"");
1278 }
1279}
1280
1281////////////////////////////////////////////////////////////////////////////////
1282/// disable post-processing of the code
1287
1288////////////////////////////////////////////////////////////////////////////////
1289/// return non-zero value when class has special handling in JSON
1290/// it is TCollection (-130), TArray (100), TString (110), std::string (120) and STL containers (1..6)
1291
1293{
1294 if (!cl)
1295 return 0;
1296
1297 Bool_t isarray = strncmp("TArray", cl->GetName(), 6) == 0;
1298 if (isarray)
1299 isarray = (const_cast<TClass *>(cl))->GetBaseClassOffset(TArray::Class()) == 0;
1300 if (isarray)
1301 return json_TArray;
1302
1303 // negative value used to indicate that collection stored as object
1304 if ((const_cast<TClass *>(cl))->GetBaseClassOffset(TCollection::Class()) == 0)
1305 return json_TCollection;
1306
1307 // special case for TString - it is saved as string in JSON
1308 if (cl == TString::Class())
1309 return json_TString;
1310
1311 bool isstd = TClassEdit::IsStdClass(cl->GetName());
1313 if (isstd)
1315 if (isstlcont > 0)
1316 return isstlcont;
1317
1318 // also special handling for STL string, which handled similar to TString
1319 if (isstd && !strcmp(cl->GetName(), "string"))
1320 return json_stdstring;
1321
1322 return 0;
1323}
1324
1325////////////////////////////////////////////////////////////////////////////////
1326/// Write object to buffer
1327/// If object was written before, only pointer will be stored
1328/// If check_map==kFALSE, object will be stored in any case and pointer will not be registered in the map
1329
1330void TBufferJSON::JsonWriteObject(const void *obj, const TClass *cl, Bool_t check_map)
1331{
1332 if (!cl)
1333 obj = nullptr;
1334
1335 if (gDebug > 0)
1336 Info("JsonWriteObject", "Object %p class %s check_map %s", obj, cl ? cl->GetName() : "null",
1337 check_map ? "true" : "false");
1338
1340
1342
1343 TJSONStackObj *stack = Stack();
1344
1345 if (stack && stack->fAccObjects && ((fValue.Length() > 0) || (stack->fValues.size() > 0))) {
1346 // accumulate data of super-object in stack
1347
1348 if (fValue.Length() > 0)
1349 stack->PushValue(fValue);
1350
1351 // redirect output to local buffer, use it later as value
1354 } else if ((special_kind <= 0) || (special_kind > json_TArray)) {
1355 // FIXME: later post processing should be active for all special classes, while they all keep output in the value
1359
1360 if ((fMapAsObject && (fStack.size()==1)) || (stack && stack->fElem && strstr(stack->fElem->GetTitle(), "JSON_object")))
1361 map_convert = 2; // mapped into normal object
1362 else
1363 map_convert = 1;
1364
1365 if (!cl->HasDictionary()) {
1366 Error("JsonWriteObject", "Cannot stream class %s without dictionary", cl->GetName());
1367 AppendOutput(map_convert == 1 ? "[]" : "null");
1368 goto post_process;
1369 }
1370 }
1371
1372 if (!obj) {
1373 AppendOutput("null");
1374 goto post_process;
1375 }
1376
1377 if (special_kind <= 0) {
1378 // add element name which should correspond to the object
1379 if (check_map) {
1381 if (refid > 0) {
1382 // old-style refs, coded into string like "$ref12"
1383 // AppendOutput(TString::Format("\"$ref:%u\"", iter->second));
1384 // new-style refs, coded into extra object {"$ref":12}, auto-detected by JSROOT 4.8 and higher
1385 AppendOutput(TString::Format("{\"$ref\":%u}", (unsigned)(refid - 1)));
1386 goto post_process;
1387 }
1388 MapObject(obj, cl, fJsonrCnt + 1); // +1 used
1389 }
1390
1391 fJsonrCnt++; // object counts required in dereferencing part
1392
1393 stack = JsonStartObjectWrite(cl);
1394
1395 } else if (map_convert == 2) {
1396 // special handling of map - it is object, but stored in the fValue
1397
1398 if (check_map) {
1400 if (refid > 0) {
1401 fValue.Form("{\"$ref\":%u}", (unsigned)(refid - 1));
1402 goto post_process;
1403 }
1404 MapObject(obj, cl, fJsonrCnt + 1); // +1 used
1405 }
1406
1407 fJsonrCnt++; // object counts required in dereferencing part
1408 stack = PushStack(0);
1409
1410 } else {
1411
1412 bool base64 = ((special_kind == TClassEdit::kVector) && stack && stack->fElem && strstr(stack->fElem->GetTitle(), "JSON_base64"));
1413
1414 // for array, string and STL collections different handling -
1415 // they not recognized at the end as objects in JSON
1416 stack = PushStack(0);
1417
1418 stack->fBase64 = base64;
1419 }
1420
1421 if (gDebug > 3)
1422 Info("JsonWriteObject", "Starting object %p write for class: %s", obj, cl->GetName());
1423
1425
1427 JsonWriteCollection((TCollection *)obj, cl);
1428 else
1429 (const_cast<TClass *>(cl))->Streamer((void *)obj, *this);
1430
1431 if (gDebug > 3)
1432 Info("JsonWriteObject", "Done object %p write for class: %s", obj, cl->GetName());
1433
1434 if (special_kind == json_TArray) {
1435 if (stack->fValues.size() != 1)
1436 Error("JsonWriteObject", "Problem when writing array");
1437 stack->fValues.clear();
1438 } else if ((special_kind == json_TString) || (special_kind == json_stdstring)) {
1439 if (stack->fValues.size() > 2)
1440 Error("JsonWriteObject", "Problem when writing TString or std::string");
1441 stack->fValues.clear();
1443 fValue.Clear();
1444 } else if ((special_kind > 0) && (special_kind < ROOT::kSTLend)) {
1445 // here make STL container processing
1446
1447 if (map_convert == 2) {
1448 // converting map into object
1449
1450 if (!stack->fValues.empty() && (fValue.Length() > 0))
1451 stack->PushValue(fValue);
1452
1453 const char *separ = (fCompact < 2) ? ", " : ",";
1454 const char *semi = (fCompact < 2) ? ": " : ":";
1455 bool first = true;
1456
1457 fValue = "{";
1458 if ((fTypeNameTag.Length() > 0) && !IsSkipClassInfo(cl)) {
1459 fValue.Append("\"");
1461 fValue.Append("\"");
1463 fValue.Append("\"");
1464 fValue.Append(cl->GetName());
1465 fValue.Append("\"");
1466 first = false;
1467 }
1468 for (Int_t k = 1; k < (int)stack->fValues.size() - 1; k += 2) {
1469 if (!first)
1471 first = false;
1472 fValue.Append(stack->fValues[k].c_str());
1474 fValue.Append(stack->fValues[k + 1].c_str());
1475 }
1476 fValue.Append("}");
1477 stack->fValues.clear();
1478 } else if (stack->fValues.empty()) {
1479 // empty container
1480 if (fValue != "0")
1481 Error("JsonWriteObject", "With empty stack fValue!=0");
1482 fValue = "[]";
1483 } else {
1484
1485 auto size = std::stoi(stack->fValues[0]);
1486
1487 bool trivial_format = false;
1488
1489 if ((stack->fValues.size() == 1) && ((size > 1) || ((fValue.Length() > 1) && (fValue[0]=='[')))) {
1490 // prevent case of vector<vector<value_class>>
1491 const auto proxy = cl->GetCollectionProxy();
1492 TClass *value_class = proxy ? proxy->GetValueClass() : nullptr;
1493 if (value_class && TClassEdit::IsStdClass(value_class->GetName()) && (value_class->GetCollectionType() != ROOT::kNotSTL))
1494 trivial_format = false;
1495 else
1496 trivial_format = true;
1497 }
1498
1499 if (trivial_format) {
1500 // case of simple vector, array already in the value
1501 stack->fValues.clear();
1502 if (fValue.Length() == 0) {
1503 Error("JsonWriteObject", "Empty value when it should contain something");
1504 fValue = "[]";
1505 }
1506
1507 } else {
1508 const char *separ = "[";
1509
1510 if (fValue.Length() > 0)
1511 stack->PushValue(fValue);
1512
1513 if ((size * 2 == (int) stack->fValues.size() - 1) && (map_convert > 0)) {
1514 // special handling for std::map.
1515 // Create entries like { '$pair': 'typename' , 'first' : key, 'second' : value }
1516 TString pairtype = cl->GetName();
1517 if (pairtype.Index("unordered_map<") == 0)
1518 pairtype.Replace(0, 14, "pair<");
1519 else if (pairtype.Index("unordered_multimap<") == 0)
1520 pairtype.Replace(0, 19, "pair<");
1521 else if (pairtype.Index("multimap<") == 0)
1522 pairtype.Replace(0, 9, "pair<");
1523 else if (pairtype.Index("map<") == 0)
1524 pairtype.Replace(0, 4, "pair<");
1525 else
1526 pairtype = "TPair";
1527 if (fTypeNameTag.Length() == 0)
1528 pairtype = "1";
1529 else
1530 pairtype = TString("\"") + pairtype + TString("\"");
1531 for (Int_t k = 1; k < (int) stack->fValues.size() - 1; k += 2) {
1534 // fJsonrCnt++; // do not add entry in the map, can conflict with objects inside values
1535 fValue.Append("{");
1536 fValue.Append("\"$pair\"");
1538 fValue.Append(pairtype.Data());
1540 fValue.Append("\"first\"");
1542 fValue.Append(stack->fValues[k].c_str());
1544 fValue.Append("\"second\"");
1546 fValue.Append(stack->fValues[k + 1].c_str());
1547 fValue.Append("}");
1548 }
1549 } else {
1550 // for most stl containers write just like blob, but skipping first element with size
1551 for (Int_t k = 1; k < (int) stack->fValues.size(); k++) {
1554 fValue.Append(stack->fValues[k].c_str());
1555 }
1556 }
1557
1558 fValue.Append("]");
1559 stack->fValues.clear();
1560 }
1561 }
1562 }
1563
1564 // reuse post-processing code for TObject or TRef
1565 PerformPostProcessing(stack, cl);
1566
1567 if ((special_kind == 0) && (!stack->fValues.empty() || (fValue.Length() > 0))) {
1568 if (gDebug > 0)
1569 Info("JsonWriteObject", "Create blob value for class %s", cl->GetName());
1570
1571 AppendOutput(fArraySepar.Data(), "\"_blob\"");
1573
1574 const char *separ = "[";
1575
1576 for (auto &elem: stack->fValues) {
1579 AppendOutput(elem.c_str());
1580 }
1581
1582 if (fValue.Length() > 0) {
1585 }
1586
1587 AppendOutput("]");
1588
1589 fValue.Clear();
1590 stack->fValues.clear();
1591 }
1592
1593 PopStack();
1594
1595 if ((special_kind <= 0))
1596 AppendOutput(nullptr, "}");
1597
1599
1600 if (fPrevOutput) {
1602 // for STL containers and TArray object in fValue itself
1603 if ((special_kind <= 0) || (special_kind > json_TArray))
1605 else if (fObjectOutput.Length() != 0)
1606 Error("JsonWriteObject", "Non-empty object output for special class %s", cl->GetName());
1607 }
1608}
1609
1610////////////////////////////////////////////////////////////////////////////////
1611/// store content of ROOT collection
1612
1614{
1615 AppendOutput(Stack()->NextMemberSeparator(), "\"name\"");
1617 AppendOutput("\"");
1618 AppendOutput(col->GetName());
1619 AppendOutput("\"");
1620 AppendOutput(Stack()->NextMemberSeparator(), "\"arr\"");
1622
1623 // collection treated as JS Array
1624 AppendOutput("[");
1625
1626 bool islist = col->InheritsFrom(TList::Class());
1627 TMap *map = nullptr;
1628 if (col->InheritsFrom(TMap::Class()))
1629 map = dynamic_cast<TMap *>(col);
1630
1631 TString sopt;
1632 if (islist) {
1633 sopt.Capacity(500);
1634 sopt = "[";
1635 }
1636
1637 TIter iter(col);
1638 TObject *obj;
1639 Bool_t first = kTRUE;
1640 while ((obj = iter()) != nullptr) {
1641 if (!first)
1643
1644 if (map) {
1645 // fJsonrCnt++; // do not account map pair as JSON object
1646 AppendOutput("{", "\"$pair\"");
1648 AppendOutput("\"TPair\"");
1649 AppendOutput(fArraySepar.Data(), "\"first\"");
1651 }
1652
1654
1655 if (map) {
1656 AppendOutput(fArraySepar.Data(), "\"second\"");
1659 AppendOutput("", "}");
1660 }
1661
1662 if (islist) {
1663 if (!first)
1664 sopt.Append(fArraySepar.Data());
1665 sopt.Append("\"");
1666 sopt.Append(iter.GetOption());
1667 sopt.Append("\"");
1668 }
1669
1670 first = kFALSE;
1671 }
1672
1673 AppendOutput("]");
1674
1675 if (islist) {
1676 sopt.Append("]");
1677 AppendOutput(Stack()->NextMemberSeparator(), "\"opt\"");
1679 AppendOutput(sopt.Data());
1680 }
1681 fValue.Clear();
1682}
1683
1684////////////////////////////////////////////////////////////////////////////////
1685/// read content of ROOT collection
1686
1688{
1689 if (!col)
1690 return;
1691
1692 TList *lst = nullptr;
1693 TMap *map = nullptr;
1694 TClonesArray *clones = nullptr;
1695 if (col->InheritsFrom(TList::Class()))
1696 lst = dynamic_cast<TList *>(col);
1697 else if (col->InheritsFrom(TMap::Class()))
1698 map = dynamic_cast<TMap *>(col);
1699 else if (col->InheritsFrom(TClonesArray::Class()))
1700 clones = dynamic_cast<TClonesArray *>(col);
1701
1702 nlohmann::json *json = Stack()->fNode;
1703
1704 std::string name = json->at("name");
1705 col->SetName(name.c_str());
1706
1707 nlohmann::json &arr = json->at("arr");
1708 int size = arr.size();
1709
1710 for (int n = 0; n < size; ++n) {
1711 nlohmann::json *subelem = &arr.at(n);
1712
1713 if (map)
1714 subelem = &subelem->at("first");
1715
1716 PushStack(0, subelem);
1717
1718 TClass *readClass = nullptr, *objClass = nullptr;
1719 void *subobj = nullptr;
1720
1721 if (clones) {
1722 if (n == 0) {
1723 if (!clones->GetClass() || (clones->GetSize() == 0)) {
1724 if (fTypeNameTag.Length() > 0) {
1725 clones->SetClass(subelem->at(fTypeNameTag.Data()).get<std::string>().c_str(), size);
1726 } else {
1727 Error("JsonReadCollection",
1728 "Cannot detect class name for TClonesArray - typename tag not configured");
1729 return;
1730 }
1731 } else if (size > clones->GetSize()) {
1732 Error("JsonReadCollection", "TClonesArray size %d smaller than required %d", clones->GetSize(), size);
1733 return;
1734 }
1735 }
1736 objClass = clones->GetClass();
1737 subobj = clones->ConstructedAt(n);
1738 }
1739
1741
1742 PopStack();
1743
1744 if (clones)
1745 continue;
1746
1747 if (!subobj || !readClass) {
1748 subobj = nullptr;
1749 } else if (readClass->GetBaseClassOffset(TObject::Class()) != 0) {
1750 Error("JsonReadCollection", "Try to add object %s not derived from TObject", readClass->GetName());
1751 subobj = nullptr;
1752 }
1753
1754 TObject *tobj = static_cast<TObject *>(subobj);
1755
1756 if (map) {
1757 PushStack(0, &arr.at(n).at("second"));
1758
1759 readClass = nullptr;
1760 void *subobj2 = JsonReadObject(nullptr, nullptr, &readClass);
1761
1762 PopStack();
1763
1764 if (!subobj2 || !readClass) {
1765 subobj2 = nullptr;
1766 } else if (readClass->GetBaseClassOffset(TObject::Class()) != 0) {
1767 Error("JsonReadCollection", "Try to add object %s not derived from TObject", readClass->GetName());
1768 subobj2 = nullptr;
1769 }
1770
1771 map->Add(tobj, static_cast<TObject *>(subobj2));
1772 } else if (lst) {
1773 std::string opt = json->at("opt").at(n).get<std::string>();
1774 lst->Add(tobj, opt.c_str());
1775 } else {
1776 // generic method, all kinds of TCollection should work
1777 col->Add(tobj);
1778 }
1779 }
1780}
1781
1782////////////////////////////////////////////////////////////////////////////////
1783/// Read object from current JSON node
1784
1786{
1787 if (readClass)
1788 *readClass = nullptr;
1789
1790 TJSONStackObj *stack = Stack();
1791
1792 Bool_t process_stl = stack->IsStl();
1793 nlohmann::json *json = stack->GetStlNode();
1794
1795 // check if null pointer
1796 if (json->is_null())
1797 return nullptr;
1798
1800
1801 // Extract pointer
1802 if (json->is_object() && (json->size() == 1) && (json->find("$ref") != json->end())) {
1803 unsigned refid = json->at("$ref").get<unsigned>();
1804
1805 void *ref_obj = nullptr;
1806 TClass *ref_cl = nullptr;
1807
1809
1810 if (!ref_obj || !ref_cl) {
1811 Error("JsonReadObject", "Fail to find object for reference %u", refid);
1812 return nullptr;
1813 }
1814
1815 if (readClass)
1816 *readClass = ref_cl;
1817
1818 if (gDebug > 2)
1819 Info("JsonReadObject", "Extract object reference %u %p cl:%s expects:%s", refid, ref_obj, ref_cl->GetName(),
1820 (objClass ? objClass->GetName() : "---"));
1821
1822 return ref_obj;
1823 }
1824
1825 // special case of strings - they do not create JSON object, but just string
1827 if (!obj)
1828 obj = objClass->New();
1829
1830 if (gDebug > 2)
1831 Info("JsonReadObject", "Read string from %s", json->dump().c_str());
1832
1834 *((std::string *)obj) = json->get<std::string>();
1835 else
1836 *((TString *)obj) = json->get<std::string>().c_str();
1837
1838 if (readClass)
1839 *readClass = const_cast<TClass *>(objClass);
1840
1841 return obj;
1842 }
1843
1844 Bool_t isBase = (stack->fElem && objClass) ? stack->fElem->IsBase() : kFALSE; // base class
1845
1846 if (isBase && (!obj || !objClass)) {
1847 Error("JsonReadObject", "No object when reading base class");
1848 return obj;
1849 }
1850
1851 Int_t map_convert = 0;
1854 map_convert = json->is_object() ? 2 : 1; // check if map was written as array or as object
1855
1856 if (objClass && !objClass->HasDictionary()) {
1857 Error("JsonReadObject", "Cannot stream class %s without dictionary", objClass->GetName());
1858 return obj;
1859 }
1860 }
1861
1862 // from now all operations performed with sub-element,
1863 // stack should be repaired at the end
1864 if (process_stl)
1865 stack = PushStack(0, json);
1866
1867 TClass *jsonClass = nullptr;
1869
1870 if ((special_kind == json_TArray) || ((special_kind > 0) && (special_kind < ROOT::kSTLend))) {
1871
1872 jsonClass = const_cast<TClass *>(objClass);
1873
1874 if (!obj)
1875 obj = jsonClass->New();
1876
1877 Int_t len = stack->IsJsonArray(json, map_convert == 2 ? fTypeNameTag.Data() : nullptr);
1878
1879 stack->PushIntValue(len > 0 ? len : 0);
1880
1881 if (len < 0) // should never happens
1882 Error("JsonReadObject", "Not array when expecting such %s", json->dump().c_str());
1883
1884 if (gDebug > 1)
1885 Info("JsonReadObject", "Reading special kind %d %s ptr %p", special_kind, objClass->GetName(), obj);
1886
1887 } else if (isBase) {
1888 // base class has special handling - no additional level and no extra refid
1889
1890 jsonClass = const_cast<TClass *>(objClass);
1891
1892 if (gDebug > 1)
1893 Info("JsonReadObject", "Reading baseclass %s ptr %p", objClass->GetName(), obj);
1894 } else {
1895
1896 if ((fTypeNameTag.Length() > 0) && (json->count(fTypeNameTag.Data()) > 0)) {
1897 std::string clname = json->at(fTypeNameTag.Data()).get<std::string>();
1899 if (!jsonClass)
1900 Error("JsonReadObject", "Cannot find class %s", clname.c_str());
1901 } else {
1902 // try to use class which is assigned by streamers - better than nothing
1903 jsonClass = const_cast<TClass *>(objClass);
1904 }
1905
1906 if (!jsonClass) {
1907 if (process_stl)
1908 PopStack();
1909 return obj;
1910 }
1911
1912 if ((fTypeVersionTag.Length() > 0) && (json->count(fTypeVersionTag.Data()) > 0))
1913 jsonClassVersion = json->at(fTypeVersionTag.Data()).get<int>();
1914
1915 if (objClass && (jsonClass != objClass)) {
1916 if (obj || (jsonClass->GetBaseClassOffset(objClass) != 0)) {
1917 if (jsonClass->GetBaseClassOffset(objClass) < 0)
1918 Error("JsonReadObject", "Not possible to read %s and casting to %s pointer as the two classes are unrelated",
1919 jsonClass->GetName(), objClass->GetName());
1920 else
1921 Error("JsonReadObject", "Reading %s and casting to %s pointer is currently not supported",
1922 jsonClass->GetName(), objClass->GetName());
1923 if (process_stl)
1924 PopStack();
1925 return obj;
1926 }
1927 }
1928
1929 if (!obj)
1930 obj = jsonClass->New();
1931
1932 if (gDebug > 1)
1933 Info("JsonReadObject", "Reading object of class %s refid %u ptr %p", jsonClass->GetName(), fJsonrCnt, obj);
1934
1935 if (!special_kind)
1937
1938 // add new element to the reading map
1939 MapObject(obj, jsonClass, ++fJsonrCnt);
1940 }
1941
1942 // there are two ways to handle custom streamers
1943 // either prepare data before streamer and tweak basic function which are reading values like UInt32_t
1944 // or try re-implement custom streamer here
1945
1946 if ((jsonClass == TObject::Class()) || (jsonClass == TRef::Class())) {
1947 // for TObject we re-implement custom streamer - it is much easier
1948
1950
1951 } else if (special_kind == json_TCollection) {
1952
1954
1955 } else {
1956
1958
1959 // special handling of STL which coded into arrays
1960 if ((special_kind > 0) && (special_kind < ROOT::kSTLend))
1962
1963 // if provided - use class version from JSON
1964 stack->fClVersion = jsonClassVersion ? jsonClassVersion : jsonClass->GetClassVersion();
1965
1966 if (gDebug > 3)
1967 Info("JsonReadObject", "Calling streamer of class %s", jsonClass->GetName());
1968
1969 if (isBase && (special_kind == 0))
1970 Error("JsonReadObject", "Should not be used for reading of base class %s", jsonClass->GetName());
1971
1972 if (do_read)
1973 jsonClass->Streamer((void *)obj, *this);
1974
1975 stack->fClVersion = 0;
1976
1977 stack->ClearStl(); // reset STL index for itself to prevent looping
1978 }
1979
1980 // return back stack position
1981 if (process_stl)
1982 PopStack();
1983
1984 if (gDebug > 1)
1985 Info("JsonReadObject", "Reading object of class %s done", jsonClass->GetName());
1986
1987 if (readClass)
1989
1990 return obj;
1991}
1992
1993////////////////////////////////////////////////////////////////////////////////
1994/// Read TObject data members from JSON.
1995/// Do not call TObject::Streamer() to avoid special tweaking of TBufferJSON interface
1996
1998{
1999 nlohmann::json *json = node ? (nlohmann::json *)node : Stack()->fNode;
2000
2001 UInt_t uid = json->at("fUniqueID").get<unsigned>();
2002 UInt_t bits = json->at("fBits").get<unsigned>();
2003 // UInt32_t pid = json->at("fPID").get<unsigned>(); // ignore PID for the moment
2004
2005 tobj->SetUniqueID(uid);
2006
2007 static auto tobj_fbits_offset = TObject::Class()->GetDataMemberOffset("fBits");
2008
2009 // there is no method to set all bits directly - do it differently
2010 if (tobj_fbits_offset > 0) {
2011 UInt_t *fbits = (UInt_t *) ((char* ) tobj + tobj_fbits_offset);
2013 }
2014}
2015
2016////////////////////////////////////////////////////////////////////////////////
2017/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
2018/// and indent new level in json structure.
2019/// This call indicates, that TStreamerInfo functions starts streaming
2020/// object data of correspondent class
2021
2023{
2024 if (gDebug > 2)
2025 Info("IncrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
2026
2028}
2029
2030////////////////////////////////////////////////////////////////////////////////
2031/// Prepares buffer to stream data of specified class
2032
2034{
2035 if (sinfo)
2036 cl = sinfo->GetClass();
2037
2038 if (!cl)
2039 return;
2040
2041 if (gDebug > 3)
2042 Info("WorkWithClass", "Class: %s", cl->GetName());
2043
2044 TJSONStackObj *stack = Stack();
2045
2046 if (IsReading()) {
2047 stack = PushStack(0, stack->fNode);
2048 } else if (stack && stack->IsStreamerElement() && !stack->fIsObjStarted &&
2049 ((stack->fElem->GetType() == TStreamerInfo::kObject) ||
2050 (stack->fElem->GetType() == TStreamerInfo::kAny))) {
2051
2052 stack->fIsObjStarted = kTRUE;
2053
2054 fJsonrCnt++; // count object, but do not keep reference
2055
2056 stack = JsonStartObjectWrite(cl, sinfo);
2057 } else {
2058 stack = PushStack(0);
2059 }
2060
2061 stack->fInfo = sinfo;
2062 stack->fIsStreamerInfo = kTRUE;
2063}
2064
2065////////////////////////////////////////////////////////////////////////////////
2066/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
2067/// and decrease level in json structure.
2068
2070{
2071 if (gDebug > 2)
2072 Info("DecrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
2073
2074 TJSONStackObj *stack = Stack();
2075
2076 if (stack->IsStreamerElement()) {
2077
2078 if (IsWriting()) {
2079 if (gDebug > 3)
2080 Info("DecrementLevel", " Perform post-processing elem: %s", stack->fElem->GetName());
2081
2082 PerformPostProcessing(stack);
2083 }
2084
2085 stack = PopStack(); // remove stack of last element
2086 }
2087
2088 if (stack->fInfo != (TStreamerInfo *)info)
2089 Error("DecrementLevel", " Mismatch of streamer info");
2090
2091 PopStack(); // back from data of stack info
2092
2093 if (gDebug > 3)
2094 Info("DecrementLevel", "Class: %s done", (info ? info->GetClass()->GetName() : "custom"));
2095}
2096
2097////////////////////////////////////////////////////////////////////////////////
2098/// Return current streamer info element
2099
2104
2105////////////////////////////////////////////////////////////////////////////////
2106/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
2107/// and add/verify next element of json structure
2108/// This calls allows separate data, correspondent to one class member, from another
2109
2111{
2112 if (gDebug > 3)
2113 Info("SetStreamerElementNumber", "Element name %s", elem->GetName());
2114
2116}
2117
2118////////////////////////////////////////////////////////////////////////////////
2119/// This is call-back from streamer which indicates
2120/// that class member will be streamed
2121/// Name of element used in JSON
2122
2124{
2125 TJSONStackObj *stack = Stack();
2126 if (!stack) {
2127 Error("WorkWithElement", "stack is empty");
2128 return;
2129 }
2130
2131 if (gDebug > 0)
2132 Info("WorkWithElement", " Start element %s type %d typename %s", elem ? elem->GetName() : "---",
2133 elem ? elem->GetType() : -1, elem ? elem->GetTypeName() : "---");
2134
2135 if (stack->IsStreamerElement()) {
2136 // this is post processing
2137
2138 if (IsWriting()) {
2139 if (gDebug > 3)
2140 Info("WorkWithElement", " Perform post-processing elem: %s", stack->fElem->GetName());
2141 PerformPostProcessing(stack);
2142 }
2143
2144 stack = PopStack(); // go level back
2145 }
2146
2147 fValue.Clear();
2148
2149 if (!stack) {
2150 Error("WorkWithElement", "Lost of stack");
2151 return;
2152 }
2153
2154 TStreamerInfo *info = stack->fInfo;
2155 if (!stack->IsStreamerInfo()) {
2156 Error("WorkWithElement", "Problem in Inc/Dec level");
2157 return;
2158 }
2159
2160 Int_t number = info ? info->GetElements()->IndexOf(elem) : -1;
2161
2162 if (!elem) {
2163 Error("WorkWithElement", "streamer info returns elem = nullptr");
2164 return;
2165 }
2166
2167 TClass *base_class = elem->IsBase() ? elem->GetClassPointer() : nullptr;
2168
2169 stack = PushStack(0, stack->fNode);
2170 stack->fElem = elem;
2171 stack->fIsElemOwner = (number < 0);
2172
2174
2175 if (base_class && IsReading())
2176 stack->fClVersion = base_class->GetClassVersion();
2177
2178 if ((elem->GetType() == TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop) && (elem->GetArrayDim() > 0)) {
2179 // array of array, start handling here
2180 stack->fIndx = std::make_unique<TArrayIndexProducer>(elem, -1, fArraySepar.Data());
2181 if (IsWriting())
2182 AppendOutput(stack->fIndx->GetBegin());
2183 }
2184
2185 if (IsReading() && (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20)) {
2186 // reading of such array begins with reading of single Char_t value
2187 // it indicates if array should be read or not
2188 stack->PushIntValue(stack->IsJsonString() || (stack->IsJsonArray() > 0) ? 1 : 0);
2189 }
2190}
2191
2192////////////////////////////////////////////////////////////////////////////////
2193/// Should be called in the beginning of custom class streamer.
2194/// Informs buffer data about class which will be streamed now.
2195///
2196/// ClassBegin(), ClassEnd() and ClassMember() should be used in
2197/// custom class streamers to specify which kind of data are
2198/// now streamed. Such information is used to correctly
2199/// convert class data to JSON. Without that functions calls
2200/// classes with custom streamers cannot be used with TBufferJSON
2201
2203{
2204 WorkWithClass(nullptr, cl);
2205}
2206
2207////////////////////////////////////////////////////////////////////////////////
2208/// Should be called at the end of custom streamer
2209/// See TBufferJSON::ClassBegin for more details
2210
2212{
2213 DecrementLevel(0);
2214}
2215
2216////////////////////////////////////////////////////////////////////////////////
2217/// Method indicates name and typename of class member,
2218/// which should be now streamed in custom streamer
2219/// Following combinations are supported:
2220/// 1. name = "ClassName", typeName = 0 or typename==ClassName
2221/// This is a case, when data of parent class "ClassName" should be streamed.
2222/// For instance, if class directly inherited from TObject, custom
2223/// streamer should include following code:
2224/// ~~~{.cpp}
2225/// b.ClassMember("TObject");
2226/// TObject::Streamer(b);
2227/// ~~~
2228/// 2. Basic data type
2229/// ~~~{.cpp}
2230/// b.ClassMember("fInt","Int_t");
2231/// b >> fInt;
2232/// ~~~
2233/// 3. Array of basic data types
2234/// ~~~{.cpp}
2235/// b.ClassMember("fArr","Int_t", 5);
2236/// b.ReadFastArray(fArr, 5);
2237/// ~~~
2238/// 4. Object as data member
2239/// ~~~{.cpp}
2240/// b.ClassMember("fName","TString");
2241/// fName.Streamer(b);
2242/// ~~~
2243/// 5. Pointer on object as data member
2244/// ~~~{.cpp}
2245/// b.ClassMember("fObj","TObject*");
2246/// b.StreamObject(fObj);
2247/// ~~~
2248///
2249/// arrsize1 and arrsize2 arguments (when specified) indicate first and
2250/// second dimension of array. Can be used for array of basic types.
2251/// See ClassBegin() method for more details.
2252
2253void TBufferJSON::ClassMember(const char *name, const char *typeName, Int_t arrsize1, Int_t arrsize2)
2254{
2255 if (!typeName)
2256 typeName = name;
2257
2258 if (!name || (strlen(name) == 0)) {
2259 Error("ClassMember", "Invalid member name");
2260 return;
2261 }
2262
2263 TString tname = typeName;
2264
2265 Int_t typ_id = -1;
2266
2267 if (strcmp(typeName, "raw:data") == 0)
2269
2270 if (typ_id < 0) {
2271 TDataType *dt = gROOT->GetType(typeName);
2272 if (dt && (dt->GetType() > 0) && (dt->GetType() < 20))
2273 typ_id = dt->GetType();
2274 }
2275
2276 if (typ_id < 0)
2277 if (strcmp(name, typeName) == 0) {
2278 TClass *cl = TClass::GetClass(tname.Data());
2279 if (cl)
2281 }
2282
2283 if (typ_id < 0) {
2285 if (tname[tname.Length() - 1] == '*') {
2286 tname.Resize(tname.Length() - 1);
2287 isptr = kTRUE;
2288 }
2289 TClass *cl = TClass::GetClass(tname.Data());
2290 if (!cl) {
2291 Error("ClassMember", "Invalid class specifier %s", typeName);
2292 return;
2293 }
2294
2295 if (cl->IsTObject())
2297 else
2299
2300 if ((cl == TString::Class()) && !isptr)
2302 }
2303
2304 TStreamerElement *elem = nullptr;
2305
2307 elem = new TStreamerElement(name, "title", 0, typ_id, "raw:data");
2308 } else if (typ_id == TStreamerInfo::kBase) {
2309 TClass *cl = TClass::GetClass(tname.Data());
2310 if (cl) {
2311 TStreamerBase *b = new TStreamerBase(tname.Data(), "title", 0);
2312 b->SetBaseVersion(cl->GetClassVersion());
2313 elem = b;
2314 }
2315 } else if ((typ_id > 0) && (typ_id < 20)) {
2316 elem = new TStreamerBasicType(name, "title", 0, typ_id, typeName);
2319 elem = new TStreamerObject(name, "title", 0, tname.Data());
2320 } else if (typ_id == TStreamerInfo::kObjectp) {
2321 elem = new TStreamerObjectPointer(name, "title", 0, tname.Data());
2322 } else if (typ_id == TStreamerInfo::kAny) {
2323 elem = new TStreamerObjectAny(name, "title", 0, tname.Data());
2324 } else if (typ_id == TStreamerInfo::kAnyp) {
2325 elem = new TStreamerObjectAnyPointer(name, "title", 0, tname.Data());
2326 } else if (typ_id == TStreamerInfo::kTString) {
2327 elem = new TStreamerString(name, "title", 0);
2328 }
2329
2330 if (!elem) {
2331 Error("ClassMember", "Invalid combination name = %s type = %s", name, typeName);
2332 return;
2333 }
2334
2335 if (arrsize1 > 0) {
2336 elem->SetArrayDim(arrsize2 > 0 ? 2 : 1);
2337 elem->SetMaxIndex(0, arrsize1);
2338 if (arrsize2 > 0)
2339 elem->SetMaxIndex(1, arrsize2);
2340 }
2341
2342 // we indicate that there is no streamerinfo
2343 WorkWithElement(elem, -1);
2344}
2345
2346////////////////////////////////////////////////////////////////////////////////
2347/// Function is converts TObject and TString structures to more compact representation
2348
2350{
2351 if (stack->fIsPostProcessed)
2352 return;
2353
2354 const TStreamerElement *elem = stack->fElem;
2355
2356 if (!elem && !obj_cl)
2357 return;
2358
2359 stack->fIsPostProcessed = kTRUE;
2360
2361 // when element was written as separate object, close only braces and exit
2362 if (stack->fIsObjStarted) {
2363 AppendOutput("", "}");
2364 return;
2365 }
2366
2369
2370 if (obj_cl) {
2371 if (obj_cl == TObject::Class())
2372 isTObject = kTRUE;
2373 else if (obj_cl == TRef::Class())
2374 isTRef = kTRUE;
2375 else
2376 return;
2377 } else {
2378 const char *typname = elem->IsBase() ? elem->GetName() : elem->GetTypeName();
2379 isTObject = (elem->GetType() == TStreamerInfo::kTObject) || (strcmp("TObject", typname) == 0);
2380 isTString = elem->GetType() == TStreamerInfo::kTString;
2382 isOffsetPArray = (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20);
2383 isTArray = (strncmp("TArray", typname, 6) == 0);
2384 }
2385
2386 if (isTString || isSTLstring) {
2387 // just remove all kind of string length information
2388
2389 if (gDebug > 3)
2390 Info("PerformPostProcessing", "reformat string value = '%s'", fValue.Data());
2391
2392 stack->fValues.clear();
2393 } else if (isOffsetPArray) {
2394 // basic array with [fN] comment
2395
2396 if (stack->fValues.empty() && (fValue == "0")) {
2397 fValue = "[]";
2398 } else if ((stack->fValues.size() == 1) && (stack->fValues[0] == "1")) {
2399 stack->fValues.clear();
2400 } else {
2401 Error("PerformPostProcessing", "Wrong values for kOffsetP element %s", (elem ? elem->GetName() : "---"));
2402 stack->fValues.clear();
2403 fValue = "[]";
2404 }
2405 } else if (isTObject || isTRef) {
2406 // complex workaround for TObject/TRef streamer
2407 // would be nice if other solution can be found
2408 // Here is not supported TRef on TRef (double reference)
2409
2410 Int_t cnt = stack->fValues.size();
2411 if (fValue.Length() > 0)
2412 cnt++;
2413
2414 if (cnt < 2 || cnt > 3) {
2415 if (gDebug > 0)
2416 Error("PerformPostProcessing", "When storing TObject/TRef, strange number of items %d", cnt);
2417 AppendOutput(stack->NextMemberSeparator(), "\"dummy\"");
2419 } else {
2420 AppendOutput(stack->NextMemberSeparator(), "\"fUniqueID\"");
2422 AppendOutput(stack->fValues[0].c_str());
2423 AppendOutput(stack->NextMemberSeparator(), "\"fBits\"");
2425 auto tbits = std::atol((stack->fValues.size() > 1) ? stack->fValues[1].c_str() : fValue.Data());
2426 AppendOutput(std::to_string(tbits & ~TObject::kNotDeleted & ~TObject::kIsOnHeap).c_str());
2427 if (cnt == 3) {
2428 AppendOutput(stack->NextMemberSeparator(), "\"fPID\"");
2430 AppendOutput((stack->fValues.size() > 2) ? stack->fValues[2].c_str() : fValue.Data());
2431 }
2432
2433 stack->fValues.clear();
2434 fValue.Clear();
2435 return;
2436 }
2437
2438 } else if (isTArray) {
2439 // for TArray one deletes complete stack
2440 stack->fValues.clear();
2441 }
2442
2443 if (elem && elem->IsBase() && (fValue.Length() == 0)) {
2444 // here base class data already completely stored
2445 return;
2446 }
2447
2448 if (!stack->fValues.empty()) {
2449 // append element blob data just as abstract array, user is responsible to decode it
2450 AppendOutput("[");
2451 for (auto &blob: stack->fValues) {
2452 AppendOutput(blob.c_str());
2454 }
2455 }
2456
2457 if (fValue.Length() == 0) {
2458 AppendOutput("null");
2459 } else {
2461 fValue.Clear();
2462 }
2463
2464 if (!stack->fValues.empty())
2465 AppendOutput("]");
2466}
2467
2468////////////////////////////////////////////////////////////////////////////////
2469/// suppressed function of TBuffer
2470
2472{
2473 return nullptr;
2474}
2475
2476////////////////////////////////////////////////////////////////////////////////
2477/// suppressed function of TBuffer
2478
2480
2481////////////////////////////////////////////////////////////////////////////////
2482/// read version value from buffer
2483
2485{
2486 Version_t res = cl ? cl->GetClassVersion() : 0;
2487
2488 if (start)
2489 *start = 0;
2490 if (bcnt)
2491 *bcnt = 0;
2492
2493 if (!cl && Stack()->fClVersion) {
2494 res = Stack()->fClVersion;
2495 Stack()->fClVersion = 0;
2496 }
2497
2498 if (gDebug > 3)
2499 Info("ReadVersion", "Result: %d Class: %s", res, (cl ? cl->GetName() : "---"));
2500
2501 return res;
2502}
2503
2504////////////////////////////////////////////////////////////////////////////////
2505/// Ignored in TBufferJSON
2506
2507UInt_t TBufferJSON::WriteVersion(const TClass * /*cl*/, Bool_t /* useBcnt */)
2508{
2509 return 0;
2510}
2511
2512////////////////////////////////////////////////////////////////////////////////
2513/// Read object from buffer. Only used from TBuffer
2514
2516{
2517 if (gDebug > 2)
2518 Info("ReadObjectAny", "From current JSON node");
2519 void *res = JsonReadObject(nullptr, expectedClass);
2520 return res;
2521}
2522
2523////////////////////////////////////////////////////////////////////////////////
2524/// Skip any kind of object from buffer
2525
2527
2528////////////////////////////////////////////////////////////////////////////////
2529/// Write object to buffer. Only used from TBuffer
2530
2532{
2533 if (gDebug > 3)
2534 Info("WriteObjectClass", "Class %s", (actualClass ? actualClass->GetName() : " null"));
2535
2537}
2538
2539////////////////////////////////////////////////////////////////////////////////
2540/// If value exists, push in the current stack for post-processing
2541
2543{
2544 if (fValue.Length() > 0)
2546}
2547
2548////////////////////////////////////////////////////////////////////////////////
2549/// Read array of Bool_t from buffer
2550
2555
2556////////////////////////////////////////////////////////////////////////////////
2557/// Read array of Char_t from buffer
2558
2563
2564////////////////////////////////////////////////////////////////////////////////
2565/// Read array of UChar_t from buffer
2566
2571
2572////////////////////////////////////////////////////////////////////////////////
2573/// Read array of Short_t from buffer
2574
2579
2580////////////////////////////////////////////////////////////////////////////////
2581/// Read array of UShort_t from buffer
2582
2587
2588////////////////////////////////////////////////////////////////////////////////
2589/// Read array of Int_t from buffer
2590
2592{
2593 return JsonReadArray(i);
2594}
2595
2596////////////////////////////////////////////////////////////////////////////////
2597/// Read array of UInt_t from buffer
2598
2600{
2601 return JsonReadArray(i);
2602}
2603
2604////////////////////////////////////////////////////////////////////////////////
2605/// Read array of Long_t from buffer
2606
2611
2612////////////////////////////////////////////////////////////////////////////////
2613/// Read array of ULong_t from buffer
2614
2619
2620////////////////////////////////////////////////////////////////////////////////
2621/// Read array of Long64_t from buffer
2622
2627
2628////////////////////////////////////////////////////////////////////////////////
2629/// Read array of ULong64_t from buffer
2630
2635
2636////////////////////////////////////////////////////////////////////////////////
2637/// Read array of Float_t from buffer
2638
2643
2644////////////////////////////////////////////////////////////////////////////////
2645/// Read array of Double_t from buffer
2646
2651
2652////////////////////////////////////////////////////////////////////////////////
2653/// Read static array from JSON - not used
2654
2655template <typename T>
2657{
2658 Info("ReadArray", "Not implemented");
2659 return value ? 1 : 0;
2660}
2661
2662////////////////////////////////////////////////////////////////////////////////
2663/// Read array of Bool_t from buffer
2664
2669
2670////////////////////////////////////////////////////////////////////////////////
2671/// Read array of Char_t from buffer
2672
2677
2678////////////////////////////////////////////////////////////////////////////////
2679/// Read array of UChar_t from buffer
2680
2685
2686////////////////////////////////////////////////////////////////////////////////
2687/// Read array of Short_t from buffer
2688
2693
2694////////////////////////////////////////////////////////////////////////////////
2695/// Read array of UShort_t from buffer
2696
2701
2702////////////////////////////////////////////////////////////////////////////////
2703/// Read array of Int_t from buffer
2704
2709
2710////////////////////////////////////////////////////////////////////////////////
2711/// Read array of UInt_t from buffer
2712
2717
2718////////////////////////////////////////////////////////////////////////////////
2719/// Read array of Long_t from buffer
2720
2725
2726////////////////////////////////////////////////////////////////////////////////
2727/// Read array of ULong_t from buffer
2728
2733
2734////////////////////////////////////////////////////////////////////////////////
2735/// Read array of Long64_t from buffer
2736
2741
2742////////////////////////////////////////////////////////////////////////////////
2743/// Read array of ULong64_t from buffer
2744
2749
2750////////////////////////////////////////////////////////////////////////////////
2751/// Read array of Float_t from buffer
2752
2757
2758////////////////////////////////////////////////////////////////////////////////
2759/// Read array of Double_t from buffer
2760
2765
2766////////////////////////////////////////////////////////////////////////////////
2767/// Template method to read array from the JSON
2768
2769template <typename T>
2771{
2772 if (!arr || (arrsize <= 0))
2773 return;
2774 nlohmann::json *json = Stack()->fNode;
2775 if (gDebug > 2)
2776 Info("ReadFastArray", "Reading array sz %d from JSON %s", arrsize, json->dump().substr(0, 30).c_str());
2777 auto indexes = Stack()->MakeReadIndexes();
2778 if (indexes) { /* at least two dims */
2779 TArrayI &indx = indexes->GetIndices();
2780 Int_t lastdim = indx.GetSize() - 1;
2781 if (indexes->TotalLength() != arrsize)
2782 Error("ReadFastArray", "Mismatch %d-dim array sizes %d %d", lastdim + 1, arrsize, (int)indexes->TotalLength());
2783 for (int cnt = 0; cnt < arrsize; ++cnt) {
2784 nlohmann::json *elem = &(json->at(indx[0]));
2785 for (int k = 1; k < lastdim; ++k)
2786 elem = &((*elem)[indx[k]]);
2787 arr[cnt] = (asstring && elem->is_string()) ? elem->get<std::string>()[indx[lastdim]] : (*elem)[indx[lastdim]].get<T>();
2788 indexes->NextSeparator();
2789 }
2790 } else if (asstring && json->is_string()) {
2791 std::string str = json->get<std::string>();
2792 for (int cnt = 0; cnt < arrsize; ++cnt)
2793 arr[cnt] = (cnt < (int)str.length()) ? str[cnt] : 0;
2794 } else if (json->is_object() && (json->count("$arr") == 1)) {
2795 if (json->at("len").get<int>() != arrsize)
2796 Error("ReadFastArray", "Mismatch compressed array size %d %d", arrsize, json->at("len").get<int>());
2797
2798 for (int cnt = 0; cnt < arrsize; ++cnt)
2799 arr[cnt] = 0;
2800
2801 if (json->count("b") == 1) {
2802 auto base64 = json->at("b").get<std::string>();
2803
2804 int offset = (json->count("o") == 1) ? json->at("o").get<int>() : 0;
2805
2806 // TODO: provide TBase64::Decode with direct write into target buffer
2807 auto decode = TBase64::Decode(base64.c_str());
2808
2809 if (arrsize * (long) sizeof(T) < (offset + decode.Length())) {
2810 Error("ReadFastArray", "Base64 data %ld larger than target array size %ld", (long) decode.Length() + offset, (long) (arrsize*sizeof(T)));
2811 } else if ((sizeof(T) > 1) && (decode.Length() % sizeof(T) != 0)) {
2812 Error("ReadFastArray", "Base64 data size %ld not matches with element size %ld", (long) decode.Length(), (long) sizeof(T));
2813 } else {
2814 memcpy((char *) arr + offset, decode.Data(), decode.Length());
2815 }
2816 return;
2817 }
2818
2819 int p = 0, id = 0;
2820 std::string idname = "", pname, vname, nname;
2821 while (p < arrsize) {
2822 pname = std::string("p") + idname;
2823 if (json->count(pname) == 1)
2824 p = json->at(pname).get<int>();
2825 vname = std::string("v") + idname;
2826 if (json->count(vname) != 1)
2827 break;
2828 nlohmann::json &v = json->at(vname);
2829 if (v.is_array()) {
2830 for (unsigned sub = 0; sub < v.size(); ++sub)
2831 arr[p++] = v[sub].get<T>();
2832 } else {
2833 nname = std::string("n") + idname;
2834 unsigned ncopy = (json->count(nname) == 1) ? json->at(nname).get<unsigned>() : 1;
2835 for (unsigned sub = 0; sub < ncopy; ++sub)
2836 arr[p++] = v.get<T>();
2837 }
2838 idname = std::to_string(++id);
2839 }
2840 } else {
2841 if ((int)json->size() != arrsize)
2842 Error("ReadFastArray", "Mismatch array sizes %d %d", arrsize, (int)json->size());
2843 for (int cnt = 0; cnt < arrsize; ++cnt)
2844 arr[cnt] = json->at(cnt).get<T>();
2845 }
2846}
2847
2848////////////////////////////////////////////////////////////////////////////////
2849/// read array of Bool_t from buffer
2850
2855
2856////////////////////////////////////////////////////////////////////////////////
2857/// read array of Char_t from buffer
2858
2860{
2861 JsonReadFastArray(c, n, true);
2862}
2863
2864////////////////////////////////////////////////////////////////////////////////
2865/// read array of Char_t from buffer
2866
2871
2872////////////////////////////////////////////////////////////////////////////////
2873/// read array of UChar_t from buffer
2874
2879
2880////////////////////////////////////////////////////////////////////////////////
2881/// read array of Short_t from buffer
2882
2887
2888////////////////////////////////////////////////////////////////////////////////
2889/// read array of UShort_t from buffer
2890
2895
2896////////////////////////////////////////////////////////////////////////////////
2897/// read array of Int_t from buffer
2898
2903
2904////////////////////////////////////////////////////////////////////////////////
2905/// read array of UInt_t from buffer
2906
2911
2912////////////////////////////////////////////////////////////////////////////////
2913/// read array of Long_t from buffer
2914
2919
2920////////////////////////////////////////////////////////////////////////////////
2921/// read array of ULong_t from buffer
2922
2927
2928////////////////////////////////////////////////////////////////////////////////
2929/// read array of Long64_t from buffer
2930
2935
2936////////////////////////////////////////////////////////////////////////////////
2937/// read array of ULong64_t from buffer
2938
2943
2944////////////////////////////////////////////////////////////////////////////////
2945/// read array of Float_t from buffer
2946
2951
2952////////////////////////////////////////////////////////////////////////////////
2953/// read array of Double_t from buffer
2954
2959
2960////////////////////////////////////////////////////////////////////////////////
2961/// Read an array of 'n' objects from the I/O buffer.
2962/// Stores the objects read starting at the address 'start'.
2963/// The objects in the array are assume to be of class 'cl'.
2964/// Copied code from TBufferFile
2965
2966void TBufferJSON::ReadFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer * /* streamer */,
2967 const TClass * /* onFileClass */)
2968{
2969 if (gDebug > 1)
2970 Info("ReadFastArray", "void* n:%d cl:%s", n, cl->GetName());
2971
2972 // if (streamer) {
2973 // Info("ReadFastArray", "(void*) Calling streamer - not handled correctly");
2974 // streamer->SetOnFileClass(onFileClass);
2975 // (*streamer)(*this, start, 0);
2976 // return;
2977 // }
2978
2979 int objectSize = cl->Size();
2980 char *obj = (char *)start;
2981
2982 TJSONStackObj *stack = Stack();
2983 nlohmann::json *topnode = stack->fNode, *subnode = topnode;
2984 if (stack->fIndx)
2985 subnode = stack->fIndx->ExtractNode(topnode);
2986
2987 TArrayIndexProducer indexes(stack->fElem, n, "");
2988
2989 if (gDebug > 1)
2990 Info("ReadFastArray", "Indexes ndim:%d totallen:%d", indexes.NumDimensions(), indexes.TotalLength());
2991
2992 for (Int_t j = 0; j < n; j++, obj += objectSize) {
2993
2994 stack->fNode = indexes.ExtractNode(subnode);
2995
2996 JsonReadObject(obj, cl);
2997 }
2998
2999 // restore top node - show we use stack here?
3000 stack->fNode = topnode;
3001}
3002
3003////////////////////////////////////////////////////////////////////////////////
3004/// redefined here to avoid warning message from gcc
3005
3007 TMemberStreamer * /* streamer */, const TClass * /* onFileClass */)
3008{
3009 if (gDebug > 1)
3010 Info("ReadFastArray", "void** n:%d cl:%s prealloc:%s", n, cl->GetName(), (isPreAlloc ? "true" : "false"));
3011
3012 // if (streamer) {
3013 // Info("ReadFastArray", "(void**) Calling streamer - not handled correctly");
3014 // if (isPreAlloc) {
3015 // for (Int_t j = 0; j < n; j++) {
3016 // if (!start[j])
3017 // start[j] = cl->New();
3018 // }
3019 // }
3020 // streamer->SetOnFileClass(onFileClass);
3021 // (*streamer)(*this, (void *)start, 0);
3022 // return;
3023 // }
3024
3025 TJSONStackObj *stack = Stack();
3026 nlohmann::json *topnode = stack->fNode, *subnode = topnode;
3027 if (stack->fIndx)
3028 subnode = stack->fIndx->ExtractNode(topnode);
3029
3030 TArrayIndexProducer indexes(stack->fElem, n, "");
3031
3032 for (Int_t j = 0; j < n; j++) {
3033
3034 stack->fNode = indexes.ExtractNode(subnode);
3035
3036 if (!isPreAlloc) {
3037 void *old = start[j];
3038 start[j] = JsonReadObject(nullptr, cl);
3039 if (old && old != start[j] && TStreamerInfo::CanDelete())
3040 (const_cast<TClass *>(cl))->Destructor(old, kFALSE); // call delete and destruct
3041 } else {
3042 if (!start[j])
3043 start[j] = (const_cast<TClass *>(cl))->New();
3044 JsonReadObject(start[j], cl);
3045 }
3046 }
3047
3048 stack->fNode = topnode;
3049}
3050
3051template <typename T>
3053{
3054 bool is_base64 = Stack()->fBase64 || (fArrayCompact == kBase64);
3055
3056 if (!is_base64 && ((fArrayCompact == 0) || (arrsize < 6))) {
3057 fValue.Append("[");
3058 for (Int_t indx = 0; indx < arrsize; indx++) {
3059 if (indx > 0)
3062 }
3063 fValue.Append("]");
3064 } else if (is_base64 && !arrsize) {
3065 fValue.Append("[]");
3066 } else {
3067 fValue.Append("{");
3068 fValue.Append(TString::Format("\"$arr\":\"%s\"%s\"len\":%d", typname, fArraySepar.Data(), arrsize));
3069 Int_t aindx(0), bindx(arrsize);
3070 while ((aindx < arrsize) && (vname[aindx] == 0))
3071 aindx++;
3072 while ((aindx < bindx) && (vname[bindx - 1] == 0))
3073 bindx--;
3074
3075 if (is_base64) {
3076 // small initial offset makes no sense - JSON code is large then size gain
3077 if ((aindx * sizeof(T) < 5) && (aindx < bindx))
3078 aindx = 0;
3079
3080 if ((aindx > 0) && (aindx < bindx))
3081 fValue.Append(TString::Format("%s\"o\":%ld", fArraySepar.Data(), (long) (aindx * (int) sizeof(T))));
3082
3084 fValue.Append("\"b\":\"");
3085
3086 if (aindx < bindx)
3087 fValue.Append(TBase64::Encode((const char *) (vname + aindx), (bindx - aindx) * sizeof(T)));
3088
3089 fValue.Append("\"");
3090 } else if (aindx < bindx) {
3091 TString suffix("");
3092 Int_t p(aindx), suffixcnt(-1), lastp(0);
3093 while (p < bindx) {
3094 if (vname[p] == 0) {
3095 p++;
3096 continue;
3097 }
3098 Int_t p0(p++), pp(0), nsame(1);
3100 pp = bindx;
3101 p = bindx + 1;
3102 nsame = 0;
3103 }
3104 for (; p <= bindx; ++p) {
3105 if ((p < bindx) && (vname[p] == vname[p - 1])) {
3106 nsame++;
3107 continue;
3108 }
3109 if (vname[p - 1] == 0) {
3110 if (nsame > 9) {
3111 nsame = 0;
3112 break;
3113 }
3114 } else if (nsame > 5) {
3115 if (pp) {
3116 p = pp;
3117 nsame = 0;
3118 } else
3119 pp = p;
3120 break;
3121 }
3122 pp = p;
3123 nsame = 1;
3124 }
3125 if (pp <= p0)
3126 continue;
3127 if (++suffixcnt > 0)
3128 suffix.Form("%d", suffixcnt);
3129 if (p0 != lastp)
3130 fValue.Append(TString::Format("%s\"p%s\":%d", fArraySepar.Data(), suffix.Data(), p0));
3131 lastp = pp; /* remember cursor, it may be the same */
3132 fValue.Append(TString::Format("%s\"v%s\":", fArraySepar.Data(), suffix.Data()));
3133 if ((nsame > 1) || (pp - p0 == 1)) {
3135 if (nsame > 1)
3136 fValue.Append(TString::Format("%s\"n%s\":%d", fArraySepar.Data(), suffix.Data(), nsame));
3137 } else {
3138 fValue.Append("[");
3139 for (Int_t indx = p0; indx < pp; indx++) {
3140 if (indx > p0)
3143 }
3144 fValue.Append("]");
3145 }
3146 }
3147 }
3148 fValue.Append("}");
3149 }
3150}
3151
3152////////////////////////////////////////////////////////////////////////////////
3153/// Write array of Bool_t to buffer
3154
3156{
3157 JsonPushValue();
3158 JsonWriteArrayCompress(b, n, "Bool");
3159}
3160
3161////////////////////////////////////////////////////////////////////////////////
3162/// Write array of Char_t to buffer
3163
3165{
3166 JsonPushValue();
3167 JsonWriteArrayCompress(c, n, "Int8");
3168}
3169
3170////////////////////////////////////////////////////////////////////////////////
3171/// Write array of UChar_t to buffer
3172
3174{
3175 JsonPushValue();
3176 JsonWriteArrayCompress(c, n, "Uint8");
3177}
3178
3179////////////////////////////////////////////////////////////////////////////////
3180/// Write array of Short_t to buffer
3181
3183{
3184 JsonPushValue();
3185 JsonWriteArrayCompress(h, n, "Int16");
3186}
3187
3188////////////////////////////////////////////////////////////////////////////////
3189/// Write array of UShort_t to buffer
3190
3192{
3193 JsonPushValue();
3194 JsonWriteArrayCompress(h, n, "Uint16");
3195}
3196
3197////////////////////////////////////////////////////////////////////////////////
3198/// Write array of Int_ to buffer
3199
3201{
3202 JsonPushValue();
3203 JsonWriteArrayCompress(i, n, "Int32");
3204}
3205
3206////////////////////////////////////////////////////////////////////////////////
3207/// Write array of UInt_t to buffer
3208
3210{
3211 JsonPushValue();
3212 JsonWriteArrayCompress(i, n, "Uint32");
3213}
3214
3215////////////////////////////////////////////////////////////////////////////////
3216/// Write array of Long_t to buffer
3217
3219{
3220 JsonPushValue();
3221 JsonWriteArrayCompress(l, n, "Int64");
3222}
3223
3224////////////////////////////////////////////////////////////////////////////////
3225/// Write array of ULong_t to buffer
3226
3228{
3229 JsonPushValue();
3230 JsonWriteArrayCompress(l, n, "Uint64");
3231}
3232
3233////////////////////////////////////////////////////////////////////////////////
3234/// Write array of Long64_t to buffer
3235
3237{
3238 JsonPushValue();
3239 JsonWriteArrayCompress(l, n, "Int64");
3240}
3241
3242////////////////////////////////////////////////////////////////////////////////
3243/// Write array of ULong64_t to buffer
3244
3246{
3247 JsonPushValue();
3248 JsonWriteArrayCompress(l, n, "Uint64");
3249}
3250
3251////////////////////////////////////////////////////////////////////////////////
3252/// Write array of Float_t to buffer
3253
3255{
3256 JsonPushValue();
3257 JsonWriteArrayCompress(f, n, "Float32");
3258}
3259
3260////////////////////////////////////////////////////////////////////////////////
3261/// Write array of Double_t to buffer
3262
3264{
3265 JsonPushValue();
3266 JsonWriteArrayCompress(d, n, "Float64");
3267}
3268
3269////////////////////////////////////////////////////////////////////////////////
3270/// Template method to write array of arbitrary dimensions
3271/// Different methods can be used for store last array dimension -
3272/// either JsonWriteArrayCompress<T>() or JsonWriteConstChar()
3273/// \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.
3274///
3275template <typename T>
3277 void (TBufferJSON::*method)(const T *, Int_t, const char *))
3278{
3279 JsonPushValue();
3280 if (arrsize <= 0) { /*fJsonrCnt++;*/
3281 fValue.Append("[]");
3282 return;
3283 }
3284 constexpr Int_t dataWidth = 1; // at least 1
3285 const Int_t maxElements = (std::numeric_limits<Int_t>::max() - Length())/dataWidth;
3286 if (arrsize > maxElements)
3287 {
3288 Fatal("JsonWriteFastArray", "Not enough space left in the buffer (1GB limit). %lld elements is greater than the max left of %d", arrsize, maxElements);
3289 return; // In case the user re-routes the error handler to not die when Fatal is called
3290 }
3291
3293 if (elem && (elem->GetArrayDim() > 1) && (elem->GetArrayLength() == arrsize)) {
3294 TArrayI indexes(elem->GetArrayDim() - 1);
3295 indexes.Reset(0);
3296 Int_t cnt = 0, shift = 0, len = elem->GetMaxIndex(indexes.GetSize());
3297 while (cnt >= 0) {
3298 if (indexes[cnt] >= elem->GetMaxIndex(cnt)) {
3299 fValue.Append("]");
3300 indexes[cnt--] = 0;
3301 if (cnt >= 0)
3302 indexes[cnt]++;
3303 continue;
3304 }
3305 fValue.Append(indexes[cnt] == 0 ? "[" : fArraySepar.Data());
3306 if (++cnt == indexes.GetSize()) {
3307 (*this.*method)((arr + shift), len, typname);
3308 indexes[--cnt]++;
3309 shift += len;
3310 }
3311 }
3312 } else {
3313 (*this.*method)(arr, arrsize, typname);
3314 }
3315}
3316
3317////////////////////////////////////////////////////////////////////////////////
3318/// Write array of Bool_t to buffer
3319
3321{
3322 JsonWriteFastArray(b, n, "Bool", &TBufferJSON::JsonWriteArrayCompress<Bool_t>);
3323}
3324
3325////////////////////////////////////////////////////////////////////////////////
3326/// Write array of Char_t to buffer
3327///
3328/// Normally written as JSON string, but if string includes \0 in the middle
3329/// or some special characters, uses regular array. From array size 1000 it
3330/// will be automatically converted into base64 coding
3331
3333{
3334 Bool_t need_blob = false;
3335 Bool_t has_zero = false;
3336 for (Long64_t i=0;i<n;++i) {
3337 if (!c[i]) {
3338 has_zero = true; // might be terminal '\0'
3339 } else if (has_zero || !isprint(c[i])) {
3340 need_blob = true;
3341 break;
3342 }
3343 }
3344
3345 if (need_blob && (n >= 1000) && (!Stack()->fElem || (Stack()->fElem->GetArrayDim() < 2)))
3346 Stack()->fBase64 = true;
3347
3348 JsonWriteFastArray(c, n, "Int8", need_blob ? &TBufferJSON::JsonWriteArrayCompress<Char_t> : &TBufferJSON::JsonWriteConstChar);
3349}
3350
3351////////////////////////////////////////////////////////////////////////////////
3352/// Write array of Char_t to buffer
3353
3358
3359////////////////////////////////////////////////////////////////////////////////
3360/// Write array of UChar_t to buffer
3361
3363{
3364 JsonWriteFastArray(c, n, "Uint8", &TBufferJSON::JsonWriteArrayCompress<UChar_t>);
3365}
3366
3367////////////////////////////////////////////////////////////////////////////////
3368/// Write array of Short_t to buffer
3369
3371{
3372 JsonWriteFastArray(h, n, "Int16", &TBufferJSON::JsonWriteArrayCompress<Short_t>);
3373}
3374
3375////////////////////////////////////////////////////////////////////////////////
3376/// Write array of UShort_t to buffer
3377
3379{
3380 JsonWriteFastArray(h, n, "Uint16", &TBufferJSON::JsonWriteArrayCompress<UShort_t>);
3381}
3382
3383////////////////////////////////////////////////////////////////////////////////
3384/// Write array of Int_t to buffer
3385
3387{
3388 JsonWriteFastArray(i, n, "Int32", &TBufferJSON::JsonWriteArrayCompress<Int_t>);
3389}
3390
3391////////////////////////////////////////////////////////////////////////////////
3392/// Write array of UInt_t to buffer
3393
3395{
3396 JsonWriteFastArray(i, n, "Uint32", &TBufferJSON::JsonWriteArrayCompress<UInt_t>);
3397}
3398
3399////////////////////////////////////////////////////////////////////////////////
3400/// Write array of Long_t to buffer
3401
3403{
3404 JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long_t>);
3405}
3406
3407////////////////////////////////////////////////////////////////////////////////
3408/// Write array of ULong_t to buffer
3409
3411{
3412 JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong_t>);
3413}
3414
3415////////////////////////////////////////////////////////////////////////////////
3416/// Write array of Long64_t to buffer
3417
3419{
3420 JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long64_t>);
3421}
3422
3423////////////////////////////////////////////////////////////////////////////////
3424/// Write array of ULong64_t to buffer
3425
3427{
3428 JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong64_t>);
3429}
3430
3431////////////////////////////////////////////////////////////////////////////////
3432/// Write array of Float_t to buffer
3433
3435{
3436 JsonWriteFastArray(f, n, "Float32", &TBufferJSON::JsonWriteArrayCompress<Float_t>);
3437}
3438
3439////////////////////////////////////////////////////////////////////////////////
3440/// Write array of Double_t to buffer
3441
3443{
3444 JsonWriteFastArray(d, n, "Float64", &TBufferJSON::JsonWriteArrayCompress<Double_t>);
3445}
3446
3447////////////////////////////////////////////////////////////////////////////////
3448/// Recall TBuffer function to avoid gcc warning message
3449
3450void TBufferJSON::WriteFastArray(void *start, const TClass *cl, Long64_t n, TMemberStreamer * /* streamer */)
3451{
3452 if (gDebug > 2)
3453 Info("WriteFastArray", "void *start cl:%s n:%lld", cl ? cl->GetName() : "---", n);
3454
3455 // if (streamer) {
3456 // JsonDisablePostprocessing();
3457 // (*streamer)(*this, start, 0);
3458 // return;
3459 // }
3460
3461 if (n < 0) {
3462 // special handling of empty StreamLoop
3463 AppendOutput("null");
3465 } else {
3466
3467 char *obj = (char *)start;
3468 if (!n)
3469 n = 1;
3470 int size = cl->Size();
3471
3473
3474 if (indexes.IsArray()) {
3476 AppendOutput(indexes.GetBegin());
3477 }
3478
3479 for (Long64_t j = 0; j < n; j++, obj += size) {
3480
3481 if (j > 0)
3482 AppendOutput(indexes.NextSeparator());
3483
3484 JsonWriteObject(obj, cl, kFALSE);
3485
3486 if (indexes.IsArray() && (fValue.Length() > 0)) {
3488 fValue.Clear();
3489 }
3490 }
3491
3492 if (indexes.IsArray())
3493 AppendOutput(indexes.GetEnd());
3494 }
3495
3496 if (Stack()->fIndx)
3497 AppendOutput(Stack()->fIndx->NextSeparator());
3498}
3499
3500////////////////////////////////////////////////////////////////////////////////
3501/// Recall TBuffer function to avoid gcc warning message
3502
3504 TMemberStreamer * /* streamer */)
3505{
3506 if (gDebug > 2)
3507 Info("WriteFastArray", "void **startp cl:%s n:%lld", cl->GetName(), n);
3508
3509 // if (streamer) {
3510 // JsonDisablePostprocessing();
3511 // (*streamer)(*this, (void *)start, 0);
3512 // return 0;
3513 // }
3514
3515 if (n <= 0)
3516 return 0;
3517
3518 Int_t res = 0;
3519
3521
3522 if (indexes.IsArray()) {
3524 AppendOutput(indexes.GetBegin());
3525 }
3526
3527 for (Long64_t j = 0; j < n; j++) {
3528
3529 if (j > 0)
3530 AppendOutput(indexes.NextSeparator());
3531
3532 if (!isPreAlloc) {
3533 res |= WriteObjectAny(start[j], cl);
3534 } else {
3535 if (!start[j])
3536 start[j] = (const_cast<TClass *>(cl))->New();
3537 // ((TClass*)cl)->Streamer(start[j],*this);
3538 JsonWriteObject(start[j], cl, kFALSE);
3539 }
3540
3541 if (indexes.IsArray() && (fValue.Length() > 0)) {
3543 fValue.Clear();
3544 }
3545 }
3546
3547 if (indexes.IsArray())
3548 AppendOutput(indexes.GetEnd());
3549
3550 if (Stack()->fIndx)
3551 AppendOutput(Stack()->fIndx->NextSeparator());
3552
3553 return res;
3554}
3555
3556////////////////////////////////////////////////////////////////////////////////
3557/// stream object to/from buffer
3558
3559void TBufferJSON::StreamObject(void *obj, const TClass *cl, const TClass * /* onfileClass */)
3560{
3561 if (gDebug > 3)
3562 Info("StreamObject", "Class: %s", (cl ? cl->GetName() : "none"));
3563
3564 if (IsWriting())
3565 JsonWriteObject(obj, cl);
3566 else
3567 JsonReadObject(obj, cl);
3568}
3569
3570////////////////////////////////////////////////////////////////////////////////
3571/// Template function to read basic value from JSON
3572
3573template <typename T>
3575{
3576 value = Stack()->GetStlNode()->get<T>();
3577}
3578
3579////////////////////////////////////////////////////////////////////////////////
3580/// Reads Bool_t value from buffer
3581
3583{
3584 JsonReadBasic(val);
3585}
3586
3587////////////////////////////////////////////////////////////////////////////////
3588/// Reads Char_t value from buffer
3589
3591{
3592 if (!Stack()->fValues.empty())
3593 val = (Char_t)Stack()->PopIntValue();
3594 else
3595 val = Stack()->GetStlNode()->get<Char_t>();
3596}
3597
3598////////////////////////////////////////////////////////////////////////////////
3599/// Reads UChar_t value from buffer
3600
3602{
3603 JsonReadBasic(val);
3604}
3605
3606////////////////////////////////////////////////////////////////////////////////
3607/// Reads Short_t value from buffer
3608
3610{
3611 JsonReadBasic(val);
3612}
3613
3614////////////////////////////////////////////////////////////////////////////////
3615/// Reads UShort_t value from buffer
3616
3618{
3619 JsonReadBasic(val);
3620}
3621
3622////////////////////////////////////////////////////////////////////////////////
3623/// Reads Int_t value from buffer
3624
3626{
3627 if (!Stack()->fValues.empty())
3628 val = Stack()->PopIntValue();
3629 else
3630 JsonReadBasic(val);
3631}
3632
3633////////////////////////////////////////////////////////////////////////////////
3634/// Reads UInt_t value from buffer
3635
3637{
3638 JsonReadBasic(val);
3639}
3640
3641////////////////////////////////////////////////////////////////////////////////
3642/// Reads Long_t value from buffer
3643
3645{
3646 JsonReadBasic(val);
3647}
3648
3649////////////////////////////////////////////////////////////////////////////////
3650/// Reads ULong_t value from buffer
3651
3653{
3654 JsonReadBasic(val);
3655}
3656
3657////////////////////////////////////////////////////////////////////////////////
3658/// Reads Long64_t value from buffer
3659
3661{
3662 JsonReadBasic(val);
3663}
3664
3665////////////////////////////////////////////////////////////////////////////////
3666/// Reads ULong64_t value from buffer
3667
3669{
3670 JsonReadBasic(val);
3671}
3672
3673////////////////////////////////////////////////////////////////////////////////
3674/// Reads Float_t value from buffer
3675
3677{
3678 nlohmann::json *json = Stack()->GetStlNode();
3679 if (json->is_null())
3680 val = std::numeric_limits<Float_t>::quiet_NaN();
3681 else
3682 val = json->get<Float_t>();
3683}
3684
3685////////////////////////////////////////////////////////////////////////////////
3686/// Reads Double_t value from buffer
3687
3689{
3690 nlohmann::json *json = Stack()->GetStlNode();
3691 if (json->is_null())
3692 val = std::numeric_limits<Double_t>::quiet_NaN();
3693 else
3694 val = json->get<Double_t>();
3695}
3696
3697////////////////////////////////////////////////////////////////////////////////
3698/// Reads array of characters from buffer
3699
3701{
3702 Error("ReadCharP", "Not implemented");
3703}
3704
3705////////////////////////////////////////////////////////////////////////////////
3706/// Reads a TString
3707
3709{
3710 std::string str;
3711 JsonReadBasic(str);
3712 val = str.c_str();
3713}
3714
3715////////////////////////////////////////////////////////////////////////////////
3716/// Reads a std::string
3717
3718void TBufferJSON::ReadStdString(std::string *val)
3719{
3720 JsonReadBasic(*val);
3721}
3722
3723////////////////////////////////////////////////////////////////////////////////
3724/// Reads a char* string
3725
3727{
3728 std::string str;
3729 JsonReadBasic(str);
3730
3731 if (s) {
3732 delete[] s;
3733 s = nullptr;
3734 }
3735
3736 std::size_t nch = str.length();
3737 if (nch > 0) {
3738 s = new char[nch + 1];
3739 memcpy(s, str.c_str(), nch);
3740 s[nch] = 0;
3741 }
3742}
3743
3744////////////////////////////////////////////////////////////////////////////////
3745/// Writes Bool_t value to buffer
3746
3752
3753////////////////////////////////////////////////////////////////////////////////
3754/// Writes Char_t value to buffer
3755
3761
3762////////////////////////////////////////////////////////////////////////////////
3763/// Writes UChar_t value to buffer
3764
3770
3771////////////////////////////////////////////////////////////////////////////////
3772/// Writes Short_t value to buffer
3773
3779
3780////////////////////////////////////////////////////////////////////////////////
3781/// Writes UShort_t value to buffer
3782
3788
3789////////////////////////////////////////////////////////////////////////////////
3790/// Writes Int_t value to buffer
3791
3793{
3794 JsonPushValue();
3795 JsonWriteBasic(i);
3796}
3797
3798////////////////////////////////////////////////////////////////////////////////
3799/// Writes UInt_t value to buffer
3800
3802{
3803 JsonPushValue();
3804 JsonWriteBasic(i);
3805}
3806
3807////////////////////////////////////////////////////////////////////////////////
3808/// Writes Long_t value to buffer
3809
3815
3816////////////////////////////////////////////////////////////////////////////////
3817/// Writes ULong_t value to buffer
3818
3824
3825////////////////////////////////////////////////////////////////////////////////
3826/// Writes Long64_t value to buffer
3827
3833
3834////////////////////////////////////////////////////////////////////////////////
3835/// Writes ULong64_t value to buffer
3836
3842
3843////////////////////////////////////////////////////////////////////////////////
3844/// Writes Float_t value to buffer
3845
3851
3852////////////////////////////////////////////////////////////////////////////////
3853/// Writes Double_t value to buffer
3854
3860
3861////////////////////////////////////////////////////////////////////////////////
3862/// Writes array of characters to buffer
3863
3865{
3866 JsonPushValue();
3867
3869}
3870
3871////////////////////////////////////////////////////////////////////////////////
3872/// Writes a TString
3873
3875{
3876 JsonPushValue();
3877
3878 JsonWriteConstChar(s.Data(), s.Length());
3879}
3880
3881////////////////////////////////////////////////////////////////////////////////
3882/// Writes a std::string
3883
3884void TBufferJSON::WriteStdString(const std::string *s)
3885{
3886 JsonPushValue();
3887
3888 if (s)
3889 JsonWriteConstChar(s->c_str(), s->length());
3890 else
3891 JsonWriteConstChar("", 0);
3892}
3893
3894////////////////////////////////////////////////////////////////////////////////
3895/// Writes a char*
3896
3898{
3899 JsonPushValue();
3900
3902}
3903
3904////////////////////////////////////////////////////////////////////////////////
3905/// converts Char_t to string and add to json value buffer
3906
3908{
3909 char buf[50];
3910 snprintf(buf, sizeof(buf), "%d", value);
3911 fValue.Append(buf);
3912}
3913
3914////////////////////////////////////////////////////////////////////////////////
3915/// converts Short_t to string and add to json value buffer
3916
3918{
3919 char buf[50];
3920 snprintf(buf, sizeof(buf), "%hd", value);
3921 fValue.Append(buf);
3922}
3923
3924////////////////////////////////////////////////////////////////////////////////
3925/// converts Int_t to string and add to json value buffer
3926
3928{
3929 char buf[50];
3930 snprintf(buf, sizeof(buf), "%d", value);
3931 fValue.Append(buf);
3932}
3933
3934////////////////////////////////////////////////////////////////////////////////
3935/// converts Long_t to string and add to json value buffer
3936
3938{
3939 char buf[50];
3940 snprintf(buf, sizeof(buf), "%ld", value);
3941 fValue.Append(buf);
3942}
3943
3944////////////////////////////////////////////////////////////////////////////////
3945/// converts Long64_t to string and add to json value buffer
3946
3948{
3949 fValue.Append(std::to_string(value).c_str());
3950}
3951
3952////////////////////////////////////////////////////////////////////////////////
3953/// converts Float_t to string and add to json value buffer
3954
3956{
3957 if (std::isinf(value)) {
3958 fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3959 } else if (std::isnan(value)) {
3960 fValue.Append("null");
3961 } else {
3962 char buf[200];
3963 ConvertFloat(value, buf, sizeof(buf));
3964 fValue.Append(buf);
3965 }
3966}
3967
3968////////////////////////////////////////////////////////////////////////////////
3969/// converts Double_t to string and add to json value buffer
3970
3972{
3973 if (std::isinf(value)) {
3974 fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3975 } else if (std::isnan(value)) {
3976 fValue.Append("null");
3977 } else {
3978 char buf[200];
3979 ConvertDouble(value, buf, sizeof(buf));
3980 fValue.Append(buf);
3981 }
3982}
3983
3984////////////////////////////////////////////////////////////////////////////////
3985/// converts Bool_t to string and add to json value buffer
3986
3988{
3989 fValue.Append(value ? "true" : "false");
3990}
3991
3992////////////////////////////////////////////////////////////////////////////////
3993/// converts UChar_t to string and add to json value buffer
3994
3996{
3997 char buf[50];
3998 snprintf(buf, sizeof(buf), "%u", value);
3999 fValue.Append(buf);
4000}
4001
4002////////////////////////////////////////////////////////////////////////////////
4003/// converts UShort_t to string and add to json value buffer
4004
4006{
4007 char buf[50];
4008 snprintf(buf, sizeof(buf), "%hu", value);
4009 fValue.Append(buf);
4010}
4011
4012////////////////////////////////////////////////////////////////////////////////
4013/// converts UInt_t to string and add to json value buffer
4014
4016{
4017 char buf[50];
4018 snprintf(buf, sizeof(buf), "%u", value);
4019 fValue.Append(buf);
4020}
4021
4022////////////////////////////////////////////////////////////////////////////////
4023/// converts ULong_t to string and add to json value buffer
4024
4026{
4027 char buf[50];
4028 snprintf(buf, sizeof(buf), "%lu", value);
4029 fValue.Append(buf);
4030}
4031
4032////////////////////////////////////////////////////////////////////////////////
4033/// converts ULong64_t to string and add to json value buffer
4034
4036{
4037 fValue.Append(std::to_string(value).c_str());
4038}
4039
4040////////////////////////////////////////////////////////////////////////////////
4041/// writes string value, processing all kind of special characters
4042
4043void TBufferJSON::JsonWriteConstChar(const char *value, Int_t len, const char * /* typname */)
4044{
4045 if (!value) {
4046
4047 fValue.Append("\"\"");
4048
4049 } else {
4050
4051 fValue.Append("\"");
4052
4053 if (len < 0)
4054 len = strlen(value);
4055
4056 for (Int_t n = 0; n < len; n++) {
4057 unsigned char c = value[n];
4058 switch (c) {
4059 case 0: n = len; break;
4060 case '\n': fValue.Append("\n"); break;
4061 case '\t': fValue.Append("\t"); break;
4062 case '\"': fValue.Append("\\""); break;
4063 case '\': fValue.Append("\\"); break;
4064 case '\b': fValue.Append("\b"); break;
4065 case '\f': fValue.Append("\f"); break;
4066 case '\r': fValue.Append("\r"); break;
4067 case '/': fValue.Append("\/"); break;
4068 default:
4069 if (c < 31) {
4070 fValue.Append(TString::Format("\u%04x", (unsigned)c));
4071 } else if (c < 0x80) {
4072 fValue.Append(c);
4073 } else if ((n < len - 1) && ((c & 0xe0) == 0xc0) && ((value[n+1] & 0xc0) == 0x80)) {
4074 unsigned code = ((unsigned)value[n+1] & 0x3f) | (((unsigned) c & 0x1f) << 6);
4075 fValue.Append(TString::Format("\u%04x", code));
4076 n++;
4077 } else if ((n < len - 2) && ((c & 0xf0) == 0xe0) && ((value[n+1] & 0xc0) == 0x80) && ((value[n+2] & 0xc0) == 0x80)) {
4078 unsigned code = ((unsigned)value[n+2] & 0x3f) | (((unsigned) value[n+1] & 0x3f) << 6) | (((unsigned) c & 0x0f) << 12);
4079 fValue.Append(TString::Format("\u%04x", code));
4080 n+=2;
4081 } else if ((n < len - 3) && ((c & 0xf8) == 0xf0) && ((value[n+1] & 0xc0) == 0x80) && ((value[n+2] & 0xc0) == 0x80) && ((value[n+3] & 0xc0) == 0x80)) {
4082 unsigned code = ((unsigned)value[n+3] & 0x3f) | (((unsigned) value[n+2] & 0x3f) << 6) | (((unsigned) value[n+1] & 0x3f) << 12) | (((unsigned) c & 0x07) << 18);
4083 // TODO: no idea how to add codes which are higher then 0xFFFF
4084 fValue.Append(TString::Format("\u%04x\u%04x", code & 0xffff, code >> 16));
4085 n+=3;
4086 } else {
4087 fValue.Append(TString::Format("\u%04x", (unsigned)c));
4088 }
4089 }
4090 }
4091
4092 fValue.Append("\"");
4093 }
4094}
4095
4096////////////////////////////////////////////////////////////////////////////////
4097/// Read data of base class.
4098
4100{
4101 if (elem->GetClassPointer() == TObject::Class()) {
4103 } else {
4105 }
4106}
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:82
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:101
long long Long64_t
Definition RtypesCore.h:80
unsigned long long ULong64_t
Definition RtypesCore.h:81
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
#define ClassImp(name)
Definition Rtypes.h:377
@ 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.
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 Returns string with converted member.
void ReadInt(Int_t &i) final
Reads Int_t value from buffer.
std::vector< const TClass * > fSkipClasses
! list of classes, which class info is not stored
@ 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 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:81
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2886
Bool_t HasDictionary() const
Check whether a class has a dictionary or not.
Definition TClass.cxx:3919
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5413
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5717
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:5951
Int_t GetBaseClassOffset(const TClass *toBase, void *address=nullptr, bool isDerivedObject=true)
Definition TClass.cxx:2791
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2897
Version_t GetClassVersion() const
Definition TClass.h:420
TClass * GetActualClass(const void *object) const
Return a pointer to the real class of the object.
Definition TClass.cxx:2607
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:2968
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
Option_t * GetOption() const
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()
TObject * GetValue(const char *keyname) const
Returns a pointer to the value associated with keyname as name of the key.
Definition TMap.cxx:236
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
Mother of all ROOT objects.
Definition TObject.h:41
@ kIsOnHeap
object is on heap
Definition TObject.h:81
@ kNotDeleted
object has not been deleted
Definition TObject.h:82
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:973
static TClass * Class()
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:525
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:987
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1015
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:961
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
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