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
36const char *item_prop_kind = "_kind";
37const char *item_prop_more = "_more";
38const char *item_prop_title = "_title";
39const char *item_prop_hidden = "_hidden";
40const char *item_prop_typename = "_typename";
41const char *item_prop_arraydim = "_arraydim";
42const char *item_prop_realname = "_realname"; // real object name
43const char *item_prop_user = "_username";
44const char *item_prop_autoload = "_autoload";
45const char *item_prop_rootversion = "_root_version";
46
47/** \class TRootSnifferScanRec
48\ingroup http
49
50Structure used to scan hierarchies of ROOT objects
51
52Represents single level of hierarchy
53*/
54
55////////////////////////////////////////////////////////////////////////////////
56/// constructor
57
59{
61}
62
63////////////////////////////////////////////////////////////////////////////////
64/// destructor
65
67{
68 CloseNode();
69}
70
71////////////////////////////////////////////////////////////////////////////////
72/// record field for current element
73
74void TRootSnifferScanRec::SetField(const char *name, const char *value, Bool_t with_quotes)
75{
76 if (CanSetFields())
77 fStore->SetField(fLevel, name, value, with_quotes);
78 fNumFields++;
79}
80
81////////////////////////////////////////////////////////////////////////////////
82/// Indicates that new child for current element will be started
83
85{
86 if (CanSetFields())
88 fNumChilds++;
89}
90
91////////////////////////////////////////////////////////////////////////////////
92/// Constructs item name from object name
93/// if special symbols like '/', '#', ':', '&', '?' are used in object name
94/// they will be replaced with '_'.
95/// To avoid item name duplication, additional id number can be appended
96
97void TRootSnifferScanRec::MakeItemName(const char *objname, TString &itemname)
98{
99 std::string nnn = objname;
100
101 size_t pos;
102
103 // replace all special symbols which can make problem to navigate in hierarchy
104 while ((pos = nnn.find_first_of("- []<>#:&?/\'\"\\")) != std::string::npos)
105 nnn.replace(pos, 1, "_");
106
107 itemname = nnn.c_str();
108 Int_t cnt = 0;
109
110 while (fItemsNames.FindObject(itemname.Data())) {
111 itemname.Form("%s_%d", nnn.c_str(), cnt++);
112 }
113
114 fItemsNames.Add(new TObjString(itemname.Data()));
115}
116
117////////////////////////////////////////////////////////////////////////////////
118/// Produce full name, including all parents
119
121{
122 if (!prnt)
123 prnt = fParent;
124
125 if (prnt) {
126 prnt->BuildFullName(buf);
127
128 buf.Append("/");
129 buf.Append(fItemName);
130 }
131}
132
133////////////////////////////////////////////////////////////////////////////////
134/// Creates new node with specified name
135/// if special symbols like "[]&<>" are used, node name
136/// will be replaced by default name like "extra_item_N" and
137/// original node name will be recorded as "_original_name" field
138/// Optionally, object name can be recorded as "_realname" field
139
140void TRootSnifferScanRec::CreateNode(const char *_node_name)
141{
142 if (!CanSetFields())
143 return;
144
146
147 if (fParent)
149
150 if (fStore)
151 fStore->CreateNode(fLevel, _node_name);
152}
153
154////////////////////////////////////////////////////////////////////////////////
155/// Close started node
156
158{
159 if (fStore && fNodeStarted) {
162 }
163}
164
165////////////////////////////////////////////////////////////////////////////////
166/// set root class name as node kind
167/// in addition, path to master item (streamer info) specified
168/// Such master item required to correctly unstream data on JavaScript
169
171{
172 if (cl && CanSetFields())
174}
175
176////////////////////////////////////////////////////////////////////////////////
177/// returns true if scanning is done
178/// Can happen when searched element is found
179
181{
182 if (!fStore)
183 return kFALSE;
184
185 if ((fMask & kSearch) && fStore->GetResPtr())
186 return kTRUE;
187
188 if ((fMask & kCheckChilds) && fStore->GetResPtr() && (fStore->GetResNumChilds() >= 0))
189 return kTRUE;
190
191 return kFALSE;
192}
193
194////////////////////////////////////////////////////////////////////////////////
195/// Checks if result will be accepted.
196/// Used to verify if sniffer should read object from the file
197
199{
200 if (Done())
201 return kFALSE;
202
203 // only when doing search, result will be propagated
204 if ((fMask & (kSearch | kCheckChilds)) == 0)
205 return kFALSE;
206
207 // only when full search path is scanned
208 if (fSearchPath)
209 return kFALSE;
210
211 if (!fStore)
212 return kFALSE;
213
214 return kTRUE;
215}
216
217////////////////////////////////////////////////////////////////////////////////
218/// set results of scanning
219/// when member should be specified, use SetFoundResult instead
220
222{
223 if (!member)
224 return SetFoundResult(obj, cl);
225
226 fStore->Error("SetResult",
227 "When member specified, pointer on object (not member) should be provided; use SetFoundResult");
228 return kFALSE;
229}
230
231////////////////////////////////////////////////////////////////////////////////
232/// set results of scanning
233/// when member specified, obj is pointer on object to which member belongs
234
236{
237 if (Done())
238 return kTRUE;
239
240 if (!IsReadyForResult())
241 return kFALSE;
242
243 fStore->SetResult(obj, cl, member, fNumChilds, fRestriction);
244
245 return Done();
246}
247
248////////////////////////////////////////////////////////////////////////////////
249/// returns current depth of scanned hierarchy
250
252{
253 Int_t cnt = 0;
254 const TRootSnifferScanRec *rec = this;
255 while (rec->fParent) {
256 rec = rec->fParent;
257 cnt++;
258 }
259
260 return cnt;
261}
262
263////////////////////////////////////////////////////////////////////////////////
264/// returns true if current item can be expanded - means one could explore
265/// objects members
266
268{
269 if (fMask & (kExpand | kSearch | kCheckChilds))
270 return kTRUE;
271
272 if (!fHasMore)
273 return kFALSE;
274
275 // if parent has expand mask, allow to expand item
276 if (fParent && (fParent->fMask & kExpand))
277 return kTRUE;
278
279 return kFALSE;
280}
281
282////////////////////////////////////////////////////////////////////////////////
283/// returns read-only flag for current item
284/// Depends from default value and current restrictions
285
287{
288 if (fRestriction == 0)
289 return dflt;
290
291 return fRestriction != 2;
292}
293
294////////////////////////////////////////////////////////////////////////////////
295/// Method verifies if new level of hierarchy
296/// should be started with provided object.
297/// If required, all necessary nodes and fields will be created
298/// Used when different collection kinds should be scanned
299
301{
302 if (super.Done())
303 return kFALSE;
304
305 if (obj && !obj_name)
306 obj_name = obj->GetName();
307
308 // exclude zero names
309 if (!obj_name || (*obj_name == 0))
310 return kFALSE;
311
312 const char *full_name = nullptr;
313
314 // remove slashes from file names
315 if (obj && obj->InheritsFrom(TDirectoryFile::Class())) {
316 const char *slash = strrchr(obj_name, '/');
317 if (slash) {
318 full_name = obj_name;
319 obj_name = slash + 1;
320 if (*obj_name == 0)
321 obj_name = "file";
322 }
323 }
324
325 super.MakeItemName(obj_name, fItemName);
326
327 if (sniffer && sniffer->HasRestriction(fItemName.Data())) {
328 // check restriction more precisely
329 TString fullname;
330 BuildFullName(fullname, &super);
331 fRestriction = sniffer->CheckRestriction(fullname.Data());
332 if (fRestriction < 0)
333 return kFALSE;
334 }
335
336 fParent = &super;
337 fLevel = super.fLevel;
338 fStore = super.fStore;
339 fSearchPath = super.fSearchPath;
340 fMask = super.fMask & kActions;
341 if (fRestriction == 0)
342 fRestriction = super.fRestriction; // get restriction from parent
343 Bool_t topelement(kFALSE);
344
345 if (fMask & kScan) {
346 // if scanning only fields, ignore all childs
347 if (super.ScanOnlyFields())
348 return kFALSE;
349 // only when doing scan, increment level, used for text formatting
350 fLevel++;
351 } else {
352 if (!fSearchPath)
353 return kFALSE;
354
355 if (strncmp(fSearchPath, fItemName.Data(), fItemName.Length()) != 0)
356 return kFALSE;
357
358 const char *separ = fSearchPath + fItemName.Length();
359
360 Bool_t isslash = kFALSE;
361 while (*separ == '/') {
362 separ++;
363 isslash = kTRUE;
364 }
365
366 if (*separ == 0) {
367 fSearchPath = nullptr;
368 if (fMask & kExpand) {
369 topelement = kTRUE;
371 fHasMore = (fMask & kOnlyFields) == 0;
372 }
373 } else {
374 if (!isslash)
375 return kFALSE;
376 fSearchPath = separ;
377 }
378 }
379
381
382 if (obj_name && (fItemName != obj_name))
383 SetField(item_prop_realname, obj_name);
384
385 if (full_name)
386 SetField("_fullname", full_name);
387
388 if (topelement)
389 SetField(item_prop_rootversion, TString::Format("%d", gROOT->GetVersionCode()), kFALSE);
390
391 if (topelement && sniffer->GetAutoLoad())
393
394 return kTRUE;
395}
396
397
398/** \class TRootSniffer
399\ingroup http
400
401Sniffer of ROOT objects, data provider for THttpServer
402
403Provides methods to scan different structures like folders,
404directories, files and collections. Can locate objects (or its data member) per name.
405Can be extended to application-specific classes.
406
407Normally TRootSnifferFull class is used which able to access data from trees, canvases, histograms.
408*/
409
411
412////////////////////////////////////////////////////////////////////////////////
413/// constructor
414
415TRootSniffer::TRootSniffer(const char *name, const char *objpath)
416 : TNamed(name, "sniffer of root objects"), fObjectsPath(objpath)
417{
419}
420
421////////////////////////////////////////////////////////////////////////////////
422/// destructor
423
425{
426}
427
428////////////////////////////////////////////////////////////////////////////////
429/// set current http arguments, which then used in different process methods
430/// For instance, if user authorized with some user name,
431/// depending from restrictions some objects will be invisible
432/// or user get full access to the element
433/// Returns previous argument which was set before
434
436{
437 auto res = fCurrentArg;
438 fCurrentArg = arg;
441 return res;
442}
443
444////////////////////////////////////////////////////////////////////////////////
445/// Restrict access to the specified location
446///
447/// Hides or provides read-only access to different parts of the hierarchy
448/// Restriction done base on user-name specified with http requests
449/// Options can be specified in URL style (separated with &)
450/// Following parameters can be specified:
451///
452/// visible = [all|user(s)] - make item visible for all users or only specified user
453/// hidden = [all|user(s)] - make item hidden from all users or only specified user
454/// readonly = [all|user(s)] - make item read-only for all users or only specified user
455/// allow = [all|user(s)] - make full access for all users or only specified user
456/// allow_method = method(s) - allow method(s) execution even when readonly flag specified for the object
457///
458/// Like make command seen by all but can be executed only by admin
459///
460/// sniff->Restrict("/CmdReset","allow=admin");
461///
462/// Or fully hide command from guest account
463///
464/// sniff->Restrict("/CmdRebin","hidden=guest");
465
466void TRootSniffer::Restrict(const char *path, const char *options)
467{
468 const char *rslash = strrchr(path, '/');
469 if (rslash)
470 rslash++;
471 if (!rslash || (*rslash == 0))
472 rslash = path;
473
474 fRestrictions.Add(new TNamed(rslash, TString::Format("%s%s%s", path, "%%%", options).Data()));
475}
476
477////////////////////////////////////////////////////////////////////////////////
478/// When specified, _autoload attribute will be always add
479/// to top element of h.json/h.hml requests
480/// Used to instruct browser automatically load special code
481
482void TRootSniffer::SetAutoLoad(const char *scripts)
483{
484 fAutoLoad = scripts ? scripts : "";
485}
486
487////////////////////////////////////////////////////////////////////////////////
488/// return name of configured autoload scripts (or 0)
489
490const char *TRootSniffer::GetAutoLoad() const
491{
492 return fAutoLoad.Length() > 0 ? fAutoLoad.Data() : nullptr;
493}
494
495////////////////////////////////////////////////////////////////////////////////
496/// Made fast check if item with specified name is in restriction list
497/// If returns true, requires precise check with CheckRestriction() method
498
500{
501 if (!item_name || (*item_name == 0) || !fCurrentArg)
502 return kFALSE;
503
504 return fRestrictions.FindObject(item_name) != nullptr;
505}
506
507////////////////////////////////////////////////////////////////////////////////
508/// return 2 when option match to current user name
509/// return 1 when option==all
510/// return 0 when option does not match user name
511
513{
514 const char *username = fCurrentArg ? fCurrentArg->GetUserName() : nullptr;
515
516 if (!username || !option || (*option == 0))
517 return 0;
518
519 if (strcmp(option, "all") == 0)
520 return 1;
521
522 if (strcmp(username, option) == 0)
523 return 2;
524
525 if (strstr(option, username) == 0)
526 return -1;
527
528 TObjArray *arr = TString(option).Tokenize(",");
529
530 Bool_t find = arr->FindObject(username) != nullptr;
531
532 delete arr;
533
534 return find ? 2 : -1;
535}
536
537////////////////////////////////////////////////////////////////////////////////
538/// Checked if restriction is applied to the item full_item_name
539/// should have full path to the item. Returns:
540///
541/// * -1 - object invisible, cannot be accessed or listed
542/// * 0 - no explicit restrictions, use default
543/// * 1 - read-only access
544/// * 2 - full access
545
546Int_t TRootSniffer::CheckRestriction(const char *full_item_name)
547{
548 if (!full_item_name || (*full_item_name == 0))
549 return 0;
550
551 const char *item_name = strrchr(full_item_name, '/');
552 if (item_name)
553 item_name++;
554 if (!item_name || (*item_name == 0))
555 item_name = full_item_name;
556
557 TString pattern1 = TString("*/") + item_name + "%%%";
558 TString pattern2 = TString(full_item_name) + "%%%";
559
560 const char *options = nullptr;
561 TIter iter(&fRestrictions);
562 TObject *obj;
563
564 while ((obj = iter()) != nullptr) {
565 const char *title = obj->GetTitle();
566
567 if (strstr(title, pattern1.Data()) == title) {
568 options = title + pattern1.Length();
569 break;
570 }
571 if (strstr(title, pattern2.Data()) == title) {
572 options = title + pattern2.Length();
573 break;
574 }
575 }
576
577 if (!options)
578 return 0;
579
580 TUrl url;
581 url.SetOptions(options);
582 url.ParseOptions();
583
584 Int_t can_see =
586
587 Int_t can_access =
589
590 if (can_access > 0)
591 return 2; // first of all, if access enabled, provide it
592 if (can_see < 0)
593 return -1; // if object to be hidden, do it
594
595 const char *methods = url.GetValueFromOptions("allow_method");
596 if (methods)
597 fCurrentAllowedMethods = methods;
598
599 if (can_access < 0)
600 return 1; // read-only access
601
602 return 0; // default behavior
603}
604
605////////////////////////////////////////////////////////////////////////////////
606/// scan object data members
607/// some members like enum or static members will be excluded
608
610{
611 if (!cl || !ptr || rec.Done())
612 return;
613
614 // ensure that real class data (including parents) exists
615 if (!(cl->Property() & kIsAbstract))
616 cl->BuildRealData();
617
618 // scan only real data
619 TObject *obj = nullptr;
620 TIter iter(cl->GetListOfRealData());
621 while ((obj = iter()) != nullptr) {
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 && (strlen(title) != 0))
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 != 0) {
712 if (*pos == ' ') {
713 pos++;
714 continue;
715 }
716 // first locate identifier
717 const char *pos0 = pos;
718 while ((*pos != 0) && (*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 != 0) && (*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 TObject *kobj = nullptr;
850
851 while ((kobj = iter()) != nullptr) {
852 TKey *key = dynamic_cast<TKey *>(kobj);
853 if (!key)
854 continue;
855 TObject *obj = lst ? lst->FindObject(key->GetName()) : nullptr;
856
857 // even object with the name exists, it should also match with class name
858 if (obj && (strcmp(obj->ClassName(), key->GetClassName()) != 0))
859 obj = nullptr;
860
861 // if object of that name and of that class already in the list, ignore appropriate key
862 if (obj && (master.fMask & TRootSnifferScanRec::kScan))
863 continue;
864
865 Bool_t iskey = kFALSE;
866 // if object not exists, provide key itself for the scan
867 if (!obj) {
868 obj = key;
869 iskey = kTRUE;
870 }
871
873 TString fullname = TString::Format("%s;%d", key->GetName(), key->GetCycle());
874
875 if (chld.GoInside(master, obj, fullname.Data(), this)) {
876
877 if (!chld.IsReadOnly(fReadOnly) && iskey && chld.IsReadyForResult()) {
878 TObject *keyobj = key->ReadObj();
879 if (keyobj)
880 if (chld.SetResult(keyobj, keyobj->IsA()))
881 return;
882 }
883
884 if (chld.SetResult(obj, obj->IsA()))
885 return;
886
887 TClass *obj_class = obj->IsA();
888
889 ScanObjectProperties(chld, obj);
890
891 if (obj->GetTitle())
892 chld.SetField(item_prop_title, obj->GetTitle());
893
894 // special handling of TKey class - in non-readonly mode
895 // sniffer allowed to fetch objects
896 if (!chld.IsReadOnly(fReadOnly) && iskey)
897 ScanKeyProperties(chld, key, obj, obj_class);
898
899 rec.SetRootClass(obj_class);
900
901 ScanObjectChilds(chld, obj);
902
903 // here we should know how many childs are accumulated
904 if (chld.SetResult(obj, obj_class))
905 return;
906 }
907 }
908 }
909}
910
911////////////////////////////////////////////////////////////////////////////////
912/// Create own TFolder structures independent from gROOT
913/// This allows to have many independent TRootSniffer instances
914/// At the same time such sniffer lost access to all global lists and folders
915
917{
918 if (fTopFolder) return;
919
921
922 // this only works with c++14, use ROOT wrapper
923 fTopFolder = std::make_unique<TFolder>("http","Dedicated instance");
924
925 // not sure if we have to add that private folder to global list of cleanups
926
927 // R__LOCKGUARD(gROOTMutex);
928 // gROOT->GetListOfCleanups()->Add(fTopFolder.get());
929
930}
931
932////////////////////////////////////////////////////////////////////////////////
933/// Returns top TFolder instance for the sniffer
934
936{
937 if (fTopFolder) return fTopFolder.get();
938
939 TFolder *topf = gROOT->GetRootFolder();
940
941 if (!topf) {
942 Error("RegisterObject", "Not found top ROOT folder!!!");
943 return nullptr;
944 }
945
946 TFolder *httpfold = dynamic_cast<TFolder *>(topf->FindObject("http"));
947 if (!httpfold) {
948 if (!force)
949 return nullptr;
950 httpfold = topf->AddFolder("http", "ROOT http server");
951 httpfold->SetBit(kCanDelete);
952 // register top folder in list of cleanups
954 gROOT->GetListOfCleanups()->Add(httpfold);
955 }
956
957 return httpfold;
958}
959
960////////////////////////////////////////////////////////////////////////////////
961/// scan complete ROOT objects hierarchy
962/// For the moment it includes objects in gROOT directory
963/// and list of canvases and files
964/// Also all registered objects are included.
965/// One could re-implement this method to provide alternative
966/// scan methods or to extend some collection kinds
967
969{
970 rec.SetField(item_prop_kind, "ROOT.Session");
972 rec.SetField(item_prop_user, fCurrentArg->GetUserName());
973
974 // should be on the top while //root/http folder could have properties for itself
975 TFolder *topf = GetTopFolder();
976 if (topf) {
977 rec.SetField(item_prop_title, topf->GetTitle());
978 ScanCollection(rec, topf->GetListOfFolders());
979 }
980
981 if (HasStreamerInfo()) {
983 if (chld.GoInside(rec, nullptr, "StreamerInfo", this)) {
984 chld.SetField(item_prop_kind, "ROOT.TStreamerInfoList");
985 chld.SetField(item_prop_title, "List of streamer infos for binary I/O");
986 chld.SetField(item_prop_hidden, "true", kFALSE);
987 chld.SetField("_module", "hierarchy");
988 chld.SetField("_after_request", "markAsStreamerInfo");
989 }
990 }
991
992 if (IsScanGlobalDir()) {
993 ScanCollection(rec, gROOT->GetList());
994
995 ScanCollection(rec, gROOT->GetListOfCanvases(), "Canvases");
996
997 ScanCollection(rec, gROOT->GetListOfFiles(), "Files");
998 }
999}
1000
1001////////////////////////////////////////////////////////////////////////////////
1002/// scan ROOT hierarchy with provided store object
1003
1004void TRootSniffer::ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store,
1005 Bool_t only_fields)
1006{
1008 rec.fSearchPath = path;
1009 if (rec.fSearchPath) {
1010 while (*rec.fSearchPath == '/')
1011 rec.fSearchPath++;
1012 if (*rec.fSearchPath == 0)
1013 rec.fSearchPath = nullptr;
1014 }
1015
1016 // if path non-empty, we should find item first and than start scanning
1017 rec.fMask = !rec.fSearchPath ? TRootSnifferScanRec::kScan : TRootSnifferScanRec::kExpand;
1018 if (only_fields)
1020
1021 rec.fStore = store;
1022
1023 rec.CreateNode(topname);
1024
1025 if (!rec.fSearchPath)
1027
1028 if (!rec.fSearchPath && GetAutoLoad())
1029 rec.SetField(item_prop_autoload, GetAutoLoad());
1030
1031 ScanRoot(rec);
1032
1033 rec.CloseNode();
1034}
1035
1036////////////////////////////////////////////////////////////////////////////////
1037/// Search element with specified path
1038/// Returns pointer on element
1039/// Optionally one could obtain element class, member description
1040/// and number of childs. When chld!=nullptr, not only element is searched,
1041/// but also number of childs are counted. When member!=0, any object
1042/// will be scanned for its data members (disregard of extra options)
1043
1044void *TRootSniffer::FindInHierarchy(const char *path, TClass **cl, TDataMember **member, Int_t *chld)
1045{
1046 TRootSnifferStore store;
1047
1049 rec.fSearchPath = path;
1051 if (*rec.fSearchPath == '/')
1052 rec.fSearchPath++;
1053 rec.fStore = &store;
1054
1055 ScanRoot(rec);
1056
1057 TDataMember *res_member = store.GetResMember();
1058 TClass *res_cl = store.GetResClass();
1059 void *res = store.GetResPtr();
1060
1061 if (res_member && res_cl && !member) {
1062 res_cl = (res_member->IsBasic() || res_member->IsSTLContainer()) ? nullptr : gROOT->GetClass(res_member->GetTypeName());
1063 TRealData *rdata = res_cl ? res_cl->GetRealData(res_member->GetName()) : nullptr;
1064 if (rdata) {
1065 res = (char *)res + rdata->GetThisOffset();
1066 if (res_member->IsaPointer())
1067 res = *((char **)res);
1068 } else {
1069 res = nullptr; // should never happen
1070 }
1071 }
1072
1073 if (cl)
1074 *cl = res_cl;
1075 if (member)
1076 *member = res_member;
1077 if (chld)
1078 *chld = store.GetResNumChilds();
1079
1080 // remember current restriction
1082
1083 return res;
1084}
1085
1086////////////////////////////////////////////////////////////////////////////////
1087/// Search element in hierarchy, derived from TObject
1088
1090{
1091 TClass *cl = nullptr;
1092
1093 void *obj = FindInHierarchy(path, &cl);
1094
1095 return cl && (cl->GetBaseClassOffset(TObject::Class()) == 0) ? (TObject *)obj : nullptr;
1096}
1097
1098////////////////////////////////////////////////////////////////////////////////
1099/// Get hash function for specified item
1100/// used to detect any changes in the specified object
1101
1103{
1104 TObject *obj = FindTObjectInHierarchy(itemname);
1105
1106 return !obj ? 0 : TString::Hash(obj, obj->IsA()->Size());
1107}
1108
1109////////////////////////////////////////////////////////////////////////////////
1110/// Method verifies if object can be drawn
1111
1113{
1114 TClass *obj_cl = nullptr;
1115 void *res = FindInHierarchy(path, &obj_cl);
1116 return (res != nullptr) && CanDrawClass(obj_cl);
1117}
1118
1119////////////////////////////////////////////////////////////////////////////////
1120/// Method returns true when object has childs or
1121/// one could try to expand item
1122
1124{
1125 TClass *obj_cl = nullptr;
1126 Int_t obj_chld(-1);
1127 void *res = FindInHierarchy(path, &obj_cl, nullptr, &obj_chld);
1128 return res && (obj_chld > 0);
1129}
1130
1131////////////////////////////////////////////////////////////////////////////////
1132/// Produce JSON data for specified item
1133/// For object conversion TBufferJSON is used
1134
1135Bool_t TRootSniffer::ProduceJson(const std::string &path, const std::string &options, std::string &res)
1136{
1137 if (path.empty())
1138 return kFALSE;
1139
1140 const char *path_ = path.c_str();
1141 if (*path_ == '/')
1142 path_++;
1143
1144 TUrl url;
1145 url.SetOptions(options.c_str());
1146 url.ParseOptions();
1147 Int_t compact = -1;
1148 if (url.GetValueFromOptions("compact"))
1149 compact = url.GetIntValueFromOptions("compact");
1150
1151 TClass *obj_cl = nullptr;
1152 TDataMember *member = nullptr;
1153 void *obj_ptr = FindInHierarchy(path_, &obj_cl, &member);
1154 if (!obj_ptr || (!obj_cl && !member))
1155 return kFALSE;
1156
1157 // TODO: implement direct storage into std::string
1158 TString buf = TBufferJSON::ConvertToJSON(obj_ptr, obj_cl, compact >= 0 ? compact : 0, member ? member->GetName() : nullptr);
1159 res = buf.Data();
1160
1161 return !res.empty();
1162}
1163
1164////////////////////////////////////////////////////////////////////////////////
1165/// Execute command marked as _kind=='Command'
1166
1167Bool_t TRootSniffer::ExecuteCmd(const std::string &path, const std::string &options, std::string &res)
1168{
1169 TFolder *parent = nullptr;
1170 TObject *obj = GetItem(path.c_str(), parent, kFALSE, kFALSE);
1171
1172 const char *kind = GetItemField(parent, obj, item_prop_kind);
1173 if ((kind == 0) || (strcmp(kind, "Command") != 0)) {
1174 if (gDebug > 0)
1175 Info("ExecuteCmd", "Entry %s is not a command", path.c_str());
1176 res = "false";
1177 return kTRUE;
1178 }
1179
1180 const char *cmethod = GetItemField(parent, obj, "method");
1181 if (!cmethod || (strlen(cmethod) == 0)) {
1182 if (gDebug > 0)
1183 Info("ExecuteCmd", "Entry %s do not defines method for execution", path.c_str());
1184 res = "false";
1185 return kTRUE;
1186 }
1187
1188 // if read-only specified for the command, it is not allowed for execution
1189 if (fRestrictions.GetLast() >= 0) {
1190 FindInHierarchy(path.c_str()); // one need to call method to check access rights
1191 if (fCurrentRestrict == 1) {
1192 if (gDebug > 0)
1193 Info("ExecuteCmd", "Entry %s not allowed for specified user", path.c_str());
1194 res = "false";
1195 return kTRUE;
1196 }
1197 }
1198
1199 TString method = cmethod;
1200
1201 const char *cnumargs = GetItemField(parent, obj, "_numargs");
1202 Int_t numargs = cnumargs ? TString(cnumargs).Atoi() : 0;
1203 if (numargs > 0) {
1204 TUrl url;
1205 url.SetOptions(options.c_str());
1206 url.ParseOptions();
1207
1208 for (Int_t n = 0; n < numargs; n++) {
1209 TString argname = TString::Format("arg%d", n + 1);
1210 const char *argvalue = url.GetValueFromOptions(argname);
1211 if (!argvalue) {
1212 if (gDebug > 0)
1213 Info("ExecuteCmd", "For command %s argument %s not specified in options %s", path.c_str(), argname.Data(),
1214 options.c_str());
1215 res = "false";
1216 return kTRUE;
1217 }
1218
1219 TString svalue = DecodeUrlOptionValue(argvalue, kTRUE);
1220 argname = TString("%") + argname + TString("%");
1221 method.ReplaceAll(argname, svalue);
1222 }
1223 }
1224
1225 if (gDebug > 0)
1226 Info("ExecuteCmd", "Executing command %s method:%s", path.c_str(), method.Data());
1227
1228 TObject *item_obj = nullptr;
1229 Ssiz_t separ = method.Index("/->");
1230
1231 if (method.Index("this->") == 0) {
1232 // if command name started with this-> means method of sniffer will be executed
1233 item_obj = this;
1234 separ = 3;
1235 } else if (separ != kNPOS) {
1236 item_obj = FindTObjectInHierarchy(TString(method.Data(), separ).Data());
1237 }
1238
1239 if (item_obj) {
1240 method = TString::Format("((%s*)%zu)->%s", item_obj->ClassName(), (size_t)item_obj, method.Data() + separ + 3);
1241 if (gDebug > 2)
1242 Info("ExecuteCmd", "Executing %s", method.Data());
1243 }
1244
1245 auto v = gROOT->ProcessLineSync(method.Data());
1246
1247 res = std::to_string(v);
1248
1249 return kTRUE;
1250}
1251
1252////////////////////////////////////////////////////////////////////////////////
1253/// Produce JSON/XML for specified item
1254///
1255/// Contrary to h.json request, only fields for specified item are stored
1256
1257Bool_t TRootSniffer::ProduceItem(const std::string &path, const std::string &options, std::string &res, Bool_t asjson)
1258{
1259 TString buf; // TODO: implement direct storage into std::string
1260 if (asjson) {
1261 TRootSnifferStoreJson store(buf, options.find("compact") != std::string::npos);
1262 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1263 } else {
1264 TRootSnifferStoreXml store(buf, options.find("compact") != std::string::npos);
1265 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1266 }
1267 res = buf.Data();
1268 return !res.empty();
1269}
1270
1271////////////////////////////////////////////////////////////////////////////////
1272/// Produce XML data for specified item
1273///
1274/// For object conversion TBufferXML is used
1275/// Method implemented only in TRootSnifferFull class
1276
1277Bool_t TRootSniffer::ProduceXml(const std::string &/* path */, const std::string & /* options */, std::string & /* res */)
1278{
1279 return kFALSE;
1280}
1281
1282////////////////////////////////////////////////////////////////////////////////
1283/// Method replaces all kind of special symbols, which could appear in URL options
1284
1286{
1287 if (!value || (strlen(value) == 0))
1288 return TString();
1289
1290 TString res = value;
1291
1292 res.ReplaceAll("%27", "\'");
1293 res.ReplaceAll("%22", "\"");
1294 res.ReplaceAll("%3E", ">");
1295 res.ReplaceAll("%3C", "<");
1296 res.ReplaceAll("%20", " ");
1297 res.ReplaceAll("%5B", "[");
1298 res.ReplaceAll("%5D", "]");
1299 res.ReplaceAll("%3D", "=");
1300
1301 if (remove_quotes && (res.Length() > 1) && ((res[0] == '\'') || (res[0] == '\"')) &&
1302 (res[0] == res[res.Length() - 1])) {
1303 res.Remove(res.Length() - 1);
1304 res.Remove(0, 1);
1305 }
1306
1307 return res;
1308}
1309
1310////////////////////////////////////////////////////////////////////////////////
1311/// Execute command for specified object
1312///
1313/// Options include method and extra list of parameters
1314/// sniffer should be not-readonly to allow execution of the commands
1315/// reskind defines kind of result 0 - debug, 1 - json, 2 - binary
1316///
1317/// Method implemented only in TRootSnifferFull class
1318
1319Bool_t TRootSniffer::ProduceExe(const std::string & /*path*/, const std::string & /*options*/, Int_t /*reskind*/,
1320 std::string & /*res*/)
1321{
1322 return kFALSE;
1323}
1324
1325////////////////////////////////////////////////////////////////////////////////
1326/// Process several requests, packing all results into binary or JSON buffer
1327///
1328/// Input parameters should be coded in the POST block and has
1329/// individual request relative to current path, separated with '\n' symbol like
1330/// item1/root.bin\n
1331/// item2/exe.bin?method=GetList\n
1332/// item3/exe.bin?method=GetTitle\n
1333/// Request requires 'number' URL option which contains number of requested items
1334///
1335/// In case of binary request output buffer looks like:
1336///
1337/// 4bytes length + payload,
1338/// 4bytes length + payload, ...
1339///
1340/// In case of JSON request output is array with results for each item
1341/// multi.json request do not support binary requests for the items
1342
1343Bool_t TRootSniffer::ProduceMulti(const std::string &path, const std::string &options, std::string &str, Bool_t asjson)
1344{
1346 return kFALSE;
1347
1348 const char *args = (const char *)fCurrentArg->GetPostData();
1349 const char *ends = args + fCurrentArg->GetPostDataLength();
1350
1351 TUrl url;
1352 url.SetOptions(options.c_str());
1353
1354 Int_t number = 0;
1355 if (url.GetValueFromOptions("number"))
1356 number = url.GetIntValueFromOptions("number");
1357
1358 // binary buffers required only for binary requests, json output can be produced as is
1359 std::vector<std::string> mem;
1360
1361 if (asjson)
1362 str = "[";
1363
1364 for (Int_t n = 0; n < number; n++) {
1365 const char *next = args;
1366 while ((next < ends) && (*next != '\n'))
1367 next++;
1368 if (next == ends) {
1369 Error("ProduceMulti", "Not enough arguments in POST block");
1370 break;
1371 }
1372
1373 std::string file1(args, next - args);
1374 args = next + 1;
1375
1376 std::string path1, opt1;
1377
1378 // extract options
1379 std::size_t pos = file1.find_first_of('?');
1380 if (pos != std::string::npos) {
1381 opt1 = file1.substr(pos + 1, file1.length() - pos);
1382 file1.resize(pos);
1383 }
1384
1385 // extract extra path
1386 pos = file1.find_last_of('/');
1387 if (pos != std::string::npos) {
1388 path1 = file1.substr(0, pos);
1389 file1.erase(0, pos + 1);
1390 }
1391
1392 if (!path.empty())
1393 path1 = path + "/" + path1;
1394
1395 std::string res1;
1396
1397 // produce next item request
1398 Produce(path1, file1, opt1, res1);
1399
1400 if (asjson) {
1401 if (n > 0)
1402 str.append(", ");
1403 if (res1.empty())
1404 str.append("null");
1405 else
1406 str.append(res1);
1407 } else {
1408 mem.emplace_back(std::move(res1));
1409 }
1410 }
1411
1412 if (asjson) {
1413 str.append("]");
1414 } else {
1415 Int_t length = 0;
1416 for (unsigned n = 0; n < mem.size(); n++)
1417 length += 4 + mem[n].length();
1418 str.resize(length);
1419 char *curr = (char *)str.data();
1420 for (unsigned n = 0; n < mem.size(); n++) {
1421 Long_t l = mem[n].length();
1422 *curr++ = (char)(l & 0xff);
1423 l = l >> 8;
1424 *curr++ = (char)(l & 0xff);
1425 l = l >> 8;
1426 *curr++ = (char)(l & 0xff);
1427 l = l >> 8;
1428 *curr++ = (char)(l & 0xff);
1429 if (!mem[n].empty())
1430 memcpy(curr, mem[n].data(), mem[n].length());
1431 curr += mem[n].length();
1432 }
1433 }
1434
1435 return kTRUE;
1436}
1437
1438////////////////////////////////////////////////////////////////////////////////
1439/// Produce binary data for specified item
1440///
1441/// If "zipped" option specified in query, buffer will be compressed
1442///
1443/// Implemented only in TRootSnifferFull class
1444
1445Bool_t TRootSniffer::ProduceBinary(const std::string & /*path*/, const std::string & /*query*/, std::string & /*res*/)
1446{
1447 return kFALSE;
1448}
1449
1450////////////////////////////////////////////////////////////////////////////////
1451/// Method to produce image from specified object
1452///
1453/// Parameters:
1454///
1455/// kind - image kind TImage::kPng, TImage::kJpeg, TImage::kGif
1456/// path - path to object
1457/// options - extra options
1458///
1459/// By default, image 300x200 is produced
1460/// In options string one could provide following parameters:
1461///
1462/// w - image width
1463/// h - image height
1464/// opt - draw options
1465///
1466/// For instance:
1467///
1468/// http://localhost:8080/Files/hsimple.root/hpx/get.png?w=500&h=500&opt=lego1
1469///
1470/// Returns produced image in the res string
1471///
1472/// Method implemented only in TRootSnifferFull class
1473
1474Bool_t TRootSniffer::ProduceImage(Int_t /*kind*/, const std::string & /*path*/, const std::string & /*options*/, std::string & /*res*/)
1475{
1476 return kFALSE;
1477}
1478
1479////////////////////////////////////////////////////////////////////////////////
1480/// Invokes TRootSniffer::ProduceIamge, converting kind into TImage::EImageFileTypes type
1481
1482Bool_t TRootSniffer::CallProduceImage(const std::string &/*kind*/, const std::string &/*path*/, const std::string &/*options*/, std::string &/*res*/)
1483{
1484 return kFALSE;
1485}
1486
1487////////////////////////////////////////////////////////////////////////////////
1488/// Method produce different kind of data out of object
1489///
1490/// @param path specifies object or object member
1491/// @param file can be:
1492///
1493/// * "root.bin" - binary data
1494/// * "root.png" - png image
1495/// * "root.jpeg" - jpeg image
1496/// * "root.gif" - gif image
1497/// * "root.xml" - xml representation
1498/// * "root.json" - json representation
1499/// * "exe.json" - method execution with json reply
1500/// * "exe.bin" - method execution with binary reply
1501/// * "exe.txt" - method execution with debug output
1502/// * "cmd.json" - execution of registered commands
1503///
1504/// @param res returns result - binary or text.
1505
1506Bool_t TRootSniffer::Produce(const std::string &path, const std::string &file, const std::string &options, std::string &res)
1507{
1508 if (file.empty())
1509 return kFALSE;
1510
1511 if (file == "root.bin")
1512 return ProduceBinary(path, options, res);
1513
1514 if (file == "root.png")
1515 return CallProduceImage("png", path, options, res);
1516
1517 if (file == "root.jpeg")
1518 return CallProduceImage("jpeg", path, options, res);
1519
1520 if (file == "root.gif")
1521 return CallProduceImage("gif", path, options, res);
1522
1523 if (file == "exe.bin")
1524 return ProduceExe(path, options, 2, res);
1525
1526 if (file == "root.xml")
1527 return ProduceXml(path, options, res);
1528
1529 if (file == "root.json")
1530 return ProduceJson(path, options, res);
1531
1532 // used for debugging
1533 if (file == "exe.txt")
1534 return ProduceExe(path, options, 0, res);
1535
1536 if (file == "exe.json")
1537 return ProduceExe(path, options, 1, res);
1538
1539 if (file == "cmd.json")
1540 return ExecuteCmd(path, options, res);
1541
1542 if (file == "item.json")
1543 return ProduceItem(path, options, res, kTRUE);
1544
1545 if (file == "item.xml")
1546 return ProduceItem(path, options, res, kFALSE);
1547
1548 if (file == "multi.bin")
1549 return ProduceMulti(path, options, res, kFALSE);
1550
1551 if (file == "multi.json")
1552 return ProduceMulti(path, options, res, kTRUE);
1553
1554 return kFALSE;
1555}
1556
1557////////////////////////////////////////////////////////////////////////////////
1558/// Return item from the subfolders structure
1559
1560TObject *TRootSniffer::GetItem(const char *fullname, TFolder *&parent, Bool_t force, Bool_t within_objects)
1561{
1562 TFolder *httpfold = GetTopFolder(force);
1563 if (!httpfold) return nullptr;
1564
1565 parent = httpfold;
1566 TObject *obj = httpfold;
1567
1568 if (!fullname)
1569 return httpfold;
1570
1571 // when full path started not with slash, "Objects" subfolder is appended
1572 TString path = fullname;
1573 if (within_objects && ((path.Length() == 0) || (path[0] != '/')))
1574 path = fObjectsPath + "/" + path;
1575
1576 TString tok;
1577 Ssiz_t from(0);
1578
1579 while (path.Tokenize(tok, from, "/")) {
1580 if (tok.Length() == 0)
1581 continue;
1582
1583 TFolder *fold = dynamic_cast<TFolder *>(obj);
1584 if (!fold)
1585 return nullptr;
1586
1587 TIter iter(fold->GetListOfFolders());
1588 while ((obj = iter()) != nullptr) {
1589 if (IsItemField(obj))
1590 continue;
1591 if (tok.CompareTo(obj->GetName()) == 0)
1592 break;
1593 }
1594
1595 if (!obj) {
1596 if (!force)
1597 return nullptr;
1598 obj = fold->AddFolder(tok, "sub-folder");
1599 obj->SetBit(kCanDelete);
1600 }
1601
1602 parent = fold;
1603 }
1604
1605 return obj;
1606}
1607
1608////////////////////////////////////////////////////////////////////////////////
1609/// Creates subfolder where objects can be registered
1610
1611TFolder *TRootSniffer::GetSubFolder(const char *subfolder, Bool_t force)
1612{
1613 TFolder *parent = nullptr;
1614
1615 return dynamic_cast<TFolder *>(GetItem(subfolder, parent, force));
1616}
1617
1618////////////////////////////////////////////////////////////////////////////////
1619/// Register object in subfolder structure
1620///
1621/// @param subfolder can have many levels like:
1622///
1623/// TRootSniffer* sniff = new TRootSniffer("sniff");
1624/// sniff->RegisterObject("my/sub/subfolder", h1);
1625///
1626/// Such objects can be later found in "Objects" folder of sniffer like
1627///
1628/// auto h1 = sniff->FindTObjectInHierarchy("/Objects/my/sub/subfolder/h1");
1629///
1630/// If subfolder name starts with '/', object will be registered starting from top folder.
1631///
1632/// One could provide additional fields for registered objects
1633/// For instance, setting "_more" field to true let browser
1634/// explore objects members. For instance:
1635///
1636/// TEvent* ev = new TEvent("ev");
1637/// sniff->RegisterObject("Events", ev);
1638/// sniff->SetItemField("Events/ev", "_more", "true");
1639
1640Bool_t TRootSniffer::RegisterObject(const char *subfolder, TObject *obj)
1641{
1642 TFolder *f = GetSubFolder(subfolder, kTRUE);
1643 if (!f)
1644 return kFALSE;
1645
1646 // If object will be destroyed, it will be removed from the folders automatically
1647 obj->SetBit(kMustCleanup);
1648
1649 f->Add(obj);
1650
1651 return kTRUE;
1652}
1653
1654////////////////////////////////////////////////////////////////////////////////
1655/// Unregister (remove) object from folders structures
1656///
1657/// Folder itself will remain even when it will be empty
1658
1660{
1661 if (!obj)
1662 return kTRUE;
1663
1664 TFolder *topf = GetTopFolder();
1665
1666 if (!topf) {
1667 Error("UnregisterObject", "Not found top folder");
1668 return kFALSE;
1669 }
1670
1671 // TODO - probably we should remove all set properties as well
1672 topf->RecursiveRemove(obj);
1673
1674 return kTRUE;
1675}
1676
1677////////////////////////////////////////////////////////////////////////////////
1678/// Create item element
1679
1680Bool_t TRootSniffer::CreateItem(const char *fullname, const char *title)
1681{
1682 TFolder *f = GetSubFolder(fullname, kTRUE);
1683 if (!f)
1684 return kFALSE;
1685
1686 if (title)
1687 f->SetTitle(title);
1688
1689 return kTRUE;
1690}
1691
1692////////////////////////////////////////////////////////////////////////////////
1693/// Return true when object is TNamed with kItemField bit set
1694///
1695/// such objects used to keep field values for item
1696
1698{
1699 return (obj != nullptr) && (obj->IsA() == TNamed::Class()) && obj->TestBit(kItemField);
1700}
1701
1702////////////////////////////////////////////////////////////////////////////////
1703/// Set or get field for the child
1704///
1705/// each field coded as TNamed object, placed after chld in the parent hierarchy
1706
1707Bool_t TRootSniffer::AccessField(TFolder *parent, TObject *chld, const char *name, const char *value, TNamed **only_get)
1708{
1709 if (!parent)
1710 return kFALSE;
1711
1712 if (!chld) {
1713 Info("AccessField", "Should be special case for top folder, support later");
1714 return kFALSE;
1715 }
1716
1717 TIter iter(parent->GetListOfFolders());
1718
1719 TObject *obj = nullptr;
1720 Bool_t find(kFALSE), last_find(kFALSE);
1721 // this is special case of top folder - fields are on very top
1722 if (parent == chld) {
1723 last_find = find = kTRUE;
1724 }
1725 TNamed *curr = nullptr;
1726 while ((obj = iter()) != nullptr) {
1727 if (IsItemField(obj)) {
1728 if (last_find && obj->GetName() && !strcmp(name, obj->GetName()))
1729 curr = (TNamed *)obj;
1730 } else {
1731 last_find = (obj == chld);
1732 if (last_find)
1733 find = kTRUE;
1734 if (find && !last_find)
1735 break; // no need to continue
1736 }
1737 }
1738
1739 // object must be in childs list
1740 if (!find)
1741 return kFALSE;
1742
1743 if (only_get) {
1744 *only_get = curr;
1745 return curr != nullptr;
1746 }
1747
1748 if (curr) {
1749 if (value) {
1750 curr->SetTitle(value);
1751 } else {
1752 parent->Remove(curr);
1753 delete curr;
1754 }
1755 return kTRUE;
1756 }
1757
1758 curr = new TNamed(name, value);
1759 curr->SetBit(kItemField);
1760
1761 if (last_find) {
1762 // object is on last place, therefore just add property
1763 parent->Add(curr);
1764 return kTRUE;
1765 }
1766
1767 // only here we do dynamic cast to the TList to use AddAfter
1768 TList *lst = dynamic_cast<TList *>(parent->GetListOfFolders());
1769 if (!lst) {
1770 Error("AccessField", "Fail cast to TList");
1771 return kFALSE;
1772 }
1773
1774 if (parent == chld)
1775 lst->AddFirst(curr);
1776 else
1777 lst->AddAfter(chld, curr);
1778
1779 return kTRUE;
1780}
1781
1782////////////////////////////////////////////////////////////////////////////////
1783/// Set field for specified item
1784
1785Bool_t TRootSniffer::SetItemField(const char *fullname, const char *name, const char *value)
1786{
1787 if (!fullname || !name)
1788 return kFALSE;
1789
1790 TFolder *parent = nullptr;
1791 TObject *obj = GetItem(fullname, parent);
1792
1793 if (!parent || !obj)
1794 return kFALSE;
1795
1796 if (strcmp(name, item_prop_title) == 0) {
1797 TNamed *n = dynamic_cast<TNamed *>(obj);
1798 if (n) {
1799 n->SetTitle(value);
1800 return kTRUE;
1801 }
1802 }
1803
1804 return AccessField(parent, obj, name, value);
1805}
1806
1807////////////////////////////////////////////////////////////////////////////////
1808/// Return field for specified item
1809
1810const char *TRootSniffer::GetItemField(TFolder *parent, TObject *obj, const char *name)
1811{
1812 if (!parent || !obj || !name)
1813 return nullptr;
1814
1815 TNamed *field = nullptr;
1816
1817 if (!AccessField(parent, obj, name, nullptr, &field))
1818 return nullptr;
1819
1820 return field ? field->GetTitle() : nullptr;
1821}
1822
1823////////////////////////////////////////////////////////////////////////////////
1824/// Return field for specified item
1825
1826const char *TRootSniffer::GetItemField(const char *fullname, const char *name)
1827{
1828 if (!fullname)
1829 return nullptr;
1830
1831 TFolder *parent = nullptr;
1832 TObject *obj = GetItem(fullname, parent);
1833
1834 return GetItemField(parent, obj, name);
1835}
1836
1837////////////////////////////////////////////////////////////////////////////////
1838/// Register command which can be executed from web interface
1839///
1840/// As method one typically specifies string, which is executed with
1841/// gROOT->ProcessLine() method. For instance:
1842///
1843/// serv->RegisterCommand("Invoke","InvokeFunction()");
1844///
1845/// Or one could specify any method of the object which is already registered
1846/// to the server. For instance:
1847///
1848/// serv->Register("/", hpx);
1849/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
1850///
1851/// Here symbols '/->' separates item name from method to be executed
1852///
1853/// One could specify additional arguments in the command with
1854/// syntax like %arg1%, %arg2% and so on. For example:
1855///
1856/// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
1857/// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
1858///
1859/// Such parameter(s) will be requested when command clicked in the browser.
1860///
1861/// Once command is registered, one could specify icon which will appear in the browser:
1862///
1863/// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
1864///
1865/// One also can set extra property '_fastcmd', that command appear as
1866/// tool button on the top of the browser tree:
1867///
1868/// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
1869///
1870/// Or it is equivalent to specifying extra argument when register command:
1871///
1872/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
1873
1874Bool_t TRootSniffer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
1875{
1876 CreateItem(cmdname, Form("command %s", method));
1877 SetItemField(cmdname, "_kind", "Command");
1878 if (icon) {
1879 if (strncmp(icon, "button;", 7) == 0) {
1880 SetItemField(cmdname, "_fastcmd", "true");
1881 icon += 7;
1882 }
1883 if (*icon != 0)
1884 SetItemField(cmdname, "_icon", icon);
1885 }
1886 SetItemField(cmdname, "method", method);
1887 Int_t numargs = 0;
1888 do {
1889 TString nextname = TString::Format("%sarg%d%s", "%", numargs + 1, "%");
1890 if (strstr(method, nextname.Data()) == nullptr)
1891 break;
1892 numargs++;
1893 } while (numargs < 100);
1894 if (numargs > 0)
1895 SetItemField(cmdname, "_numargs", TString::Format("%d", numargs));
1896
1897 return kTRUE;
1898}
#define f(i)
Definition RSha256.hxx:104
#define ROOT_VERSION_CODE
Definition RVersion.hxx:24
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 gDebug
Definition TROOT.cxx:597
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:407
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
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2467
#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:2031
TList * GetListOfRealData() const
Definition TClass.h:453
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5704
Int_t GetBaseClassOffset(const TClass *toBase, void *address=nullptr, bool isDerivedObject=true)
Definition TClass.cxx:2791
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6086
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:3503
Collection abstract base class.
Definition TCollection.h:65
static TClass * Class()
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
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
Get the decayed type name of this data member, removing const and volatile qualifiers,...
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.
const char * GetUserName() const
return authenticated user name (0 - when no authentication)
const void * GetPostData() const
return pointer on posted with request data
Long_t GetPostDataLength() const
return length of posted with request data
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:577
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition TKey.cxx:758
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:250
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:578
void Add(TObject *obj) override
Definition TList.h:81
void AddFirst(TObject *obj) override
Add object at the beginning of the list.
Definition TList.cxx:100
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
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:199
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:243
@ 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
@ 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
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
UInt_t fMask
! defines operation kind
void MakeItemName(const char *objname, TString &itemname)
Construct item name, using object name as basis.
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
virtual void CreateNode(Int_t, const char *)
void * GetResPtr() const
void SetResult(void *_res, TClass *_rescl, TDataMember *_resmemb, Int_t _res_chld, Int_t restr=0)
set pointer on found element, class and number of childs
virtual void CloseNode(Int_t, Int_t)
TClass * GetResClass() const
virtual void BeforeNextChild(Int_t, Int_t, Int_t)
Int_t GetResRestrict() const
virtual void SetField(Int_t, const char *, const char *, Bool_t)
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.
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'.
TRootSniffer(const char *name, const char *objpath="Objects")
constructor
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.
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.
virtual Int_t GetLast() const
Returns index of last object in collection.
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:421
int CompareTo(const char *cs, ECaseCompare cmp=kExact) const
Compare a string to char *cs2.
Definition TString.cxx:450
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:1966
const char * Data() const
Definition TString.h:380
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:2242
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition TString.cxx:670
TString & Remove(Ssiz_t pos)
Definition TString.h:685
TString & Append(const char *cs)
Definition TString.h:576
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:2356
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2334
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
Definition file.py:1
TCanvas * slash()
Definition slash.C:1
TLine l
Definition textangle.C:4