Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TRootSniffer.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 "TRootSniffer.h"
13
14#include "TDirectoryFile.h"
15#include "TKey.h"
16#include "TList.h"
17#include "TBufferJSON.h"
18#include "TROOT.h"
19#include "TFolder.h"
20#include "TClass.h"
21#include "TRealData.h"
22#include "TDataMember.h"
23#include "TDataType.h"
24#include "TObjString.h"
25#include "TObjArray.h"
26#include "TUrl.h"
27#include "TVirtualMutex.h"
28#include "TRootSnifferStore.h"
29#include "THttpCallArg.h"
30
31#include <cstdlib>
32#include <memory>
33#include <vector>
34#include <cstring>
35#include <cctype>
36
37
38const char *item_prop_kind = "_kind";
39const char *item_prop_more = "_more";
40const char *item_prop_title = "_title";
41const char *item_prop_hidden = "_hidden";
42const char *item_prop_typename = "_typename";
43const char *item_prop_arraydim = "_arraydim";
44const char *item_prop_realname = "_realname"; // real object name
45const char *item_prop_user = "_username";
46const char *item_prop_autoload = "_autoload";
47const char *item_prop_rootversion = "_root_version";
48
49/** \class TRootSnifferScanRec
50\ingroup http
51
52Structure used to scan hierarchies of ROOT objects
53
54Represents single level of hierarchy
55*/
56
57////////////////////////////////////////////////////////////////////////////////
58/// constructor
59
64
65////////////////////////////////////////////////////////////////////////////////
66/// destructor
67
72
73////////////////////////////////////////////////////////////////////////////////
74/// record field for current element
75
76void TRootSnifferScanRec::SetField(const char *name, const char *value, Bool_t with_quotes)
77{
78 if (CanSetFields())
79 fStore->SetField(fLevel, name, value, with_quotes);
80 fNumFields++;
81}
82
83////////////////////////////////////////////////////////////////////////////////
84/// Indicates that new child for current element will be started
85
87{
88 if (CanSetFields())
89 fStore->BeforeNextChild(fLevel, fNumChilds, fNumFields);
90 fNumChilds++;
91}
92
93////////////////////////////////////////////////////////////////////////////////
94/// Constructs item name from object name
95/// if special symbols like '/', '#', ':', '&', '?' are used in object name
96/// they will be replaced with '_'.
97/// To avoid item name duplication, additional id number can be appended
98
99void TRootSnifferScanRec::MakeItemName(const char *objname, TString &itemname)
100{
101 std::string nnn = objname;
102
103 size_t pos;
104
105 // replace all special symbols which can make problem to navigate in hierarchy
106 while ((pos = nnn.find_first_of("- []<>#:&?/\'\"\\")) != std::string::npos)
107 nnn.replace(pos, 1, "_");
108
109 itemname = nnn.c_str();
110 Int_t cnt = 0;
111
112 while (fItemsNames.FindObject(itemname.Data())) {
113 itemname.Form("%s_%d", nnn.c_str(), cnt++);
114 }
115
116 fItemsNames.Add(new TObjString(itemname.Data()));
117}
118
119////////////////////////////////////////////////////////////////////////////////
120/// Produce full name, including all parents
121
123{
124 if (!prnt)
125 prnt = fParent;
126
127 if (prnt) {
128 prnt->BuildFullName(buf);
129
130 buf.Append("/");
131 buf.Append(fItemName);
132 }
133}
134
135////////////////////////////////////////////////////////////////////////////////
136/// Creates new node with specified name
137/// if special symbols like "[]&<>" are used, node name
138/// will be replaced by default name like "extra_item_N" and
139/// original node name will be recorded as "_original_name" field
140/// Optionally, object name can be recorded as "_realname" field
141
142void TRootSnifferScanRec::CreateNode(const char *_node_name)
143{
144 if (!CanSetFields())
145 return;
146
148
149 if (fParent)
150 fParent->BeforeNextChild();
151
152 if (fStore)
153 fStore->CreateNode(fLevel, _node_name);
154}
155
156////////////////////////////////////////////////////////////////////////////////
157/// Close started node
158
160{
161 if (fStore && fNodeStarted) {
162 fStore->CloseNode(fLevel, fNumChilds);
164 }
165}
166
167////////////////////////////////////////////////////////////////////////////////
168/// set root class name as node kind
169/// in addition, path to master item (streamer info) specified
170/// Such master item required to correctly unstream data on JavaScript
171
173{
174 if (cl && CanSetFields())
176}
177
178////////////////////////////////////////////////////////////////////////////////
179/// returns true if scanning is done
180/// Can happen when searched element is found
181
183{
184 if (!fStore)
185 return kFALSE;
186
187 if ((fMask & kSearch) && fStore->GetResPtr())
188 return kTRUE;
189
190 if ((fMask & kCheckChilds) && fStore->GetResPtr() && (fStore->GetResNumChilds() >= 0))
191 return kTRUE;
192
193 return kFALSE;
194}
195
196////////////////////////////////////////////////////////////////////////////////
197/// Checks if result will be accepted.
198/// Used to verify if sniffer should read object from the file
199
201{
202 if (Done())
203 return kFALSE;
204
205 // only when doing search, result will be propagated
206 if ((fMask & (kSearch | kCheckChilds)) == 0)
207 return kFALSE;
208
209 // only when full search path is scanned
210 if (fSearchPath)
211 return kFALSE;
212
213 if (!fStore)
214 return kFALSE;
215
216 return kTRUE;
217}
218
219////////////////////////////////////////////////////////////////////////////////
220/// set results of scanning
221/// when member should be specified, use SetFoundResult instead
222
224{
225 if (!member)
226 return SetFoundResult(obj, cl);
227
228 fStore->Error("SetResult",
229 "When member specified, pointer on object (not member) should be provided; use SetFoundResult");
230 return kFALSE;
231}
232
233////////////////////////////////////////////////////////////////////////////////
234/// set results of scanning
235/// when member specified, obj is pointer on object to which member belongs
236
238{
239 if (Done())
240 return kTRUE;
241
242 if (!IsReadyForResult())
243 return kFALSE;
244
245 fStore->SetResult(obj, cl, member, fNumChilds, fRestriction);
246
247 return Done();
248}
249
250////////////////////////////////////////////////////////////////////////////////
251/// returns current depth of scanned hierarchy
252
254{
255 Int_t cnt = 0;
256 const TRootSnifferScanRec *rec = this;
257 while (rec->fParent) {
258 rec = rec->fParent;
259 cnt++;
260 }
261
262 return cnt;
263}
264
265////////////////////////////////////////////////////////////////////////////////
266/// returns true if current item can be expanded - means one could explore
267/// objects members
268
270{
271 if (fMask & (kExpand | kSearch | kCheckChilds))
272 return kTRUE;
273
274 if (!fHasMore)
275 return kFALSE;
276
277 // if parent has expand mask, allow to expand item
278 if (fParent && (fParent->fMask & kExpand))
279 return kTRUE;
280
281 return kFALSE;
282}
283
284////////////////////////////////////////////////////////////////////////////////
285/// returns read-only flag for current item
286/// Depends from default value and current restrictions
287
289{
290 if (fRestriction == 0)
291 return dflt;
292
293 return fRestriction != 2;
294}
295
296////////////////////////////////////////////////////////////////////////////////
297/// Method verifies if new level of hierarchy
298/// should be started with provided object.
299/// If required, all necessary nodes and fields will be created
300/// Used when different collection kinds should be scanned
301
303{
304 if (super.Done())
305 return kFALSE;
306
307 if (obj && !obj_name)
308 obj_name = obj->GetName();
309
310 // exclude zero names
311 if (!obj_name || (*obj_name == 0))
312 return kFALSE;
313
314 const char *full_name = nullptr;
315
316 // remove slashes from file names
317 if (obj && obj->InheritsFrom(TDirectoryFile::Class())) {
318 const char *slash = strrchr(obj_name, '/');
319 if (slash) {
320 full_name = obj_name;
321 obj_name = slash + 1;
322 if (*obj_name == 0)
323 obj_name = "file";
324 }
325 }
326
327 super.MakeItemName(obj_name, fItemName);
328
329 if (sniffer && sniffer->HasRestriction(fItemName.Data())) {
330 // check restriction more precisely
331 TString fullname;
332 BuildFullName(fullname, &super);
333 fRestriction = sniffer->CheckRestriction(fullname.Data());
334 if (fRestriction < 0)
335 return kFALSE;
336 }
337
338 fParent = &super;
339 fLevel = super.fLevel;
340 fStore = super.fStore;
341 fSearchPath = super.fSearchPath;
342 fMask = super.fMask & kActions;
343 if (fRestriction == 0)
344 fRestriction = super.fRestriction; // get restriction from parent
345 Bool_t topelement = kFALSE;
346
347 if (fMask & kScan) {
348 // if scanning only fields, ignore all childs
349 if (super.ScanOnlyFields())
350 return kFALSE;
351 // only when doing scan, increment level, used for text formatting
352 fLevel++;
353 } else {
354 if (!fSearchPath)
355 return kFALSE;
356
357 if (strncmp(fSearchPath, fItemName.Data(), fItemName.Length()) != 0)
358 return kFALSE;
359
360 const char *separ = fSearchPath + fItemName.Length();
361
362 Bool_t isslash = kFALSE;
363 while (*separ == '/') {
364 separ++;
365 isslash = kTRUE;
366 }
367
368 if (*separ == 0) {
369 fSearchPath = nullptr;
370 if (fMask & kExpand) {
371 topelement = kTRUE;
373 fHasMore = (fMask & kOnlyFields) == 0;
374 }
375 } else {
376 if (!isslash)
377 return kFALSE;
378 fSearchPath = separ;
379 }
380 }
381
382 CreateNode(fItemName.Data());
383
384 if (obj_name && (fItemName != obj_name))
385 SetField(item_prop_realname, obj_name);
386
387 if (full_name)
388 SetField("_fullname", full_name);
389
390 if (topelement)
391 SetField(item_prop_rootversion, TString::Format("%d", gROOT->GetVersionCode()), kFALSE);
392
393 if (topelement && sniffer->GetAutoLoad())
395
396 return kTRUE;
397}
398
399
400/** \class TRootSniffer
401\ingroup http
402
403Sniffer of ROOT objects, data provider for THttpServer
404
405Provides methods to scan different structures like folders,
406directories, files and collections. Can locate objects (or its data member) per name.
407Can be extended to application-specific classes.
408
409Normally TRootSnifferFull class is used which able to access data from trees, canvases, histograms.
410*/
411
413
414////////////////////////////////////////////////////////////////////////////////
415/// constructor
416
417TRootSniffer::TRootSniffer(const char *name, const char *objpath)
418 : TNamed(name, "sniffer of root objects"), fObjectsPath(objpath)
419{
420 fRestrictions.SetOwner(kTRUE);
421}
422
423////////////////////////////////////////////////////////////////////////////////
424/// destructor
425
429
430////////////////////////////////////////////////////////////////////////////////
431/// set current http arguments, which then used in different process methods
432/// For instance, if user authorized with some user name,
433/// depending from restrictions some objects will be invisible
434/// or user get full access to the element
435/// Returns previous argument which was set before
436
438{
439 auto res = fCurrentArg;
440 fCurrentArg = arg;
443 return res;
444}
445
446////////////////////////////////////////////////////////////////////////////////
447/// Restrict access to the specified location
448///
449/// Hides or provides read-only access to different parts of the hierarchy
450/// Restriction done base on user-name specified with http requests
451/// Options can be specified in URL style (separated with &)
452/// Following parameters can be specified:
453///
454/// visible = [all|user(s)] - make item visible for all users or only specified user
455/// hidden = [all|user(s)] - make item hidden from all users or only specified user
456/// readonly = [all|user(s)] - make item read-only for all users or only specified user
457/// allow = [all|user(s)] - make full access for all users or only specified user
458/// allow_method = method(s) - allow method(s) execution even when readonly flag specified for the object
459///
460/// Like make command seen by all but can be executed only by admin
461///
462/// sniff->Restrict("/CmdReset","allow=admin");
463///
464/// Or fully hide command from guest account
465///
466/// sniff->Restrict("/CmdRebin","hidden=guest");
467
468void TRootSniffer::Restrict(const char *path, const char *options)
469{
470 const char *rslash = strrchr(path, '/');
471 if (rslash)
472 rslash++;
473 if (!rslash || (*rslash == 0))
474 rslash = path;
475
476 fRestrictions.Add(new TNamed(rslash, TString::Format("%s%s%s", path, "%%%", options).Data()));
477}
478
479////////////////////////////////////////////////////////////////////////////////
480/// When specified, _autoload attribute will be always add
481/// to top element of h.json/h.hml requests
482/// Used to instruct browser automatically load special code
483
484void TRootSniffer::SetAutoLoad(const char *scripts)
485{
486 fAutoLoad = scripts ? scripts : "";
487}
488
489////////////////////////////////////////////////////////////////////////////////
490/// return name of configured autoload scripts (or 0)
491
492const char *TRootSniffer::GetAutoLoad() const
493{
494 return fAutoLoad.Length() > 0 ? fAutoLoad.Data() : nullptr;
495}
496
497////////////////////////////////////////////////////////////////////////////////
498/// Made fast check if item with specified name is in restriction list
499/// If returns true, requires precise check with CheckRestriction() method
500
502{
503 if (!item_name || (*item_name == 0) || !fCurrentArg)
504 return kFALSE;
505
506 return fRestrictions.FindObject(item_name) != nullptr;
507}
508
509////////////////////////////////////////////////////////////////////////////////
510/// return 2 when option match to current user name
511/// return 1 when option==all
512/// return 0 when option does not match user name
513
515{
516 const char *username = fCurrentArg ? fCurrentArg->GetUserName() : nullptr;
517
518 if (!username || !option || (*option == 0))
519 return 0;
520
521 if (strcmp(option, "all") == 0)
522 return 1;
523
524 if (strcmp(username, option) == 0)
525 return 2;
526
527 if (strstr(option, username) == 0)
528 return -1;
529
530 TObjArray *arr = TString(option).Tokenize(",");
531
532 Bool_t find = arr->FindObject(username) != nullptr;
533
534 delete arr;
535
536 return find ? 2 : -1;
537}
538
539////////////////////////////////////////////////////////////////////////////////
540/// Checked if restriction is applied to the item full_item_name
541/// should have full path to the item. Returns:
542///
543/// * -1 - object invisible, cannot be accessed or listed
544/// * 0 - no explicit restrictions, use default
545/// * 1 - read-only access
546/// * 2 - full access
547
548Int_t TRootSniffer::CheckRestriction(const char *full_item_name)
549{
550 if (!full_item_name || (*full_item_name == 0))
551 return 0;
552
553 const char *item_name = strrchr(full_item_name, '/');
554 if (item_name)
555 item_name++;
556 if (!item_name || (*item_name == 0))
557 item_name = full_item_name;
558
559 TString pattern1 = TString("*/") + item_name + "%%%";
560 TString pattern2 = TString(full_item_name) + "%%%";
561
562 const char *options = nullptr;
563 TIter iter(&fRestrictions);
564
565 while (auto obj = iter()) {
566 const char *title = obj->GetTitle();
567
568 if (strstr(title, pattern1.Data()) == title) {
569 options = title + pattern1.Length();
570 break;
571 }
572 if (strstr(title, pattern2.Data()) == title) {
573 options = title + pattern2.Length();
574 break;
575 }
576 }
577
578 if (!options)
579 return 0;
580
581 TUrl url;
582 url.SetOptions(options);
583 url.ParseOptions();
584
585 Int_t can_see =
587
588 Int_t can_access =
590
591 if (can_access > 0)
592 return 2; // first of all, if access enabled, provide it
593 if (can_see < 0)
594 return -1; // if object to be hidden, do it
595
596 const char *methods = url.GetValueFromOptions("allow_method");
597 if (methods)
598 fCurrentAllowedMethods = methods;
599
600 if (can_access < 0)
601 return 1; // read-only access
602
603 return 0; // default behavior
604}
605
606////////////////////////////////////////////////////////////////////////////////
607/// scan object data members
608/// some members like enum or static members will be excluded
609
611{
612 if (!cl || !ptr || rec.Done())
613 return;
614
615 // ensure that real class data (including parents) exists
616 if (!(cl->Property() & kIsAbstract))
617 cl->BuildRealData();
618
619 // scan only real data
620 TIter iter(cl->GetListOfRealData());
621 while (auto obj = iter()) {
622 TRealData *rdata = dynamic_cast<TRealData *>(obj);
623 if (!rdata || strchr(rdata->GetName(), '.'))
624 continue;
625
626 TDataMember *member = rdata->GetDataMember();
627 // exclude enum or static variables
628 if (!member || (member->Property() & (kIsStatic | kIsEnum | kIsUnion)))
629 continue;
630 char *member_ptr = ptr + rdata->GetThisOffset();
631
632 if (member->IsaPointer())
633 member_ptr = *((char **)member_ptr);
634
636
637 if (chld.GoInside(rec, member, 0, this)) {
638
639 TClass *mcl = (member->IsBasic() || member->IsSTLContainer()) ? nullptr : gROOT->GetClass(member->GetTypeName());
640
641 Int_t coll_offset = mcl ? mcl->GetBaseClassOffset(TCollection::Class()) : -1;
642 if (coll_offset >= 0) {
643 chld.SetField(item_prop_more, "true", kFALSE);
644 chld.fHasMore = kTRUE;
645 }
646
647 if (chld.SetFoundResult(ptr, cl, member))
648 break;
649
650 const char *title = member->GetTitle();
651 if (title && *title)
652 chld.SetField(item_prop_title, title);
653
654 if (member->GetTypeName())
655 chld.SetField(item_prop_typename, member->GetTypeName());
656
657 if (member->GetArrayDim() > 0) {
658 // store array dimensions in form [N1,N2,N3,...]
659 TString dim("[");
660 for (Int_t n = 0; n < member->GetArrayDim(); n++) {
661 if (n > 0)
662 dim.Append(",");
663 dim.Append(TString::Format("%d", member->GetMaxIndex(n)));
664 }
665 dim.Append("]");
667 } else if (member->GetArrayIndex() != 0) {
668 TRealData *idata = cl->GetRealData(member->GetArrayIndex());
669 TDataMember *imember = idata ? idata->GetDataMember() : nullptr;
670 if (imember && (strcmp(imember->GetTrueTypeName(), "int") == 0)) {
671 Int_t arraylen = *((int *)(ptr + idata->GetThisOffset()));
672 chld.SetField(item_prop_arraydim, TString::Format("[%d]", arraylen), kFALSE);
673 }
674 }
675
676 chld.SetRootClass(mcl);
677
678 if (chld.CanExpandItem()) {
679 if (coll_offset >= 0) {
680 // chld.SetField("#members", "true", kFALSE);
681 ScanCollection(chld, (TCollection *)(member_ptr + coll_offset));
682 }
683 }
684
685 if (chld.SetFoundResult(ptr, cl, member))
686 break;
687 }
688 }
689}
690
691////////////////////////////////////////////////////////////////////////////////
692/// Scans object properties
693/// here such fields as _autoload or _icon properties depending on class or object name could be assigned
694/// By default properties, coded in the Class title are scanned. Example:
695///
696/// ClassDef(UserClassName, 1) // class comments *SNIFF* _field1=value _field2="string value"
697///
698/// Here *SNIFF* mark is important. After it all expressions like field=value are parsed
699/// One could use double quotes to code string values with spaces.
700/// Fields separated from each other with spaces
701
703{
704 TClass *cl = obj ? obj->IsA() : nullptr;
705
706 const char *pos = strstr(cl ? cl->GetTitle() : "", "*SNIFF*");
707 if (!pos)
708 return;
709
710 pos += 7;
711 while (*pos) {
712 if (*pos == ' ') {
713 pos++;
714 continue;
715 }
716 // first locate identifier
717 const char *pos0 = pos;
718 while (*pos && (*pos != '='))
719 pos++;
720 if (*pos == 0)
721 return;
722 TString name(pos0, pos - pos0);
723 pos++;
724 Bool_t quotes = (*pos == '\"');
725 if (quotes)
726 pos++;
727 pos0 = pos;
728 // then value with or without quotes
729 while (*pos && (*pos != (quotes ? '\"' : ' ')))
730 pos++;
731 TString value(pos0, pos - pos0);
732 rec.SetField(name, value);
733 if (quotes)
734 pos++;
735 pos++;
736 }
737}
738
739////////////////////////////////////////////////////////////////////////////////
740/// Scans TKey properties
741/// in special cases load objects from the file
742
744{
745 if (strcmp(key->GetClassName(), "TDirectoryFile") == 0) {
746 if (rec.fLevel == 0) {
747 auto dir = key->ReadObject<TDirectory>();
748 if (dir) {
749 obj = dir;
750 obj_class = dir->IsA();
751 }
752 } else {
753 rec.SetField(item_prop_more, "true", kFALSE);
754 rec.fHasMore = kTRUE;
755 }
756 }
757}
758
759////////////////////////////////////////////////////////////////////////////////
760/// scans object childs (if any)
761/// here one scans collection, branches, trees and so on
762
764{
765 if (obj->InheritsFrom(TFolder::Class())) {
766 ScanCollection(rec, ((TFolder *)obj)->GetListOfFolders());
767 } else if (obj->InheritsFrom(TDirectory::Class())) {
768 TDirectory *dir = (TDirectory *)obj;
769 ScanCollection(rec, dir->GetList(), nullptr, dir->GetListOfKeys());
770 } else if (rec.CanExpandItem()) {
771 ScanObjectMembers(rec, obj->IsA(), (char *)obj);
772 }
773}
774
775////////////////////////////////////////////////////////////////////////////////
776/// Scan collection content
777
778void TRootSniffer::ScanCollection(TRootSnifferScanRec &rec, TCollection *lst, const char *foldername,
779 TCollection *keys_lst)
780{
781 if ((!lst || (lst->GetSize() == 0)) && (!keys_lst || (keys_lst->GetSize() == 0)))
782 return;
783
784 TRootSnifferScanRec folderrec;
785 if (foldername) {
786 if (!folderrec.GoInside(rec, nullptr, foldername, this))
787 return;
788 }
789
790 TRootSnifferScanRec &master = foldername ? folderrec : rec;
791
792 if (lst) {
793 TIter iter(lst);
794 TObject *next = iter();
795 Bool_t isany = kFALSE;
796
797 while (next) {
798 if (IsItemField(next)) {
799 // special case - in the beginning one could have items for master folder
800 if (!isany && (next->GetName() != nullptr) && ((*(next->GetName()) == '_') || master.ScanOnlyFields()))
801 master.SetField(next->GetName(), next->GetTitle());
802 next = iter();
803 continue;
804 }
805
806 isany = kTRUE;
807 TObject *obj = next;
808
810 if (!chld.GoInside(master, obj, nullptr, this)) {
811 next = iter();
812 continue;
813 }
814
815 if (chld.SetResult(obj, obj->IsA()))
816 return;
817
818 Bool_t has_kind = kFALSE, has_title = kFALSE;
819
820 ScanObjectProperties(chld, obj);
821 // now properties, coded as TNamed objects, placed after object in the hierarchy
822 while ((next = iter()) != nullptr) {
823 if (!IsItemField(next))
824 break;
825 if ((next->GetName() != nullptr) && ((*(next->GetName()) == '_') || chld.ScanOnlyFields())) {
826 // only fields starting with _ are stored
827 chld.SetField(next->GetName(), next->GetTitle());
828 if (strcmp(next->GetName(), item_prop_kind) == 0)
829 has_kind = kTRUE;
830 if (strcmp(next->GetName(), item_prop_title) == 0)
831 has_title = kTRUE;
832 }
833 }
834
835 if (!has_kind)
836 chld.SetRootClass(obj->IsA());
837 if (!has_title && obj->GetTitle())
838 chld.SetField(item_prop_title, obj->GetTitle());
839
840 ScanObjectChilds(chld, obj);
841
842 if (chld.SetResult(obj, obj->IsA()))
843 return;
844 }
845 }
846
847 if (keys_lst) {
848 TIter iter(keys_lst);
849
850 while (auto kobj = iter()) {
851 TKey *key = dynamic_cast<TKey *>(kobj);
852 if (!key)
853 continue;
854 TObject *obj = lst ? lst->FindObject(key->GetName()) : nullptr;
855
856 // even object with the name exists, it should also match with class name
857 if (obj && (strcmp(obj->ClassName(), key->GetClassName()) != 0))
858 obj = nullptr;
859
860 // if object of that name and of that class already in the list, ignore appropriate key
861 if (obj && (master.fMask & TRootSnifferScanRec::kScan))
862 continue;
863
864 Bool_t iskey = kFALSE;
865 // if object not exists, provide key itself for the scan
866 if (!obj) {
867 obj = key;
868 iskey = kTRUE;
869 }
870
872 TString fullname = TString::Format("%s;%d", key->GetName(), key->GetCycle());
873
874 if (chld.GoInside(master, obj, fullname.Data(), this)) {
875
876 if (!chld.IsReadOnly(fReadOnly) && iskey && chld.IsReadyForResult()) {
877 TObject *keyobj = key->ReadObj();
878 if (keyobj)
879 if (chld.SetResult(keyobj, keyobj->IsA()))
880 return;
881 }
882
883 if (chld.SetResult(obj, obj->IsA()))
884 return;
885
886 TClass *obj_class = obj->IsA();
887
888 ScanObjectProperties(chld, obj);
889
890 if (obj->GetTitle())
891 chld.SetField(item_prop_title, obj->GetTitle());
892
893 // special handling of TKey class - in non-readonly mode
894 // sniffer allowed to fetch objects
895 if (!chld.IsReadOnly(fReadOnly) && iskey)
896 ScanKeyProperties(chld, key, obj, obj_class);
897
898 rec.SetRootClass(obj_class);
899
900 ScanObjectChilds(chld, obj);
901
902 // here we should know how many childs are accumulated
903 if (chld.SetResult(obj, obj_class))
904 return;
905 }
906 }
907 }
908}
909
910////////////////////////////////////////////////////////////////////////////////
911/// Create own TFolder structures independent from gROOT
912/// This allows to have many independent TRootSniffer instances
913/// At the same time such sniffer lost access to all global lists and folders
914
916{
917 if (fTopFolder) return;
918
920
921 // this only works with c++14, use ROOT wrapper
922 fTopFolder = std::make_unique<TFolder>("http","Dedicated instance");
923
924 // not sure if we have to add that private folder to global list of cleanups
925
926 // R__LOCKGUARD(gROOTMutex);
927 // gROOT->GetListOfCleanups()->Add(fTopFolder.get());
928
929}
930
931////////////////////////////////////////////////////////////////////////////////
932/// Returns top TFolder instance for the sniffer
933
935{
936 if (fTopFolder) return fTopFolder.get();
937
938 TFolder *topf = gROOT->GetRootFolder();
939
940 if (!topf) {
941 Error("RegisterObject", "Not found top ROOT folder!!!");
942 return nullptr;
943 }
944
945 TFolder *httpfold = dynamic_cast<TFolder *>(topf->FindObject("http"));
946 if (!httpfold) {
947 if (!force)
948 return nullptr;
949 httpfold = topf->AddFolder("http", "ROOT http server");
950 httpfold->SetBit(kCanDelete);
951 // register top folder in list of cleanups
953 gROOT->GetListOfCleanups()->Add(httpfold);
954 }
955
956 return httpfold;
957}
958
959////////////////////////////////////////////////////////////////////////////////
960/// scan complete ROOT objects hierarchy
961/// For the moment it includes objects in gROOT directory
962/// and list of canvases and files
963/// Also all registered objects are included.
964/// One could re-implement this method to provide alternative
965/// scan methods or to extend some collection kinds
966
968{
969 rec.SetField(item_prop_kind, "ROOT.Session");
970 if (fCurrentArg && fCurrentArg->GetUserName())
971 rec.SetField(item_prop_user, fCurrentArg->GetUserName());
972
973 // should be on the top while //root/http folder could have properties for itself
974 TFolder *topf = GetTopFolder();
975 if (topf) {
976 rec.SetField(item_prop_title, topf->GetTitle());
977 ScanCollection(rec, topf->GetListOfFolders());
978 }
979
980 if (HasStreamerInfo()) {
982 if (chld.GoInside(rec, nullptr, "StreamerInfo", this)) {
983 chld.SetField(item_prop_kind, "ROOT.TStreamerInfoList");
984 chld.SetField(item_prop_title, "List of streamer infos for binary I/O");
985 chld.SetField(item_prop_hidden, "true", kFALSE);
986 chld.SetField("_module", "hierarchy");
987 chld.SetField("_after_request", "markAsStreamerInfo");
988 }
989 }
990
991 if (IsScanGlobalDir()) {
992 ScanCollection(rec, gROOT->GetList());
993
994 ScanCollection(rec, gROOT->GetListOfCanvases(), "Canvases");
995
996 ScanCollection(rec, gROOT->GetListOfFiles(), "Files");
997 }
998}
999
1000////////////////////////////////////////////////////////////////////////////////
1001/// scan ROOT hierarchy with provided store object
1002
1003void TRootSniffer::ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store,
1004 Bool_t only_fields)
1005{
1007 rec.fSearchPath = path;
1008 if (rec.fSearchPath) {
1009 while (*rec.fSearchPath == '/')
1010 rec.fSearchPath++;
1011 if (*rec.fSearchPath == 0)
1012 rec.fSearchPath = nullptr;
1013 }
1014
1015 // if path non-empty, we should find item first and than start scanning
1016 rec.fMask = !rec.fSearchPath ? TRootSnifferScanRec::kScan : TRootSnifferScanRec::kExpand;
1017 if (only_fields)
1019
1020 rec.fStore = store;
1021
1022 rec.CreateNode(topname);
1023
1024 if (!rec.fSearchPath)
1026
1027 if (!rec.fSearchPath && GetAutoLoad())
1028 rec.SetField(item_prop_autoload, GetAutoLoad());
1029
1030 ScanRoot(rec);
1031
1032 rec.CloseNode();
1033}
1034
1035////////////////////////////////////////////////////////////////////////////////
1036/// Search element with specified path
1037/// Returns pointer on element
1038/// Optionally one could obtain element class, member description
1039/// and number of childs. When chld!=nullptr, not only element is searched,
1040/// but also number of childs are counted. When member!=0, any object
1041/// will be scanned for its data members (disregard of extra options)
1042
1043void *TRootSniffer::FindInHierarchy(const char *path, TClass **cl, TDataMember **member, Int_t *chld)
1044{
1045 TRootSnifferStore store;
1046
1048 rec.fSearchPath = path;
1050 if (*rec.fSearchPath == '/')
1051 rec.fSearchPath++;
1052 rec.fStore = &store;
1053
1054 ScanRoot(rec);
1055
1056 TDataMember *res_member = store.GetResMember();
1057 TClass *res_cl = store.GetResClass();
1058 void *res = store.GetResPtr();
1059
1060 if (res_member && res_cl && !member) {
1061 res_cl = (res_member->IsBasic() || res_member->IsSTLContainer()) ? nullptr : gROOT->GetClass(res_member->GetTypeName());
1062 TRealData *rdata = res_cl ? res_cl->GetRealData(res_member->GetName()) : nullptr;
1063 if (rdata) {
1064 res = (char *)res + rdata->GetThisOffset();
1065 if (res_member->IsaPointer())
1066 res = *((char **)res);
1067 } else {
1068 res = nullptr; // should never happen
1069 }
1070 }
1071
1072 if (cl)
1073 *cl = res_cl;
1074 if (member)
1075 *member = res_member;
1076 if (chld)
1077 *chld = store.GetResNumChilds();
1078
1079 // remember current restriction
1081
1082 return res;
1083}
1084
1085////////////////////////////////////////////////////////////////////////////////
1086/// Search element in hierarchy, derived from TObject
1087
1089{
1090 TClass *cl = nullptr;
1091
1092 void *obj = FindInHierarchy(path, &cl);
1093
1094 return cl && (cl->GetBaseClassOffset(TObject::Class()) == 0) ? (TObject *)obj : nullptr;
1095}
1096
1097////////////////////////////////////////////////////////////////////////////////
1098/// Get hash function for specified item
1099/// used to detect any changes in the specified object
1100
1102{
1103 TObject *obj = FindTObjectInHierarchy(itemname);
1104
1105 return !obj ? 0 : TString::Hash(obj, obj->IsA()->Size());
1106}
1107
1108////////////////////////////////////////////////////////////////////////////////
1109/// Method verifies if object can be drawn
1110
1112{
1113 TClass *obj_cl = nullptr;
1114 void *res = FindInHierarchy(path, &obj_cl);
1115 return (res != nullptr) && CanDrawClass(obj_cl);
1116}
1117
1118////////////////////////////////////////////////////////////////////////////////
1119/// Method returns true when object has childs or
1120/// one could try to expand item
1121
1123{
1124 TClass *obj_cl = nullptr;
1125 Int_t obj_chld(-1);
1126 void *res = FindInHierarchy(path, &obj_cl, nullptr, &obj_chld);
1127 return res && (obj_chld > 0);
1128}
1129
1130////////////////////////////////////////////////////////////////////////////////
1131/// Produce JSON data for specified item
1132/// For object conversion TBufferJSON is used
1133
1134Bool_t TRootSniffer::ProduceJson(const std::string &path, const std::string &options, std::string &res)
1135{
1136 if (path.empty())
1137 return kFALSE;
1138
1139 const char *path_ = path.c_str();
1140 if (*path_ == '/')
1141 path_++;
1142
1143 TUrl url;
1144 url.SetOptions(options.c_str());
1145 url.ParseOptions();
1146 Int_t compact = -1;
1147 if (url.GetValueFromOptions("compact"))
1148 compact = url.GetIntValueFromOptions("compact");
1149
1150 TClass *obj_cl = nullptr;
1151 TDataMember *member = nullptr;
1152 void *obj_ptr = FindInHierarchy(path_, &obj_cl, &member);
1153 if (!obj_ptr || (!obj_cl && !member))
1154 return kFALSE;
1155
1156 // TODO: implement direct storage into std::string
1157 TString buf = TBufferJSON::ConvertToJSON(obj_ptr, obj_cl, compact >= 0 ? compact : 0, member ? member->GetName() : nullptr);
1158 res = buf.Data();
1159
1160 return !res.empty();
1161}
1162
1163////////////////////////////////////////////////////////////////////////////////
1164/// Execute command marked as _kind=='Command'
1165
1166Bool_t TRootSniffer::ExecuteCmd(const std::string &path, const std::string &options, std::string &res)
1167{
1168 TFolder *parent = nullptr;
1169 TObject *obj = GetItem(path.c_str(), parent, kFALSE, kFALSE);
1170
1171 const char *kind = GetItemField(parent, obj, item_prop_kind);
1172 if ((kind == 0) || (strcmp(kind, "Command") != 0)) {
1173 if (gDebug > 0)
1174 Info("ExecuteCmd", "Entry %s is not a command", path.c_str());
1175 res = "false";
1176 return kTRUE;
1177 }
1178
1179 const char *cmethod = GetItemField(parent, obj, "method");
1180 if (!cmethod || (strlen(cmethod) == 0)) {
1181 if (gDebug > 0)
1182 Info("ExecuteCmd", "Entry %s do not defines method for execution", path.c_str());
1183 res = "false";
1184 return kTRUE;
1185 }
1186
1187 // if read-only specified for the command, it is not allowed for execution
1188 if (fRestrictions.GetLast() >= 0) {
1189 FindInHierarchy(path.c_str()); // one need to call method to check access rights
1190 if (fCurrentRestrict == 1) {
1191 if (gDebug > 0)
1192 Info("ExecuteCmd", "Entry %s not allowed for specified user", path.c_str());
1193 res = "false";
1194 return kTRUE;
1195 }
1196 }
1197
1198 TString method = cmethod;
1199
1200 const char *cnumargs = GetItemField(parent, obj, "_numargs");
1201 Int_t numargs = cnumargs ? TString(cnumargs).Atoi() : 0;
1202 if (numargs > 0) {
1203 TUrl url;
1204 url.SetOptions(options.c_str());
1205 url.ParseOptions();
1206
1207 for (Int_t n = 0; n < numargs; n++) {
1208 TString argname = TString::Format("arg%d", n + 1);
1209 const char *argvalue = url.GetValueFromOptions(argname);
1210 if (!argvalue) {
1211 if (gDebug > 0)
1212 Info("ExecuteCmd", "For command %s argument %s not specified in options %s", path.c_str(), argname.Data(),
1213 options.c_str());
1214 res = "false";
1215 return kTRUE;
1216 }
1217
1218 argname = TString("%") + argname + TString("%");
1219 auto p = method.Index(argname);
1220 if (p == kNPOS)
1221 continue;
1222
1223 method.Remove(p, argname.Length());
1224
1225 if ((p > 0) && (p < method.Length()) && (method.Length() > 1) && (method[p-1] == '"') && (method[p] == '"')) {
1226 // command definition has quotes around argument
1227 // one can insert value from URL removing quotes
1228 method.Insert(p, DecodeUrlOptionValue(argvalue, kTRUE));
1229 continue;
1230 }
1231
1232 // extract argument without removing quotes
1233 TString svalue = DecodeUrlOptionValue(argvalue, kFALSE);
1234
1235 if ((svalue.Length() > 1) && (svalue[0] == '"') && (svalue[svalue.Length() - 1] == '"')) {
1236 // if value itself has quotes, all special symbols already escaped and one can insert it as is
1237 method.Insert(p, svalue);
1238 continue;
1239 }
1240
1241 Bool_t is_numeric = kTRUE;
1242 // expect decimal, hex or float values here, E/e also belong to hex
1243 for(Size_t i = 0; is_numeric && (i < svalue.Length()); ++i)
1244 is_numeric = std::isxdigit(svalue[i]) || std::strchr(".+-", svalue[i]);
1245
1246 // always quote content which not numeric
1247 if (!is_numeric)
1248 svalue = "\"" + svalue + "\"";
1249 else if (svalue.IsNull())
1250 svalue = "0";
1251
1252 method.Insert(p, svalue);
1253 }
1254 }
1255
1256 if (gDebug > 0)
1257 Info("ExecuteCmd", "Executing command %s method:%s", path.c_str(), method.Data());
1258
1259 TObject *item_obj = nullptr;
1260 Ssiz_t separ = method.Index("/->");
1261
1262 if (method.Index("this->") == 0) {
1263 // if command name started with this-> means method of sniffer will be executed
1264 item_obj = this;
1265 separ = 3;
1266 } else if (separ != kNPOS) {
1267 item_obj = FindTObjectInHierarchy(TString(method.Data(), separ).Data());
1268 }
1269
1270 if (item_obj) {
1271 method = TString::Format("((%s*)%zu)->%s", item_obj->ClassName(), (size_t)item_obj, method.Data() + separ + 3);
1272 if (gDebug > 2)
1273 Info("ExecuteCmd", "Executing %s", method.Data());
1274 }
1275
1276 auto v = gROOT->ProcessLineSync(method.Data());
1277
1278 res = std::to_string(v);
1279
1280 return kTRUE;
1281}
1282
1283////////////////////////////////////////////////////////////////////////////////
1284/// Produce JSON/XML for specified item
1285///
1286/// Contrary to h.json request, only fields for specified item are stored
1287
1288Bool_t TRootSniffer::ProduceItem(const std::string &path, const std::string &options, std::string &res, Bool_t asjson)
1289{
1290 TString buf; // TODO: implement direct storage into std::string
1291 if (asjson) {
1292 TRootSnifferStoreJson store(buf, options.find("compact") != std::string::npos);
1293 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1294 } else {
1295 TRootSnifferStoreXml store(buf, options.find("compact") != std::string::npos);
1296 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1297 }
1298 res = buf.Data();
1299 return !res.empty();
1300}
1301
1302////////////////////////////////////////////////////////////////////////////////
1303/// Produce XML data for specified item
1304///
1305/// For object conversion TBufferXML is used
1306/// Method implemented only in TRootSnifferFull class
1307
1308Bool_t TRootSniffer::ProduceXml(const std::string &/* path */, const std::string & /* options */, std::string & /* res */)
1309{
1310 return kFALSE;
1311}
1312
1313////////////////////////////////////////////////////////////////////////////////
1314/// Method replaces all kind of special symbols, which could appear in URL options
1315
1317{
1318 if (!value || !*value)
1319 return "";
1320
1321 TString res = value;
1322
1323 // discard too large URL options, they should not appear at all
1324 if (res.Length() > 1024)
1325 return "";
1326
1327 res.ReplaceAll("%27", "\'");
1328 res.ReplaceAll("%22", "\"");
1329 res.ReplaceAll("%3E", ">");
1330 res.ReplaceAll("%3C", "<");
1331 res.ReplaceAll("%20", " ");
1332 res.ReplaceAll("%5B", "[");
1333 res.ReplaceAll("%5D", "]");
1334 res.ReplaceAll("%3D", "=");
1335
1336 Char_t quote = 0;
1337
1338 if ((res.Length() > 1) && ((res[0] == '\'') || (res[0] == '\"')) && (res[0] == res[res.Length() - 1]))
1339 quote = res[0];
1340
1341 // first remove quotes
1342 if (quote) {
1343 res.Remove(res.Length() - 1);
1344 res.Remove(0, 1);
1345 }
1346
1347 // we expect normal content here, no special symbols, no unescaped quotes
1348 TString clean;
1349 for (Ssiz_t i = 0; i < res.Length(); ++i) {
1350 char c = res[i];
1351 if (c == '"' || c == '\\') {
1352 // escape quotes and slahes
1353 clean.Append('\\');
1354 clean.Append(c);
1355 } else if (!std::iscntrl(c))
1356 // ignore all special symbols
1357 clean.Append(c);
1358 }
1359
1360 if (quote && !remove_quotes) {
1361 // return string with quotes - when desired
1362 res = "";
1363 res.Append(quote);
1364 res.Append(clean);
1365 res.Append(quote);
1366 return res;
1367 }
1368
1369 return clean;
1370}
1371
1372////////////////////////////////////////////////////////////////////////////////
1373/// Execute command for specified object
1374///
1375/// Options include method and extra list of parameters
1376/// sniffer should be not-readonly to allow execution of the commands
1377/// reskind defines kind of result 0 - debug, 1 - json, 2 - binary
1378///
1379/// Method implemented only in TRootSnifferFull class
1380
1381Bool_t TRootSniffer::ProduceExe(const std::string & /*path*/, const std::string & /*options*/, Int_t /*reskind*/,
1382 std::string & /*res*/)
1383{
1384 return kFALSE;
1385}
1386
1387////////////////////////////////////////////////////////////////////////////////
1388/// Process several requests, packing all results into binary or JSON buffer
1389///
1390/// Input parameters should be coded in the POST block and has
1391/// individual request relative to current path, separated with '\n' symbol like
1392/// item1/root.bin\n
1393/// item2/exe.bin?method=GetList\n
1394/// item3/exe.bin?method=GetTitle\n
1395/// Request requires 'number' URL option which contains number of requested items
1396///
1397/// In case of binary request output buffer looks like:
1398///
1399/// 4bytes length + payload,
1400/// 4bytes length + payload, ...
1401///
1402/// In case of JSON request output is array with results for each item
1403/// multi.json request do not support binary requests for the items
1404
1405Bool_t TRootSniffer::ProduceMulti(const std::string &path, const std::string &options, std::string &str, Bool_t asjson)
1406{
1407 if (!fCurrentArg || (fCurrentArg->GetPostDataLength() <= 0) || !fCurrentArg->GetPostData())
1408 return kFALSE;
1409
1410 const char *args = (const char *)fCurrentArg->GetPostData();
1411 const char *ends = args + fCurrentArg->GetPostDataLength();
1412
1413 TUrl url;
1414 url.SetOptions(options.c_str());
1415
1416 Int_t number = 0;
1417 if (url.GetValueFromOptions("number"))
1418 number = url.GetIntValueFromOptions("number");
1419
1420 // binary buffers required only for binary requests, json output can be produced as is
1421 std::vector<std::string> mem;
1422
1423 if (asjson)
1424 str = "[";
1425
1426 for (Int_t n = 0; n < number; n++) {
1427 const char *next = args;
1428 while ((next < ends) && (*next != '\n'))
1429 next++;
1430 if (next == ends) {
1431 Error("ProduceMulti", "Not enough arguments in POST block");
1432 break;
1433 }
1434
1435 std::string file1(args, next - args);
1436 args = next + 1;
1437
1438 std::string path1, opt1;
1439
1440 // extract options
1441 std::size_t pos = file1.find_first_of('?');
1442 if (pos != std::string::npos) {
1443 opt1 = file1.substr(pos + 1, file1.length() - pos);
1444 file1.resize(pos);
1445 }
1446
1447 // extract extra path
1448 pos = file1.find_last_of('/');
1449 if (pos != std::string::npos) {
1450 path1 = file1.substr(0, pos);
1451 file1.erase(0, pos + 1);
1452 }
1453
1454 if (!path.empty())
1455 path1 = path + "/" + path1;
1456
1457 std::string res1;
1458
1459 // produce next item request
1460 Produce(path1, file1, opt1, res1);
1461
1462 if (asjson) {
1463 if (n > 0)
1464 str.append(", ");
1465 if (res1.empty())
1466 str.append("null");
1467 else
1468 str.append(res1);
1469 } else {
1470 mem.emplace_back(std::move(res1));
1471 }
1472 }
1473
1474 if (asjson) {
1475 str.append("]");
1476 } else {
1477 Int_t length = 0;
1478 for (unsigned n = 0; n < mem.size(); n++)
1479 length += 4 + mem[n].length();
1480 str.resize(length);
1481 char *curr = (char *)str.data();
1482 for (unsigned n = 0; n < mem.size(); n++) {
1483 Long_t l = mem[n].length();
1484 *curr++ = (char)(l & 0xff);
1485 l = l >> 8;
1486 *curr++ = (char)(l & 0xff);
1487 l = l >> 8;
1488 *curr++ = (char)(l & 0xff);
1489 l = l >> 8;
1490 *curr++ = (char)(l & 0xff);
1491 if (!mem[n].empty())
1492 memcpy(curr, mem[n].data(), mem[n].length());
1493 curr += mem[n].length();
1494 }
1495 }
1496
1497 return kTRUE;
1498}
1499
1500////////////////////////////////////////////////////////////////////////////////
1501/// Produce binary data for specified item
1502///
1503/// If "zipped" option specified in query, buffer will be compressed
1504///
1505/// Implemented only in TRootSnifferFull class
1506
1507Bool_t TRootSniffer::ProduceBinary(const std::string & /*path*/, const std::string & /*query*/, std::string & /*res*/)
1508{
1509 return kFALSE;
1510}
1511
1512////////////////////////////////////////////////////////////////////////////////
1513/// Produce ROOT file for specified item
1514///
1515/// Implemented only in TRootSnifferFull class
1516
1517Bool_t TRootSniffer::ProduceRootFile(const std::string & /*path*/, const std::string & /*query*/, std::string & /*res*/)
1518{
1519 return kFALSE;
1520}
1521
1522////////////////////////////////////////////////////////////////////////////////
1523/// Method to produce image from specified object
1524///
1525/// Parameters:
1526///
1527/// kind - image kind TImage::kPng, TImage::kJpeg, TImage::kGif
1528/// path - path to object
1529/// options - extra options
1530///
1531/// By default, image 300x200 is produced
1532/// In options string one could provide following parameters:
1533///
1534/// w - image width
1535/// h - image height
1536/// opt - draw options
1537///
1538/// For instance:
1539///
1540/// http://localhost:8080/Files/hsimple.root/hpx/get.png?w=500&h=500&opt=lego1
1541///
1542/// Returns produced image in the res string
1543///
1544/// Method implemented only in TRootSnifferFull class
1545
1546Bool_t TRootSniffer::ProduceImage(Int_t /*kind*/, const std::string & /*path*/, const std::string & /*options*/, std::string & /*res*/)
1547{
1548 return kFALSE;
1549}
1550
1551////////////////////////////////////////////////////////////////////////////////
1552/// Invokes TRootSniffer::ProduceIamge, converting kind into TImage::EImageFileTypes type
1553
1554Bool_t TRootSniffer::CallProduceImage(const std::string &/*kind*/, const std::string &/*path*/, const std::string &/*options*/, std::string &/*res*/)
1555{
1556 return kFALSE;
1557}
1558
1559////////////////////////////////////////////////////////////////////////////////
1560/// Method produce different kind of data out of object
1561///
1562/// @param path specifies object or object member
1563/// @param file can be:
1564///
1565/// * "root.bin" - binary data
1566/// * "root.png" - png image
1567/// * "root.jpeg" - jpeg image
1568/// * "root.gif" - gif image
1569/// * "root.xml" - xml representation
1570/// * "root.json" - json representation
1571/// * "file.root" - ROOT file with stored object
1572/// * "exe.json" - method execution with json reply
1573/// * "exe.bin" - method execution with binary reply
1574/// * "exe.txt" - method execution with debug output
1575/// * "cmd.json" - execution of registered commands
1576///
1577/// @param res returns result - binary or text.
1578
1579Bool_t TRootSniffer::Produce(const std::string &path, const std::string &file, const std::string &options, std::string &res)
1580{
1581 if (file.empty())
1582 return kFALSE;
1583
1584 if (file == "root.bin")
1585 return ProduceBinary(path, options, res);
1586
1587 if (file == "root.png")
1588 return CallProduceImage("png", path, options, res);
1589
1590 if (file == "root.jpeg")
1591 return CallProduceImage("jpeg", path, options, res);
1592
1593 if (file == "root.gif")
1594 return CallProduceImage("gif", path, options, res);
1595
1596 if (file == "exe.bin")
1597 return ProduceExe(path, options, 2, res);
1598
1599 if (file == "root.xml")
1600 return ProduceXml(path, options, res);
1601
1602 if (file == "root.json")
1603 return ProduceJson(path, options, res);
1604
1605 if (file == "file.root")
1606 return ProduceRootFile(path, options, res);
1607
1608 // used for debugging
1609 if (file == "exe.txt")
1610 return ProduceExe(path, options, 0, res);
1611
1612 if (file == "exe.json")
1613 return ProduceExe(path, options, 1, res);
1614
1615 if (file == "cmd.json")
1616 return ExecuteCmd(path, options, res);
1617
1618 if (file == "item.json")
1619 return ProduceItem(path, options, res, kTRUE);
1620
1621 if (file == "item.xml")
1622 return ProduceItem(path, options, res, kFALSE);
1623
1624 if (file == "multi.bin")
1625 return ProduceMulti(path, options, res, kFALSE);
1626
1627 if (file == "multi.json")
1628 return ProduceMulti(path, options, res, kTRUE);
1629
1630 return kFALSE;
1631}
1632
1633////////////////////////////////////////////////////////////////////////////////
1634/// Return item from the subfolders structure
1635
1636TObject *TRootSniffer::GetItem(const char *fullname, TFolder *&parent, Bool_t force, Bool_t within_objects)
1637{
1638 TFolder *httpfold = GetTopFolder(force);
1639 if (!httpfold) return nullptr;
1640
1641 parent = httpfold;
1642 TObject *obj = httpfold;
1643
1644 if (!fullname)
1645 return httpfold;
1646
1647 // when full path started not with slash, "Objects" subfolder is appended
1648 TString path = fullname;
1649 if (within_objects && ((path.Length() == 0) || (path[0] != '/')))
1650 path = fObjectsPath + "/" + path;
1651
1652 TString tok;
1653 Ssiz_t from = 0;
1654
1655 while (path.Tokenize(tok, from, "/")) {
1656 if (tok.Length() == 0)
1657 continue;
1658
1659 TFolder *fold = dynamic_cast<TFolder *>(obj);
1660 if (!fold)
1661 return nullptr;
1662
1663 TIter iter(fold->GetListOfFolders());
1664 while ((obj = iter()) != nullptr) {
1665 if (IsItemField(obj))
1666 continue;
1667 if (tok.CompareTo(obj->GetName()) == 0)
1668 break;
1669 }
1670
1671 if (!obj) {
1672 if (!force)
1673 return nullptr;
1674 obj = fold->AddFolder(tok, "sub-folder");
1675 obj->SetBit(kCanDelete);
1676 }
1677
1678 parent = fold;
1679 }
1680
1681 return obj;
1682}
1683
1684////////////////////////////////////////////////////////////////////////////////
1685/// Creates subfolder where objects can be registered
1686
1687TFolder *TRootSniffer::GetSubFolder(const char *subfolder, Bool_t force)
1688{
1689 TFolder *parent = nullptr;
1690
1691 return dynamic_cast<TFolder *>(GetItem(subfolder, parent, force));
1692}
1693
1694////////////////////////////////////////////////////////////////////////////////
1695/// Register object in subfolder structure
1696///
1697/// @param subfolder can have many levels like:
1698///
1699/// TRootSniffer* sniff = new TRootSniffer("sniff");
1700/// sniff->RegisterObject("my/sub/subfolder", h1);
1701///
1702/// Such objects can be later found in "Objects" folder of sniffer like
1703///
1704/// auto h1 = sniff->FindTObjectInHierarchy("/Objects/my/sub/subfolder/h1");
1705///
1706/// If subfolder name starts with '/', object will be registered starting from top folder.
1707///
1708/// One could provide additional fields for registered objects
1709/// For instance, setting "_more" field to true let browser
1710/// explore objects members. For instance:
1711///
1712/// TEvent* ev = new TEvent("ev");
1713/// sniff->RegisterObject("Events", ev);
1714/// sniff->SetItemField("Events/ev", "_more", "true");
1715
1716Bool_t TRootSniffer::RegisterObject(const char *subfolder, TObject *obj)
1717{
1718 TFolder *f = GetSubFolder(subfolder, kTRUE);
1719 if (!f)
1720 return kFALSE;
1721
1722 // If object will be destroyed, it will be removed from the folders automatically
1723 obj->SetBit(kMustCleanup);
1724
1725 f->Add(obj);
1726
1727 return kTRUE;
1728}
1729
1730////////////////////////////////////////////////////////////////////////////////
1731/// Unregister (remove) object from folders structures
1732///
1733/// Folder itself will remain even when it will be empty
1734
1736{
1737 if (!obj)
1738 return kTRUE;
1739
1740 TFolder *topf = GetTopFolder();
1741
1742 if (!topf) {
1743 Error("UnregisterObject", "Not found top folder");
1744 return kFALSE;
1745 }
1746
1747 // TODO - probably we should remove all set properties as well
1748 topf->RecursiveRemove(obj);
1749
1750 return kTRUE;
1751}
1752
1753////////////////////////////////////////////////////////////////////////////////
1754/// Create item element
1755
1756Bool_t TRootSniffer::CreateItem(const char *fullname, const char *title)
1757{
1758 TFolder *f = GetSubFolder(fullname, kTRUE);
1759 if (!f)
1760 return kFALSE;
1761
1762 if (title)
1763 f->SetTitle(title);
1764
1765 return kTRUE;
1766}
1767
1768////////////////////////////////////////////////////////////////////////////////
1769/// Return true when object is TNamed with kItemField bit set
1770///
1771/// such objects used to keep field values for item
1772
1774{
1775 return (obj != nullptr) && (obj->IsA() == TNamed::Class()) && obj->TestBit(kItemField);
1776}
1777
1778////////////////////////////////////////////////////////////////////////////////
1779/// Set or get field for the child
1780///
1781/// each field coded as TNamed object, placed after chld in the parent hierarchy
1782
1783Bool_t TRootSniffer::AccessField(TFolder *parent, TObject *chld, const char *name, const char *value, TNamed **only_get)
1784{
1785 if (!parent)
1786 return kFALSE;
1787
1788 if (!chld) {
1789 Info("AccessField", "Should be special case for top folder, support later");
1790 return kFALSE;
1791 }
1792
1793 TIter iter(parent->GetListOfFolders());
1794
1795 Bool_t find = kFALSE, last_find = kFALSE;
1796 // this is special case of top folder - fields are on very top
1797 if (parent == chld)
1798 last_find = find = kTRUE;
1799
1800 TNamed *curr = nullptr;
1801 while (auto obj = iter()) {
1802 if (IsItemField(obj)) {
1803 if (last_find && obj->GetName() && !strcmp(name, obj->GetName()))
1804 curr = (TNamed *)obj;
1805 } else {
1806 last_find = (obj == chld);
1807 if (last_find)
1808 find = kTRUE;
1809 if (find && !last_find)
1810 break; // no need to continue
1811 }
1812 }
1813
1814 // object must be in childs list
1815 if (!find)
1816 return kFALSE;
1817
1818 if (only_get) {
1819 *only_get = curr;
1820 return curr != nullptr;
1821 }
1822
1823 if (curr) {
1824 if (value) {
1825 curr->SetTitle(value);
1826 } else {
1827 parent->Remove(curr);
1828 delete curr;
1829 }
1830 return kTRUE;
1831 }
1832
1833 curr = new TNamed(name, value);
1834 curr->SetBit(kItemField);
1835
1836 if (last_find) {
1837 // object is on last place, therefore just add property
1838 parent->Add(curr);
1839 return kTRUE;
1840 }
1841
1842 // only here we do dynamic cast to the TList to use AddAfter
1843 TList *lst = dynamic_cast<TList *>(parent->GetListOfFolders());
1844 if (!lst) {
1845 Error("AccessField", "Fail cast to TList");
1846 return kFALSE;
1847 }
1848
1849 if (parent == chld)
1850 lst->AddFirst(curr);
1851 else
1852 lst->AddAfter(chld, curr);
1853
1854 return kTRUE;
1855}
1856
1857////////////////////////////////////////////////////////////////////////////////
1858/// Set field for specified item
1859
1860Bool_t TRootSniffer::SetItemField(const char *fullname, const char *name, const char *value)
1861{
1862 if (!fullname || !name)
1863 return kFALSE;
1864
1865 TFolder *parent = nullptr;
1866 TObject *obj = GetItem(fullname, parent);
1867
1868 if (!parent || !obj)
1869 return kFALSE;
1870
1871 if (strcmp(name, item_prop_title) == 0) {
1872 TNamed *n = dynamic_cast<TNamed *>(obj);
1873 if (n) {
1874 n->SetTitle(value);
1875 return kTRUE;
1876 }
1877 }
1878
1879 return AccessField(parent, obj, name, value);
1880}
1881
1882////////////////////////////////////////////////////////////////////////////////
1883/// Return field for specified item
1884
1885const char *TRootSniffer::GetItemField(TFolder *parent, TObject *obj, const char *name)
1886{
1887 if (!parent || !obj || !name)
1888 return nullptr;
1889
1890 TNamed *field = nullptr;
1891
1892 if (!AccessField(parent, obj, name, nullptr, &field))
1893 return nullptr;
1894
1895 return field ? field->GetTitle() : nullptr;
1896}
1897
1898////////////////////////////////////////////////////////////////////////////////
1899/// Return field for specified item
1900
1901const char *TRootSniffer::GetItemField(const char *fullname, const char *name)
1902{
1903 if (!fullname)
1904 return nullptr;
1905
1906 TFolder *parent = nullptr;
1907 TObject *obj = GetItem(fullname, parent);
1908
1909 return GetItemField(parent, obj, name);
1910}
1911
1912////////////////////////////////////////////////////////////////////////////////
1913/// Register command which can be executed from web interface
1914///
1915/// As method one typically specifies string, which is executed with
1916/// gROOT->ProcessLine() method. For instance:
1917///
1918/// serv->RegisterCommand("Invoke","InvokeFunction()");
1919///
1920/// Or one could specify any method of the object which is already registered
1921/// to the server. For instance:
1922///
1923/// serv->Register("/", hpx);
1924/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
1925///
1926/// Here symbols '/->' separates item name from method to be executed
1927///
1928/// One could specify additional arguments in the command with
1929/// syntax like %arg1%, %arg2% and so on. For example:
1930///
1931/// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
1932/// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
1933///
1934/// Such parameter(s) will be requested when command clicked in the browser.
1935///
1936/// Once command is registered, one could specify icon which will appear in the browser:
1937///
1938/// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
1939///
1940/// One also can set extra property '_fastcmd', that command appear as
1941/// tool button on the top of the browser tree:
1942///
1943/// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
1944///
1945/// Or it is equivalent to specifying extra argument when register command:
1946///
1947/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
1948
1949Bool_t TRootSniffer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
1950{
1951 CreateItem(cmdname, TString::Format("command %s", method).Data());
1952 SetItemField(cmdname, "_kind", "Command");
1953 if (icon) {
1954 if (strncmp(icon, "button;", 7) == 0) {
1955 SetItemField(cmdname, "_fastcmd", "true");
1956 icon += 7;
1957 }
1958 if (*icon)
1959 SetItemField(cmdname, "_icon", icon);
1960 }
1961 SetItemField(cmdname, "method", method);
1962 Int_t numargs = 0;
1963 do {
1964 TString nextname = TString::Format("%sarg%d%s", "%", numargs + 1, "%");
1965 if (strstr(method, nextname.Data()) == nullptr)
1966 break;
1967 numargs++;
1968 } while (numargs < 100);
1969 if (numargs > 0)
1970 SetItemField(cmdname, "_numargs", TString::Format("%d", numargs));
1971
1972 return kTRUE;
1973}
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define ROOT_VERSION_CODE
Definition RVersion.hxx:24
bool Bool_t
Definition RtypesCore.h:63
int Int_t
Definition RtypesCore.h:45
float Size_t
Definition RtypesCore.h:96
int Ssiz_t
Definition RtypesCore.h:67
char Char_t
Definition RtypesCore.h:37
unsigned long ULong_t
Definition RtypesCore.h:55
long Long_t
Definition RtypesCore.h:54
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:124
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
#define ClassImp(name)
Definition Rtypes.h:377
@ kIsEnum
Definition TDictionary.h:68
@ kIsAbstract
Definition TDictionary.h:71
@ kIsStatic
Definition TDictionary.h:80
@ kIsUnion
Definition TDictionary.h:67
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
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 length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
Int_t i
Int_t gDebug
Definition TROOT.cxx:622
#define gROOT
Definition TROOT.h:414
externTVirtualMutex * gROOTMutex
Definition TROOT.h:63
const char * item_prop_typename
const char * item_prop_realname
const char * item_prop_user
const char * item_prop_autoload
const char * item_prop_more
const char * item_prop_kind
const char * item_prop_arraydim
const char * item_prop_title
const char * item_prop_rootversion
const char * item_prop_hidden
#define R__LOCKGUARD(mutex)
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...
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2032
TList * GetListOfRealData() const
Definition TClass.h:453
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5731
Int_t GetBaseClassOffset(const TClass *toBase, void *address=nullptr, bool isDerivedObject=true)
Definition TClass.cxx:2792
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6116
TClass * IsA() const override
Definition TClass.h:618
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition TClass.cxx:3530
Collection abstract base class.
Definition TCollection.h:65
static TClass * Class()
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
const char * GetTrueTypeName() const
Get the desugared type name of this data member, including const and volatile qualifiers.
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Int_t GetArrayDim() const
Return number of array dimensions.
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
Int_t IsSTLContainer()
The return type is defined in TDictionary (kVector, kList, etc.)
Bool_t IsaPointer() const
Return true if data member is a pointer.
const char * GetTypeName() const
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
static TClass * Class()
Describe directory structure in memory.
Definition TDirectory.h:45
static TClass * Class()
virtual TList * GetList() const
Definition TDirectory.h:222
virtual TList * GetListOfKeys() const
Definition TDirectory.h:223
<div class="legacybox"><h2>Legacy Code</h2> TFolder is a legacy interface: there will be no bug fixes...
Definition TFolder.h:30
void RecursiveRemove(TObject *obj) override
Recursively remove object from a folder.
Definition TFolder.cxx:449
TCollection * GetListOfFolders() const
Definition TFolder.h:55
TFolder * AddFolder(const char *name, const char *title, TCollection *collection=nullptr)
Create a new folder and add it to the list of folders of this folder, return a pointer to the created...
Definition TFolder.cxx:182
virtual void Add(TObject *obj)
Add object to this folder. obj must be a TObject or a TFolder.
Definition TFolder.cxx:166
TObject * FindObject(const char *name) const override
Search object identified by name in the tree of folders inside this folder.
Definition TFolder.cxx:306
static TClass * Class()
virtual void Remove(TObject *obj)
Remove object from this folder. obj must be a TObject or a TFolder.
Definition TFolder.cxx:457
Contains arguments for single HTTP call.
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
T * ReadObject()
To read an object (non deriving from TObject) from the file.
Definition TKey.h:103
virtual const char * GetClassName() const
Definition TKey.h:75
Short_t GetCycle() const
Return cycle number associated to this key.
Definition TKey.cxx:594
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition TKey.cxx:775
A doubly linked list.
Definition TList.h:38
void AddAfter(const TObject *after, TObject *obj) override
Insert object after object after in the list.
Definition TList.cxx:248
void AddFirst(TObject *obj) override
Add object at the beginning of the list.
Definition TList.cxx:98
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:164
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
TNamed()
Definition TNamed.h:36
static TClass * Class()
An array of TObjects.
Definition TObjArray.h:31
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:439
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:196
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:207
static TClass * Class()
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:780
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 const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:483
virtual TClass * IsA() const
Definition TObject.h:240
TObject()
TObject constructor.
Definition TObject.h:251
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:62
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:64
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
const char * GetName() const override
Returns name of object.
Definition TRealData.h:52
TDataMember * GetDataMember() const
Definition TRealData.h:53
Long_t GetThisOffset() const
Definition TRealData.h:55
Structure used to scan hierarchies of ROOT objects.
TString fItemName
! name of current item
Int_t fLevel
! current level of hierarchy
Int_t fRestriction
! restriction 0 - default, 1 - read-only, 2 - full access
Bool_t CanExpandItem()
Returns true when item can be expanded.
TRootSnifferStore * fStore
! object to store results
virtual ~TRootSnifferScanRec()
destructor
void SetField(const char *name, const char *value, Bool_t with_quotes=kTRUE)
Set item field only when creating is specified.
void CloseNode()
Close started node.
Bool_t CanSetFields() const
return true when fields could be set to the hierarchy item
friend class TRootSniffer
UInt_t fMask
! defines operation kind
void MakeItemName(const char *objname, TString &itemname)
Construct item name, using object name as basis.
@ kSearch
search for specified item (only objects and collections)
@ kOnlyFields
if set, only fields for specified item will be set (but all fields)
@ kExpand
expand of specified item - allowed to scan object members
@ kCheckChilds
check if there childs, very similar to search
@ kScan
normal scan of hierarchy
@ kActions
mask for actions, only actions copied to child rec
Bool_t IsReadyForResult() const
Checks if result will be accepted.
Bool_t SetResult(void *obj, TClass *cl, TDataMember *member=nullptr)
Obsolete, use SetFoundResult instead.
Bool_t fHasMore
! indicates that potentially there are more items can be found
Bool_t IsReadOnly(Bool_t dflt=kTRUE)
Returns read-only flag for current item.
Bool_t GoInside(TRootSnifferScanRec &super, TObject *obj, const char *obj_name=nullptr, TRootSniffer *sniffer=nullptr)
Method verifies if new level of hierarchy should be started with provided object.
void BeforeNextChild()
Indicates that new child for current element will be started.
TRootSnifferScanRec * fParent
! pointer on parent record
void SetRootClass(TClass *cl)
Mark item with ROOT class and correspondent streamer info.
void CreateNode(const char *_node_name)
Starts new node, must be closed at the end.
Int_t fNumChilds
! number of childs
Int_t fNumFields
! number of fields
Bool_t fNodeStarted
! indicate if node was started
Bool_t SetFoundResult(void *obj, TClass *cl, TDataMember *member=nullptr)
Set found element with class and datamember (optional)
const char * fSearchPath
! current path searched
Int_t Depth() const
Returns depth of hierarchy.
TList fItemsNames
! list of created items names, need to avoid duplication
Bool_t Done() const
Method indicates that scanning can be interrupted while result is set.
Bool_t ScanOnlyFields() const
return true when only fields are scanned by the sniffer
void BuildFullName(TString &buf, TRootSnifferScanRec *prnt=nullptr)
Produces full name for the current item.
TRootSnifferScanRec()
constructor
Storage of hierarchy scan in TRootSniffer in JSON format.
Storage of hierarchy scan in TRootSniffer in XML format.
Abstract interface for storage of hierarchy scan in TRootSniffer.
Int_t GetResNumChilds() const
TDataMember * GetResMember() const
void * GetResPtr() const
TClass * GetResClass() const
Int_t GetResRestrict() const
Sniffer of ROOT objects, data provider for THttpServer.
void ScanObjectMembers(TRootSnifferScanRec &rec, TClass *cl, char *ptr)
scan object data members some members like enum or static members will be excluded
const char * GetAutoLoad() const
return name of configured autoload scripts (or 0)
TString fObjectsPath
! default path for registered objects
void ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store, Bool_t only_fields=kFALSE)
Method scans normal objects, registered in ROOT.
TRootSniffer(const char *name="sniff", const char *objpath="Objects")
constructor
TList fRestrictions
! list of restrictions for different locations
Bool_t RegisterObject(const char *subfolder, TObject *obj)
Register object in subfolder structure.
virtual void ScanObjectChilds(TRootSnifferScanRec &rec, TObject *obj)
scans object childs (if any) here one scans collection, branches, trees and so on
TString fCurrentAllowedMethods
! list of allowed methods, extracted when analyzed object restrictions
virtual Bool_t HasStreamerInfo() const
Bool_t UnregisterObject(TObject *obj)
Unregister (remove) object from folders structures.
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 CreateItem(const char *fullname, const char *title)
Create item element.
virtual Bool_t ExecuteCmd(const std::string &path, const std::string &options, std::string &res)
Execute command marked as _kind=='Command'.
Bool_t HasRestriction(const char *item_name)
Made fast check if item with specified name is in restriction list If returns true,...
virtual void ScanObjectProperties(TRootSnifferScanRec &rec, TObject *obj)
Scans object properties here such fields as _autoload or _icon properties depending on class or objec...
virtual void ScanRoot(TRootSnifferScanRec &rec)
scan complete ROOT objects hierarchy For the moment it includes objects in gROOT directory and list o...
Bool_t Produce(const std::string &path, const std::string &file, const std::string &options, std::string &res)
Method produce different kind of data out of object.
virtual Bool_t ProduceJson(const std::string &path, const std::string &options, std::string &res)
Produce JSON data for specified item For object conversion TBufferJSON is used.
void CreateOwnTopFolder()
Create own TFolder structures independent from gROOT This allows to have many independent TRootSniffe...
virtual Bool_t ProduceExe(const std::string &path, const std::string &options, Int_t reskind, std::string &res)
Execute command for specified object.
virtual Bool_t ProduceXml(const std::string &path, const std::string &options, std::string &res)
Produce XML data for specified item.
TString DecodeUrlOptionValue(const char *value, Bool_t remove_quotes=kTRUE)
Method replaces all kind of special symbols, which could appear in URL options.
THttpCallArg * SetCurrentCallArg(THttpCallArg *arg)
set current http arguments, which then used in different process methods For instance,...
void Restrict(const char *path, const char *options)
Restrict access to the specified location.
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
void SetScanGlobalDir(Bool_t on=kTRUE)
When enabled (default), sniffer scans gROOT for files, canvases, histograms.
TObject * GetItem(const char *fullname, TFolder *&parent, Bool_t force=kFALSE, Bool_t within_objects=kTRUE)
Return item from the subfolders structure.
THttpCallArg * fCurrentArg
! current http arguments (if any)
virtual Bool_t ProduceImage(Int_t kind, const std::string &path, const std::string &options, std::string &res)
Method to produce image from specified object.
TObject * FindTObjectInHierarchy(const char *path)
Search element in hierarchy, derived from TObject.
void SetAutoLoad(const char *scripts="")
When specified, _autoload attribute will be always add to top element of h.json/h....
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...
virtual Bool_t ProduceItem(const std::string &path, const std::string &options, std::string &res, Bool_t asjson=kTRUE)
Produce JSON/XML for specified item.
Int_t CheckRestriction(const char *item_name)
Checked if restriction is applied to the item full_item_name should have full path to the item.
virtual Bool_t CallProduceImage(const std::string &kind, const std::string &path, const std::string &options, std::string &res)
Invokes TRootSniffer::ProduceIamge, converting kind into TImage::EImageFileTypes type.
Bool_t IsItemField(TObject *obj) const
Return true when object is TNamed with kItemField bit set.
virtual ~TRootSniffer()
destructor
virtual Bool_t CanDrawClass(TClass *)
Int_t fCurrentRestrict
! current restriction for last-found object
TFolder * GetTopFolder(Bool_t force=kFALSE)
Returns top TFolder instance for the sniffer.
const char * GetItemField(TFolder *parent, TObject *item, const char *name)
Return field for specified item.
std::unique_ptr< TFolder > fTopFolder
! own top TFolder object, used for registering objects
Bool_t CanExploreItem(const char *path)
Method returns true when object has childs or one could try to expand item.
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
Set field for specified item.
Int_t WithCurrentUserName(const char *option)
return 2 when option match to current user name return 1 when option==all return 0 when option does n...
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon)
Register command which can be executed from web interface.
TString fAutoLoad
! scripts names, which are add as _autoload parameter to h.json request
Bool_t IsScanGlobalDir() const
Returns true when sniffer allowed to scan global directories.
virtual Bool_t ProduceBinary(const std::string &path, const std::string &options, std::string &res)
Produce binary data for specified item.
TFolder * GetSubFolder(const char *foldername, Bool_t force=kFALSE)
Creates subfolder where objects can be registered.
virtual Bool_t ProduceRootFile(const std::string &path, const std::string &options, std::string &res)
Produce ROOT file for specified item.
void ScanCollection(TRootSnifferScanRec &rec, TCollection *lst, const char *foldername=nullptr, TCollection *keys_lst=nullptr)
Scan collection content.
Bool_t AccessField(TFolder *parent, TObject *item, const char *name, const char *value, TNamed **only_get=nullptr)
Set or get field for the child.
virtual Bool_t ProduceMulti(const std::string &path, const std::string &options, std::string &res, Bool_t asjson=kTRUE)
Process several requests, packing all results into binary or JSON buffer.
Bool_t CanDrawItem(const char *path)
Method verifies if object can be drawn.
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:417
int CompareTo(const char *cs, ECaseCompare cmp=kExact) const
Compare a string to char *cs2.
Definition TString.cxx:457
TString & Insert(Ssiz_t pos, const char *s)
Definition TString.h:661
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:1988
const char * Data() const
Definition TString.h:376
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:704
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2264
Bool_t IsNull() const
Definition TString.h:414
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition TString.cxx:677
TString & Remove(Ssiz_t pos)
Definition TString.h:685
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
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651
This class represents a WWW compatible URL.
Definition TUrl.h:33
const char * GetValueFromOptions(const char *key) const
Return a value for a given key from the URL options.
Definition TUrl.cxx:660
Int_t GetIntValueFromOptions(const char *key) const
Return a value for a given key from the URL options as an Int_t, a missing key returns -1.
Definition TUrl.cxx:672
void SetOptions(const char *opt)
Definition TUrl.h:87
void ParseOptions() const
Parse URL options into a key/value map.
Definition TUrl.cxx:626
const Int_t n
Definition legend1.C:16
TCanvas * slash()
Definition slash.C:1
TLine l
Definition textangle.C:4