Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TRootSnifferFull.cxx
Go to the documentation of this file.
1// $Id$
2// Author: Sergey Linev 22/12/2013
3
4/*************************************************************************
5 * Copyright (C) 1995-2013, 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#include "TRootSnifferFull.h"
13
14#include "TH1.h"
15#include "TGraph.h"
16#include "TProfile.h"
17#include "TCanvas.h"
18#include "TFile.h"
19#include "TKey.h"
20#include "TList.h"
21#include "TMemFile.h"
22#include "TBufferFile.h"
23#include "TBufferJSON.h"
24#include "TBufferXML.h"
25#include "TROOT.h"
26#include "TFolder.h"
27#include "TTree.h"
28#include "TBranch.h"
29#include "TLeaf.h"
30#include "TClass.h"
31#include "TMethod.h"
32#include "TFunction.h"
33#include "TMethodArg.h"
34#include "TMethodCall.h"
35#include "TUrl.h"
36#include "TImage.h"
37#include "TVirtualMutex.h"
38#include "TRootSnifferStore.h"
39#include "THttpCallArg.h"
40
41#include <cstdlib>
42#include <cstring>
43
44/** \class TRootSnifferFull
45\ingroup http
46
47Extends TRootSniffer for many ROOT classes
48
49Provides access to different ROOT collections and containers
50like TTree, TCanvas, TFile, ...
51*/
52
53
54////////////////////////////////////////////////////////////////////////////////
55/// constructor
56
60
61////////////////////////////////////////////////////////////////////////////////
62/// destructor
63
65{
66 delete fSinfo;
67
68 delete fMemFile;
69}
70
71////////////////////////////////////////////////////////////////////////////////
72/// return true if given class can be drawn in JSROOT
73
75{
76 if (!cl)
77 return kFALSE;
78 if (cl->InheritsFrom(TH1::Class()))
79 return kTRUE;
80 if (cl->InheritsFrom(TGraph::Class()))
81 return kTRUE;
83 return kTRUE;
85 return kTRUE;
86 return kFALSE;
87}
88
89////////////////////////////////////////////////////////////////////////////////
90/// Scans object properties
91///
92/// here such fields as `_autoload` or `_icon` properties depending on class or object name could be assigned
93/// By default properties, coded in the Class title are scanned. Example:
94///
95/// ClassDef(UserClassName, 1) // class comments *SNIFF* _field1=value _field2="string value"
96///
97/// Here *SNIFF* mark is important. After it all expressions like field=value are parsed
98/// One could use double quotes to code string values with spaces.
99/// Fields separated from each other with spaces
100
102{
103 if (obj && obj->InheritsFrom(TLeaf::Class())) {
104 rec.SetField("_more", "false", kFALSE);
105 rec.SetField("_can_draw", "false", kFALSE);
106 rec.SetField("_player", "drawLeafPlayer");
107 rec.SetField("_module", "draw_tree");
108 return;
109 }
110
112}
113
114////////////////////////////////////////////////////////////////////////////////
115/// Scans TKey properties
116///
117/// in special cases load objects from the file
118
120{
121 if (strcmp(key->GetClassName(), "TDirectoryFile") == 0) {
123 } else {
125 if (obj_class && obj_class->InheritsFrom(TTree::Class())) {
126 if (rec.CanExpandItem()) {
127 // it is requested to expand tree element - read it
128 obj = key->ReadObj();
129 if (obj)
130 obj_class = obj->IsA();
131 } else {
132 rec.SetField("_ttree", "true", kFALSE); // indicate ROOT TTree
133 rec.SetField("_player", "drawTreePlayerKey");
134 rec.SetField("_module", "draw_tree");
135 // rec.SetField("_more", "true", kFALSE); // one could allow to extend
136 }
137 }
138 }
139}
140
141////////////////////////////////////////////////////////////////////////////////
142/// Scans object childs (if any)
143///
144/// here one scans collection, branches, trees and so on
145
147{
148 if (obj->InheritsFrom(TTree::Class())) {
149 if (!rec.IsReadOnly(fReadOnly)) {
150 rec.SetField("_ttree", "true", kFALSE); // indicate ROOT TTree
151 rec.SetField("_player", "drawTreePlayer");
152 rec.SetField("_module", "draw_tree");
153 }
154 ScanCollection(rec, ((TTree *)obj)->GetListOfLeaves());
155 } else if (obj->InheritsFrom(TBranch::Class())) {
156 ScanCollection(rec, ((TBranch *)obj)->GetListOfLeaves());
157 } else {
159 }
160}
161
162////////////////////////////////////////////////////////////////////////////////
163/// Returns hash value for streamer infos
164///
165/// At the moment - just number of items in streamer infos list.
166
171
172////////////////////////////////////////////////////////////////////////////////
173/// Return true if it is streamer info item name
174
176{
177 if (!itemname || (*itemname == 0))
178 return kFALSE;
179
180 return (strcmp(itemname, "StreamerInfo") == 0) || (strcmp(itemname, "StreamerInfo/") == 0);
181}
182
183////////////////////////////////////////////////////////////////////////////////
184/// Get hash function for specified item
185///
186/// Used to detect any changes in the specified object
187
195
196////////////////////////////////////////////////////////////////////////////////
197/// Creates TMemFile instance, which used for objects streaming
198///
199/// One could not use TBufferFile directly,
200/// while one also require streamer infos list
201
203{
204 if (fMemFile)
205 return;
206
208 gDirectory = nullptr;
210 gFile = nullptr;
211
212 fMemFile = new TMemFile("dummy.file", "RECREATE");
213 gROOT->GetListOfFiles()->Remove(fMemFile);
214
215 TH1F *d = new TH1F("d", "d", 10, 0, 10);
216 fMemFile->WriteObject(d, "h1");
217 delete d;
218
219 TGraph *gr = new TGraph(10);
220 gr->SetName("abc");
221 // // gr->SetDrawOptions("AC*");
222 fMemFile->WriteObject(gr, "gr1");
223 delete gr;
224
226
227 // make primary list of streamer infos
228 TList *l = new TList();
229
230 l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TGraph"));
231 l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TH1F"));
232 l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TH1"));
233 l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TNamed"));
234 l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TObject"));
235
236 fMemFile->WriteObject(l, "ll");
237 delete l;
238
240
242
244 gFile = oldfile;
245}
246
247////////////////////////////////////////////////////////////////////////////////
248/// Search element with specified path
249///
250/// Returns pointer on element
251///
252/// Optionally one could obtain element class, member description
253/// and number of childs. When chld!=0, not only element is searched,
254/// but also number of childs are counted. When member!=0, any object
255/// will be scanned for its data members (disregard of extra options)
256
258{
259 if (IsStreamerInfoItem(path)) {
260 // special handling for streamer info
262 if (cl && fSinfo)
263 *cl = fSinfo->IsA();
264 return fSinfo;
265 }
266
267 return TRootSniffer::FindInHierarchy(path, cl, member, chld);
268}
269
270////////////////////////////////////////////////////////////////////////////////
271/// Produce binary data for specified item
272///
273/// if "zipped" option specified in query, buffer will be compressed
274
275Bool_t TRootSnifferFull::ProduceBinary(const std::string &path, const std::string & /*query*/, std::string &res)
276{
277 if (path.empty())
278 return kFALSE;
279
280 const char *path_ = path.c_str();
281 if (*path_ == '/')
282 path_++;
283
284 TClass *obj_cl = nullptr;
286 if (!obj_ptr || !obj_cl)
287 return kFALSE;
288
289 if (obj_cl->GetBaseClassOffset(TObject::Class()) != 0) {
290 Info("ProduceBinary", "Non-TObject class not supported");
291 return kFALSE;
292 }
293
294 // ensure that memfile exists
296
298 gDirectory = nullptr;
300 gFile = nullptr;
301
302 TObject *obj = (TObject *)obj_ptr;
303
305 sbuf->SetParent(fMemFile);
306 sbuf->MapObject(obj);
307 obj->Streamer(*sbuf);
308 if (fCurrentArg)
309 fCurrentArg->SetExtraHeader("RootClassName", obj_cl->GetName());
310
311 // produce actual version of streamer info
312 delete fSinfo;
315
317 gFile = oldfile;
318
319 res.resize(sbuf->Length());
320 std::copy((const char *)sbuf->Buffer(), (const char *)sbuf->Buffer() + sbuf->Length(), res.begin());
321
322 delete sbuf;
323
324 return kTRUE;
325}
326
327////////////////////////////////////////////////////////////////////////////////
328/// Produce ROOT file for specified item
329///
330/// File created in memory using TMemFile class.
331
332Bool_t TRootSnifferFull::ProduceRootFile(const std::string &path, const std::string & /*query*/, std::string &res)
333{
334 if (path.empty())
335 return kFALSE;
336
337 const char *path_ = path.c_str();
338 if (*path_ == '/')
339 path_++;
340
341 TClass *obj_cl = nullptr;
343 if (!obj_ptr || !obj_cl)
344 return kFALSE;
345
346 const char *store_name = "object";
347
348 if (obj_cl->GetBaseClassOffset(TNamed::Class()) == 0) {
349 const char *obj_name = ((TNamed *) obj_ptr)->GetName();
350 if (obj_name && *obj_name)
352 }
353
355 gDirectory = nullptr;
357 gFile = nullptr;
358
359 {
360 TMemFile memfile("dummy.file", "RECREATE");
361 gROOT->GetListOfFiles()->Remove(&memfile);
362
363 memfile.WriteObjectAny(obj_ptr, obj_cl, store_name);
364 memfile.Close();
365
366 res.resize(memfile.GetSize());
367 memfile.CopyTo(res.data(), memfile.GetSize());
368 }
369
371 gFile = oldfile;
372
373 return kTRUE;
374}
375
376
377////////////////////////////////////////////////////////////////////////////////
378/// Method to produce image from specified object
379///
380/// @param kind image kind TImage::kPng, TImage::kJpeg, TImage::kGif
381/// @param path path to object
382/// @param options extra options
383/// @param res std::string with binary data
384///
385/// By default, image 300x200 is produced
386/// In options string one could provide following parameters:
387///
388/// * w - image width
389/// * h - image height
390/// * opt - draw options
391///
392/// For instance:
393///
394/// http://localhost:8080/Files/hsimple.root/hpx/get.png?w=500&h=500&opt=lego1
395
396Bool_t TRootSnifferFull::ProduceImage(Int_t kind, const std::string &path, const std::string &options, std::string &res)
397{
398 if (path.empty())
399 return kFALSE;
400
401 const char *path_ = path.c_str();
402 if (*path_ == '/')
403 path_++;
404
405 TClass *obj_cl(nullptr);
407 if (!obj_ptr || !obj_cl)
408 return kFALSE;
409
410 if (obj_cl->GetBaseClassOffset(TObject::Class()) != 0) {
411 Error("TRootSniffer", "Only derived from TObject classes can be drawn");
412 return kFALSE;
413 }
414
415 TObject *obj = (TObject *)obj_ptr;
416
418 if (!img)
419 return kFALSE;
420
421 if (obj->InheritsFrom(TPad::Class())) {
422
423 if (gDebug > 1)
424 Info("TRootSniffer", "Crate IMAGE directly from pad");
425 img->FromPad((TPad *)obj);
426 } else if (CanDrawClass(obj->IsA())) {
427
428 if (gDebug > 1)
429 Info("TRootSniffer", "Crate IMAGE from object %s", obj->GetName());
430
431 Int_t width = 300, height = 200;
432 TString drawopt;
433
434 if (!options.empty()) {
435 TUrl url;
436 url.SetOptions(options.c_str());
437 url.ParseOptions();
438 Int_t w = url.GetIntValueFromOptions("w");
439 if (w > 10)
440 width = w;
441 Int_t h = url.GetIntValueFromOptions("h");
442 if (h > 10)
443 height = h;
444 drawopt = DecodeUrlOptionValue(url.GetValueFromOptions("opt"), kTRUE);
445 }
446
447 Bool_t isbatch = gROOT->IsBatch();
449
450 if (!isbatch)
451 gROOT->SetBatch(kTRUE);
452
453 TCanvas *c1 = new TCanvas("__online_draw_canvas__", "title", width, height);
454 obj->Draw(drawopt.Data());
455 img->FromPad(c1);
456 delete c1;
457
458 if (!isbatch)
459 gROOT->SetBatch(kFALSE);
460
461 } else {
462 delete img;
463 return kFALSE;
464 }
465
467 im->Append(img);
468
469 char *png_buffer = nullptr;
470 int size(0);
471
472 im->GetImageBuffer(&png_buffer, &size, (TImage::EImageFileTypes)kind);
473
474 if (png_buffer && (size > 0)) {
475 res.resize(size);
476 memcpy((void *)res.data(), png_buffer, size);
477 }
478
480 delete im;
481
482 return !res.empty();
483}
484
485////////////////////////////////////////////////////////////////////////////////
486/// Invokes TRootSniffer::ProduceIamge, converting kind into TImage::EImageFileTypes type
487
488Bool_t TRootSnifferFull::CallProduceImage(const std::string &kind, const std::string &path, const std::string &options, std::string &res)
489{
490 if (kind == "png")
491 return ProduceImage(TImage::kPng, path, options, res);
492
493 if (kind == "jpeg")
494 return ProduceImage(TImage::kJpeg, path, options, res);
495
496 if (kind == "gif")
497 return ProduceImage(TImage::kGif, path, options, res);
498
499 return kFALSE;
500}
501
502////////////////////////////////////////////////////////////////////////////////
503/// Produce XML data for specified item
504///
505/// For object conversion TBufferXML is used
506
507Bool_t TRootSnifferFull::ProduceXml(const std::string &path, const std::string & /*options*/, std::string &res)
508{
509 if (path.empty())
510 return kFALSE;
511 const char *path_ = path.c_str();
512 if (*path_ == '/')
513 path_++;
514
515 TClass *obj_cl = nullptr;
517 if (!obj_ptr || !obj_cl)
518 return kFALSE;
519
520 // TODO: support std::string in TBufferXML
522
523 return !res.empty();
524}
525
526class TArgHolderBase : public TObject {
527 public:
529 virtual const void *GetPtr() const { return nullptr; }
530};
531
532template<typename T>
534 public:
537 const void *GetPtr() const override { return &fValue; }
538};
539
541 public:
543 const char *fBuf = nullptr;
544 TArgHolderConstChar(const char *v) : fValue(v) { fBuf = fValue.Data(); }
545 const void *GetPtr() const override { return &fBuf; }
546};
547
548
549////////////////////////////////////////////////////////////////////////////////
550/// Execute command for specified object
551///
552/// @param path the object path
553/// @param options include method and extra list of parameters
554/// sniffer should be not-readonly to allow execution of the commands
555/// @param reskind defines kind of result 0 - debug, 1 - json, 2 - binary
556/// @param res_str result string
557
558Bool_t TRootSnifferFull::ProduceExe(const std::string &path, const std::string &options, Int_t reskind, std::string &res_str)
559{
560 std::string *debug = (reskind == 0) ? &res_str : nullptr;
561
562 if (path.empty()) {
563 if (debug)
564 debug->append("Item name not specified\n");
565 return debug != nullptr;
566 }
567
568 const char *path_ = path.c_str();
569 if (*path_ == '/')
570 path_++;
571
572 TClass *obj_cl = nullptr;
574 if (debug)
575 debug->append(TString::Format("Item:%s found:%s\n", path_, obj_ptr ? "true" : "false").Data());
576 if (!obj_ptr || !obj_cl)
577 return debug != nullptr;
578
579 TUrl url;
580 url.SetOptions(options.c_str());
581
582 const char *method_name = url.GetValueFromOptions("method");
583 TString prototype = DecodeUrlOptionValue(url.GetValueFromOptions("prototype"), kTRUE);
584 TString funcname = DecodeUrlOptionValue(url.GetValueFromOptions("func"), kTRUE);
585 TMethod *method = nullptr;
586 TFunction *func = nullptr;
587 if (method_name) {
588 if (prototype.Length() == 0) {
589 if (debug)
590 debug->append(TString::Format("Search for any method with name \'%s\'\n", method_name).Data());
591 method = obj_cl->GetMethodAllAny(method_name);
592 } else {
593 if (debug)
594 debug->append(
595 TString::Format("Search for method \'%s\' with prototype \'%s\'\n", method_name, prototype.Data())
596 .Data());
597 method = obj_cl->GetMethodWithPrototype(method_name, prototype);
598 }
599 }
600
601 if (method) {
602 if (debug)
603 debug->append(TString::Format("Method: %s\n", method->GetPrototype()).Data());
604 } else {
605 if (funcname.Length() > 0) {
606 if (prototype.Length() == 0) {
607 if (debug)
608 debug->append(TString::Format("Search for any function with name \'%s\'\n", funcname.Data()).Data());
609 func = gROOT->GetGlobalFunction(funcname);
610 } else {
611 if (debug)
612 debug->append(TString::Format("Search for function \'%s\' with prototype \'%s\'\n", funcname.Data(),
613 prototype.Data())
614 .Data());
615 func = gROOT->GetGlobalFunctionWithPrototype(funcname, prototype);
616 }
617 }
618
619 if (func && debug)
620 debug->append(TString::Format("Function: %s\n", func->GetPrototype()).Data());
621 }
622
623 if (!method && !func) {
624 if (debug)
625 debug->append("Method not found\n");
626 return debug != nullptr;
627 }
628
629 if ((fReadOnly && (fCurrentRestrict == 0)) || (fCurrentRestrict == 1)) {
630 if ((method != nullptr) && (fCurrentAllowedMethods.Index(method_name) == kNPOS)) {
631 if (debug)
632 debug->append("Server runs in read-only mode, method cannot be executed\n");
633 return debug != nullptr;
634 } else if ((func != nullptr) && (fCurrentAllowedMethods.Index(funcname) == kNPOS)) {
635 if (debug)
636 debug->append("Server runs in read-only mode, function cannot be executed\n");
637 return debug != nullptr;
638 } else {
639 if (debug)
640 debug->append("For that special method server allows access even read-only mode is specified\n");
641 }
642 }
643
644 TList *args = method ? method->GetListOfMethodArgs() : func->GetListOfMethodArgs();
645
647 garbage.SetOwner(kTRUE); // use as garbage collection
648 TObject *post_obj = nullptr; // object reconstructed from post request
650 std::vector<const void *> plain_args;
652
654 plain_args.emplace_back(arg->GetPtr());
655 garbage.Add(arg);
657 };
658
659 TIter next(args);
660 while (auto arg = static_cast<TMethodArg *>(next())) {
662
663 if ((strcmp(arg->GetName(), "rest_url_opt") == 0) && (strcmp(arg->GetFullTypeName(), "const char*") == 0) &&
664 (args->GetSize() == 1)) {
665 // very special case - function requires list of options after method=argument
666
667 const char *pos = strstr(options.c_str(), "method=");
668 if (!pos || (strlen(pos) < strlen(method_name) + 7))
669 return debug != nullptr;
670 const char *rest_url = pos + strlen(method_name) + 7;
671 if (*rest_url == '&') ++rest_url;
672 call_args.Append("\"");
674 call_args.Append("\"");
676 break;
677 }
678
680 const char *val = url.GetValueFromOptions(arg->GetName());
681 if (val)
683
685
686 if (sval == "_this_") {
687 // special case - object itself is used as argument
688 sval.Form("(%s*)0x%zx", obj_cl->GetName(), (size_t)obj_ptr);
690 } else if ((fCurrentArg != nullptr) && (fCurrentArg->GetPostData() != nullptr)) {
691 // process several arguments which are specific for post requests
692 if (fAllowPostObject && (sval == "_post_object_xml_")) {
693 // post data has extra 0 at the end and can be used as null-terminated string
695 if (!post_obj)
696 sval = "0";
697 else {
698 sval.Form("(%s*)0x%zx", post_obj->ClassName(), (size_t)post_obj);
699 if (url.HasOption("_destroy_post_"))
700 garbage.Add(post_obj);
701 }
703 } else if (fAllowPostObject && (sval == "_post_object_json_")) {
704 // post data has extra 0 at the end and can be used as null-terminated string
706 if (!post_obj)
707 sval = "0";
708 else {
709 sval.Form("(%s*)0x%zx", post_obj->ClassName(), (size_t)post_obj);
710 if (url.HasOption("_destroy_post_"))
711 garbage.Add(post_obj);
712 }
714 } else if (fAllowPostObject && (sval == "_post_object_") && url.HasOption("_post_class_")) {
715 TString clname = DecodeUrlOptionValue(url.GetValueFromOptions("_post_class_"), kTRUE);
716 TClass *arg_cl = gROOT->GetClass(clname, kTRUE, kTRUE);
717 if ((arg_cl != nullptr) && (arg_cl->GetBaseClassOffset(TObject::Class()) == 0) && (post_obj == nullptr)) {
718 post_obj = (TObject *)arg_cl->New();
719 if (post_obj == nullptr) {
720 if (debug)
721 debug->append(TString::Format("Fail to create object of class %s\n", clname.Data()).Data());
722 } else {
723 if (debug)
724 debug->append(TString::Format("Reconstruct object of class %s from POST data\n", clname.Data()).Data());
727 post_obj->Streamer(buf);
728 if (url.HasOption("_destroy_post_"))
729 garbage.Add(post_obj);
730 }
731 }
732 if (!post_obj)
733 sval = "0";
734 else
735 sval.Form("(%s*)0x%zx", clname.Data(), (size_t)post_obj);
737 } else if (sval == "_post_data_") {
738 sval.Form("(void*)0x%zx", (size_t)fCurrentArg->GetPostData());
740 } else if (sval == "_post_length_")
741 sval.Form("%ld", (long)fCurrentArg->GetPostDataLength());
742 else
744 } else
746
747 if (sval.IsNull() && arg->GetDefault())
748 sval = arg->GetDefault();
749
750 if (debug)
751 debug->append(
752 TString::Format(" Argument:%s Type:%s Value:%s \n", arg->GetName(), arg->GetFullTypeName(), sval.Data())
753 .Data());
754
755 if (call_args.Length() > 0)
756 call_args += ", ";
757
758 if (!add_plain) {
759 std::string tname = arg->GetTypeNormalizedName();
760 if (tname == "const char*")
761 // one can use original string, just remove optional quotes
763 else if (tname == "bool")
764 add_plain_arg(new TArgHolder<bool>(!sval.IsNull() && (sval != "0") && (sval != "false")));
765 else if (tname == "double")
766 add_plain_arg(new TArgHolder<double>(std::stod(sval.Data())));
767 else if (tname == "float")
768 add_plain_arg(new TArgHolder<float>(std::stof(sval.Data())));
769 else if (tname == "int")
770 add_plain_arg(new TArgHolder<int>(std::stol(sval.Data())));
771 else if (tname == "long")
772 add_plain_arg(new TArgHolder<long>(std::stol(sval.Data())));
773 else if (tname == "short")
774 add_plain_arg(new TArgHolder<short>(std::stol(sval.Data())));
775 else if (tname == "char")
776 add_plain_arg(new TArgHolder<char>(std::stol(sval.Data())));
777 else if (tname == "unsigned int")
778 add_plain_arg(new TArgHolder<unsigned int>(std::stoul(sval.Data())));
779 else if (tname == "unisgned long")
780 add_plain_arg(new TArgHolder<unsigned long>(std::stoul(sval.Data())));
781 else if (tname == "unsigned short")
782 add_plain_arg(new TArgHolder<unsigned short>(std::stoul(sval.Data())));
783 else if (tname == "unsigned char")
784 add_plain_arg(new TArgHolder<unsigned char>(std::stoul(sval.Data())));
785 else if (!tname.empty() && tname.back() == '*' && (sval == "0" || sval == "null" || sval == "nullptr"))
787 else
788 can_use_plain = kFALSE; // unsupported type, plain args cannot be used
789 }
790
791 Bool_t isstr = (strcmp(arg->GetFullTypeName(), "const char*") == 0) ||
792 (strcmp(arg->GetFullTypeName(), "Option_t*") == 0) ||
793 (strcmp(arg->GetFullTypeName(), "string") == 0);
794
795 if (isstr) {
796 // check that quotes provided for the string argument
797 // all special characters were escaped before
798 if (sval.IsNull())
799 sval = "\"\"";
800 else {
801 if (sval[0] != '"')
802 sval.Prepend("\"");
803 if (sval[sval.Length() - 1] != '"')
804 sval.Append("\"");
805 }
806 } else {
807 // for numeric types keep only numeric and alphabetic characters
808 // exclude others - especially remove all escape characters
809 if (sanitize_numeric) {
811 for(Size_t i = 0; i < sval.Length(); ++i) {
812 if (std::isalnum(sval[i]) || std::strchr(".:+-", sval[i]))
813 sanitized.Append(sval[i]);
814 }
815 sval = sanitized;
816 }
817 if (sval.IsNull())
818 sval = "0";
819 }
820
821 call_args.Append(sval);
822 }
823
824 TMethodCall *call = nullptr;
825
826 if (method != nullptr) {
827 if (can_use_plain) {
828 // prevent creation of huge cache
829 if (fExeCache.size() > 1000)
830 fExeCache.clear();
831 auto iter = fExeCache.find(method);
832 if (iter != fExeCache.end()) {
833 call = iter->second.get();
834 } else {
835 call = new TMethodCall();
836 call->InitWithPrototype(obj_cl, method_name, prototype.IsNull() ? nullptr : prototype.Data());
837 fExeCache.emplace(method, std::unique_ptr<TMethodCall>(call));
838 }
839 } else {
840 call = new TMethodCall(obj_cl, method_name, call_args.Data());
841 garbage.Add(call);
842 }
843 if (debug)
844 debug->append(TString::Format("Calling obj->%s(%s);\n", method_name, call_args.Data()).Data());
845 } else {
846 call = new TMethodCall(funcname.Data(), call_args.Data());
847 garbage.Add(call);
848 if (debug)
849 debug->append(TString::Format("Calling %s(%s);\n", funcname.Data(), call_args.Data()).Data());
850 }
851
852 if (!call->IsValid()) {
853 if (debug)
854 debug->append("Fail: invalid TMethodCall\n");
855 return debug != nullptr;
856 }
857
858 Int_t compact = 0;
859 if (url.GetValueFromOptions("compact"))
860 compact = url.GetIntValueFromOptions("compact");
861
862 TString res = "null";
863 void *ret_obj = nullptr;
864 TClass *ret_cl = nullptr;
865 TBufferFile *resbuf = nullptr;
866 if (reskind == 2) {
867 resbuf = new TBufferFile(TBuffer::kWrite, 10000);
868 garbage.Add(resbuf);
869 }
870
871 auto ret_type = call->ReturnType();
872 if (ret_type == TMethodCall::kOther) {
873 std::string ret_kind = func ? func->GetReturnTypeNormalizedName() : method->GetReturnTypeNormalizedName();
874 if ((ret_kind.length() > 0) && (ret_kind[ret_kind.length() - 1] == '*')) {
875 ret_kind.resize(ret_kind.length() - 1);
876 ret_cl = gROOT->GetClass(ret_kind.c_str(), kTRUE, kTRUE);
877 }
878 if (!ret_cl)
879 ret_type = TMethodCall::kNone;
880 }
881
882 switch (ret_type) {
883 case TMethodCall::kLong: {
884 Longptr_t l = 0;
885 if (method && can_use_plain)
886 call->Execute(obj_ptr, plain_args.data(), plain_args.size(), &l);
887 else if (method)
888 call->Execute(obj_ptr, l);
889 else
890 call->Execute(l);
891 if (resbuf)
892 resbuf->WriteLong(l);
893 else
894 res.Form("%zd", (size_t)l);
895 break;
896 }
898 Double_t d = 0.;
899 if (method && can_use_plain)
900 call->Execute(obj_ptr, plain_args.data(), plain_args.size(), &d);
901 else if (method)
902 call->Execute(obj_ptr, d);
903 else
904 call->Execute(d);
905 if (resbuf)
906 resbuf->WriteDouble(d);
907 else
909 break;
910 }
912 char *txt = nullptr;
913 if (method && can_use_plain)
914 call->Execute(obj_ptr, plain_args.data(), plain_args.size(), &txt);
915 else if (method)
916 call->Execute(obj_ptr, &txt);
917 else
918 call->Execute(&txt);
919 if (txt != nullptr) {
920 if (resbuf)
921 resbuf->WriteString(txt);
922 else
923 res.Form("\"%s\"", txt);
924 }
925 break;
926 }
927 case TMethodCall::kOther: {
928 Longptr_t l = 0;
929 if (method && can_use_plain)
930 call->Execute(obj_ptr, plain_args.data(), plain_args.size(), &l);
931 else if (method)
932 call->Execute(obj_ptr, l);
933 else
934 call->Execute(l);
935 if (l != 0)
936 ret_obj = (void *)l;
937 break;
938 }
939 case TMethodCall::kNone: {
940 if (method && can_use_plain)
941 call->Execute(obj_ptr, plain_args.data(), plain_args.size());
942 else if (method)
943 call->Execute(obj_ptr);
944 else
945 call->Execute();
946 break;
947 }
948 }
949
950 const char *_ret_object_ = url.GetValueFromOptions("_ret_object_");
951 if (_ret_object_ != nullptr) {
952 TObject *obj = nullptr;
953 if (gDirectory)
954 obj = gDirectory->Get(_ret_object_);
955 if (debug)
956 debug->append(TString::Format("Return object %s found %s\n", _ret_object_, obj ? "true" : "false").Data());
957
958 if (obj == nullptr) {
959 res = "null";
960 } else {
961 ret_obj = obj;
962 ret_cl = obj->IsA();
963 }
964 }
965
966 if (ret_obj && ret_cl) {
967 if ((resbuf != nullptr) && (ret_cl->GetBaseClassOffset(TObject::Class()) == 0)) {
968 TObject *obj = (TObject *)ret_obj;
969 resbuf->MapObject(obj);
970 obj->Streamer(*resbuf);
971 if (fCurrentArg)
972 fCurrentArg->SetExtraHeader("RootClassName", ret_cl->GetName());
973 } else {
975 }
976 }
977
978 if ((resbuf != nullptr) && (resbuf->Length() > 0)) {
979 res_str.resize(resbuf->Length());
980 std::copy((const char *)resbuf->Buffer(), (const char *)resbuf->Buffer() + resbuf->Length(), res_str.begin());
981 }
982
983 if (debug)
984 debug->append(TString::Format("Result = %s\n", res.Data()).Data());
985
986 if (reskind == 1)
987 res_str = res.Data();
988
989 if (url.HasOption("_destroy_result_") && ret_obj && ret_cl) {
990 ret_cl->Destructor(ret_obj);
991 if (debug)
992 debug->append("Destroy result object at the end\n");
993 }
994
995 // delete all garbage objects, but should be also done with any return
996 garbage.Delete();
997
998 return kTRUE;
999}
#define d(i)
Definition RSha256.hxx:102
#define h(i)
Definition RSha256.hxx:106
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
float Size_t
Attribute size (float)
Definition RtypesCore.h:103
long Longptr_t
Integer large enough to hold a pointer (platform-dependent)
Definition RtypesCore.h:89
unsigned long ULong_t
Unsigned long integer 4 bytes (unsigned long). Size depends on architecture.
Definition RtypesCore.h:69
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:385
#define gFile
Definition TFile.h:429
Option_t Option_t width
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
char name[80]
Definition TGX11.cxx:110
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:627
#define gROOT
Definition TROOT.h:411
#define free
Definition civetweb.c:1578
const_iterator begin() const
virtual const void * GetPtr() const
TArgHolderConstChar(const char *v)
const void * GetPtr() const override
const void * GetPtr() const override
A TTree is a list of TBranches.
Definition TBranch.h:93
static TClass * Class()
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition TBufferFile.h:47
void MapObject(const TObject *obj, UInt_t offset=1) override
Add object to the fMap container.
static TObject * ConvertFromJSON(const char *str)
Read TObject-based class from JSON, produced by ConvertToJSON() method.
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...
static const char * GetFloatFormat()
return current printf format for float members, default "%e"
static TString ConvertToXML(const TObject *obj, Bool_t GenericLayout=kFALSE, Bool_t UseNamespaces=kFALSE)
Converts object, inherited from TObject class, to XML string GenericLayout defines layout choice for ...
static TObject * ConvertFromXML(const char *str, Bool_t GenericLayout=kFALSE, Bool_t UseNamespaces=kFALSE)
Read object from XML, produced by ConvertToXML() method.
@ kWrite
Definition TBuffer.h:73
@ kRead
Definition TBuffer.h:73
The Canvas class.
Definition TCanvas.h:23
static TClass * Class()
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4901
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:2973
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Describe directory structure in memory.
Definition TDirectory.h:45
std::enable_if_t<!std::is_base_of< TObject, T >::value, Int_t > WriteObject(const T *obj, const char *name, Option_t *option="", Int_t bufsize=0)
Write an object with proper type checking.
Definition TDirectory.h:283
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
virtual void WriteStreamerInfo()
Write the list of TStreamerInfo as a single object in this file The class Streamer description for al...
Definition TFile.cxx:3489
virtual TList * GetStreamerInfoList() final
Read the list of TStreamerInfo objects written to this file.
Definition TFile.cxx:1456
Global functions class (global functions are obtained from CINT).
Definition TFunction.h:30
virtual const char * GetPrototype() const
Returns the prototype of a function as defined by CINT, or 0 in case of error.
TList * GetListOfMethodArgs()
Return list containing the TMethodArgs of a TFunction.
std::string GetReturnTypeNormalizedName() const
Get the normalized name of the return type.
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
static TClass * Class()
void SetName(const char *name="") override
Set graph name.
Definition TGraph.cxx:2355
1-D histogram with a float per channel (see TH1 documentation)
Definition TH1.h:878
static TClass * Class()
const void * GetPostData() const
return pointer on posted with request data
void SetExtraHeader(const char *name, const char *value)
add extra http header value to the reply
Long_t GetPostDataLength() const
return length of posted with request data
An abstract interface to image processing library.
Definition TImage.h:29
EImageFileTypes
Definition TImage.h:36
@ kPng
Definition TImage.h:40
@ kJpeg
Definition TImage.h:41
@ kGif
Definition TImage.h:48
static TImage * Create()
Create an image.
Definition TImage.cxx:34
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
virtual const char * GetClassName() const
Definition TKey.h:75
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition TKey.cxx:773
static TClass * Class()
A doubly linked list.
Definition TList.h:38
TClass * IsA() const override
Definition TList.h:110
A TMemFile is like a normal TFile except that it reads and writes only from memory.
Definition TMemFile.h:19
Each ROOT method (see TMethod) has a linked list of its arguments.
Definition TMethodArg.h:36
Method or function calling interface.
Definition TMethodCall.h:37
EReturnType ReturnType()
Returns the return type of the method.
static const EReturnType kLong
Definition TMethodCall.h:43
static const EReturnType kString
Definition TMethodCall.h:45
static const EReturnType kOther
Definition TMethodCall.h:46
static const EReturnType kNone
Definition TMethodCall.h:49
void Execute(const char *, const char *, int *=nullptr) override
Execute method on this object with the given parameter string, e.g.
Definition TMethodCall.h:64
Bool_t IsValid() const
Return true if the method call has been properly initialized and is usable.
void InitWithPrototype(TClass *cl, const char *method, const char *proto, Bool_t objectIsConst=kFALSE, ROOT::EFunctionMatchMode mode=ROOT::kConversionMatch)
Initialize the method invocation environment.
static const EReturnType kDouble
Definition TMethodCall.h:44
Each ROOT class (see TClass) has a linked list of methods.
Definition TMethod.h:38
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
static TClass * Class()
Mother of all ROOT objects.
Definition TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:457
virtual void Streamer(TBuffer &)
Stream an object of class TObject.
Definition TObject.cxx:972
static TClass * Class()
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:543
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
virtual TClass * IsA() const
Definition TObject.h:246
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:293
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1045
The most important graphics class in the ROOT system.
Definition TPad.h:28
static TClass * Class()
static TClass * Class()
void * FindInHierarchy(const char *path, TClass **cl=nullptr, TDataMember **member=nullptr, Int_t *chld=nullptr) override
Search element with specified path.
Bool_t IsStreamerInfoItem(const char *itemname) override
Return true if it is streamer info item name.
static Bool_t IsDrawableClass(TClass *cl)
return true if given class can be drawn in JSROOT
Bool_t ProduceExe(const std::string &path, const std::string &options, Int_t reskind, std::string &res) override
Execute command for specified object.
TList * fSinfo
! last produced streamer info
TRootSnifferFull(const char *name="sniff", const char *objpath="Objects")
constructor
Bool_t CanDrawClass(TClass *cl) override
void ScanObjectProperties(TRootSnifferScanRec &rec, TObject *obj) override
Scans object properties.
virtual ~TRootSnifferFull()
destructor
void ScanObjectChilds(TRootSnifferScanRec &rec, TObject *obj) override
Scans object childs (if any)
std::map< const TMethod *, std::unique_ptr< TMethodCall > > fExeCache
! cache for exe.json invocation
Bool_t ProduceRootFile(const std::string &path, const std::string &options, std::string &res) override
Produce ROOT file for specified item.
ULong_t GetItemHash(const char *itemname) override
Get hash function for specified item.
Bool_t ProduceImage(Int_t kind, const std::string &path, const std::string &options, std::string &res) override
Method to produce image from specified object.
Bool_t CallProduceImage(const std::string &kind, const std::string &path, const std::string &options, std::string &res) override
Invokes TRootSniffer::ProduceIamge, converting kind into TImage::EImageFileTypes type.
Bool_t ProduceXml(const std::string &path, const std::string &options, std::string &res) override
Produce XML data for specified item.
void CreateMemFile()
Creates TMemFile instance, which used for objects streaming.
Bool_t ProduceBinary(const std::string &path, const std::string &options, std::string &res) override
Produce binary data for specified item.
TMemFile * fMemFile
! file used to manage streamer infos
ULong_t GetStreamerInfoHash() override
Returns hash value for streamer infos.
void ScanKeyProperties(TRootSnifferScanRec &rec, TKey *key, TObject *&obj, TClass *&obj_class) override
Scans TKey properties.
Structure used to scan hierarchies of ROOT objects.
Sniffer of ROOT objects, data provider for THttpServer.
virtual void ScanObjectChilds(TRootSnifferScanRec &rec, TObject *obj)
scans object childs (if any) here one scans collection, branches, trees and so on
TString DecodeUrlOptionValue(const char *value, Bool_t remove_quotes=kTRUE, Bool_t escape_special=kTRUE)
Method replaces all kind of special symbols, which could appear in URL options.
TString fCurrentAllowedMethods
! list of allowed methods, extracted when analyzed object restrictions
virtual void ScanKeyProperties(TRootSnifferScanRec &rec, TKey *key, TObject *&obj, TClass *&obj_class)
Scans TKey properties in special cases load objects from the file.
Bool_t fAllowPostObject
! when true allow to deserialize objects received via POST requests
virtual void ScanObjectProperties(TRootSnifferScanRec &rec, TObject *obj)
Scans object properties here such fields as _autoload or _icon properties depending on class or objec...
virtual ULong_t GetItemHash(const char *itemname)
Get hash function for specified item used to detect any changes in the specified object.
Bool_t fReadOnly
! indicate if sniffer allowed to change ROOT structures - like read objects from file
THttpCallArg * fCurrentArg
! current http arguments (if any)
virtual void * FindInHierarchy(const char *path, TClass **cl=nullptr, TDataMember **member=nullptr, Int_t *chld=nullptr)
Search element with specified path Returns pointer on element Optionally one could obtain element cla...
Int_t fCurrentRestrict
! current restriction for last-found object
void ScanCollection(TRootSnifferScanRec &rec, TCollection *lst, const char *foldername=nullptr, TCollection *keys_lst=nullptr)
Scan collection content.
Basic string class.
Definition TString.h:138
const char * Data() const
Definition TString.h:384
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:2384
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2362
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:660
A TTree represents a columnar dataset.
Definition TTree.h:89
static TClass * Class()
This class represents a WWW compatible URL.
Definition TUrl.h:33
small helper class to store/restore gPad context in TPad methods
Definition TVirtualPad.h:61
return c1
Definition legend1.C:41
TGraphErrors * gr
Definition legend1.C:25
TLine l
Definition textangle.C:4