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 "TImage.h"
28#include "TVirtualMutex.h"
29#include "TRootSnifferStore.h"
30#include "THttpCallArg.h"
31#include "ROOT/RMakeUnique.hxx"
32
33#include <stdlib.h>
34#include <vector>
35#include <string.h>
36
37const char *item_prop_kind = "_kind";
38const char *item_prop_more = "_more";
39const char *item_prop_title = "_title";
40const char *item_prop_hidden = "_hidden";
41const char *item_prop_typename = "_typename";
42const char *item_prop_arraydim = "_arraydim";
43const char *item_prop_realname = "_realname"; // real object name
44const char *item_prop_user = "_username";
45const char *item_prop_autoload = "_autoload";
46const char *item_prop_rootversion = "_root_version";
47
48//////////////////////////////////////////////////////////////////////////
49// //
50// TRootSnifferScanRec //
51// //
52// Structure used to scan hierarchies of ROOT objects //
53// Represents single level of hierarchy //
54// //
55//////////////////////////////////////////////////////////////////////////
56
57////////////////////////////////////////////////////////////////////////////////
58/// constructor
59
61{
63}
64
65////////////////////////////////////////////////////////////////////////////////
66/// destructor
67
69{
70 CloseNode();
71}
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())
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)
151
152 if (fStore)
153 fStore->CreateNode(fLevel, _node_name);
154}
155
156////////////////////////////////////////////////////////////////////////////////
157/// close started node
158
160{
161 if (fStore && fNodeStarted) {
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
302Bool_t
303TRootSnifferScanRec::GoInside(TRootSnifferScanRec &super, TObject *obj, const char *obj_name, TRootSniffer *sniffer)
304{
305 if (super.Done())
306 return kFALSE;
307
308 if (obj && !obj_name)
309 obj_name = obj->GetName();
310
311 // exclude zero names
312 if (!obj_name || (*obj_name == 0))
313 return kFALSE;
314
315 const char *full_name = nullptr;
316
317 // remove slashes from file names
318 if (obj && obj->InheritsFrom(TDirectoryFile::Class())) {
319 const char *slash = strrchr(obj_name, '/');
320 if (slash) {
321 full_name = obj_name;
322 obj_name = slash + 1;
323 if (*obj_name == 0)
324 obj_name = "file";
325 }
326 }
327
328 super.MakeItemName(obj_name, fItemName);
329
330 if (sniffer && sniffer->HasRestriction(fItemName.Data())) {
331 // check restriction more precisely
332 TString fullname;
333 BuildFullName(fullname, &super);
334 fRestriction = sniffer->CheckRestriction(fullname.Data());
335 if (fRestriction < 0)
336 return kFALSE;
337 }
338
339 fParent = &super;
340 fLevel = super.fLevel;
341 fStore = super.fStore;
342 fSearchPath = super.fSearchPath;
343 fMask = super.fMask & kActions;
344 if (fRestriction == 0)
345 fRestriction = super.fRestriction; // get restriction from parent
346 Bool_t topelement(kFALSE);
347
348 if (fMask & kScan) {
349 // if scanning only fields, ignore all childs
350 if (super.ScanOnlyFields())
351 return kFALSE;
352 // only when doing scan, increment level, used for text formatting
353 fLevel++;
354 } else {
355 if (!fSearchPath)
356 return kFALSE;
357
358 if (strncmp(fSearchPath, fItemName.Data(), fItemName.Length()) != 0)
359 return kFALSE;
360
361 const char *separ = fSearchPath + fItemName.Length();
362
363 Bool_t isslash = kFALSE;
364 while (*separ == '/') {
365 separ++;
366 isslash = kTRUE;
367 }
368
369 if (*separ == 0) {
370 fSearchPath = nullptr;
371 if (fMask & kExpand) {
372 topelement = kTRUE;
374 fHasMore = (fMask & kOnlyFields) == 0;
375 }
376 } else {
377 if (!isslash)
378 return kFALSE;
379 fSearchPath = separ;
380 }
381 }
382
384
385 if (obj_name && (fItemName != obj_name))
386 SetField(item_prop_realname, obj_name);
387
388 if (full_name)
389 SetField("_fullname", full_name);
390
391 if (topelement)
392 SetField(item_prop_rootversion, TString::Format("%d", gROOT->GetVersionCode()), kFALSE);
393
394 if (topelement && sniffer->GetAutoLoad())
396
397 return kTRUE;
398}
399
400// ====================================================================
401
402//////////////////////////////////////////////////////////////////////////
403// //
404// TRootSniffer //
405// //
406// Sniffer of ROOT objects, data provider for THttpServer //
407// Provides methods to scan different structures like folders, //
408// directories, files, trees, collections //
409// Can locate objects (or its data member) per name //
410// Can be extended to application-specific classes //
411// //
412//////////////////////////////////////////////////////////////////////////
413
415
416////////////////////////////////////////////////////////////////////////////////
417/// constructor
418
419TRootSniffer::TRootSniffer(const char *name, const char *objpath)
420 : TNamed(name, "sniffer of root objects"), fObjectsPath(objpath)
421{
423}
424
425////////////////////////////////////////////////////////////////////////////////
426/// destructor
427
429{
430}
431
432////////////////////////////////////////////////////////////////////////////////
433/// set current http arguments, which then used in different process methods
434/// For instance, if user authorized with some user name,
435/// depending from restrictions some objects will be invisible
436/// or user get full access to the element
437
439{
440 fCurrentArg = arg;
443}
444
445////////////////////////////////////////////////////////////////////////////////
446/// Restrict access to the specified location
447///
448/// Hides or provides read-only access to different parts of the hierarchy
449/// Restriction done base on user-name specified with http requests
450/// Options can be specified in URL style (separated with &)
451/// Following parameters can be specified:
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/// Like make command seen by all but can be executed only by admin
458/// sniff->Restrict("/CmdReset","allow=admin");
459/// Or fully hide command from guest account
460/// sniff->Restrict("/CmdRebin","hidden=guest");
461
462void TRootSniffer::Restrict(const char *path, const char *options)
463{
464 const char *rslash = strrchr(path, '/');
465 if (rslash)
466 rslash++;
467 if (!rslash || (*rslash == 0))
468 rslash = path;
469
470 fRestrictions.Add(new TNamed(rslash, TString::Format("%s%s%s", path, "%%%", options).Data()));
471}
472
473////////////////////////////////////////////////////////////////////////////////
474/// When specified, _autoload attribute will be always add
475/// to top element of h.json/h.hml requests
476/// Used to instruct browser automatically load special code
477
478void TRootSniffer::SetAutoLoad(const char *scripts)
479{
480 fAutoLoad = scripts ? scripts : "";
481}
482
483////////////////////////////////////////////////////////////////////////////////
484/// return name of configured autoload scripts (or 0)
485
486const char *TRootSniffer::GetAutoLoad() const
487{
488 return fAutoLoad.Length() > 0 ? fAutoLoad.Data() : nullptr;
489}
490
491////////////////////////////////////////////////////////////////////////////////
492/// Made fast check if item with specified name is in restriction list
493/// If returns true, requires precise check with CheckRestriction() method
494
496{
497 if (!item_name || (*item_name == 0) || !fCurrentArg)
498 return kFALSE;
499
500 return fRestrictions.FindObject(item_name) != nullptr;
501}
502
503////////////////////////////////////////////////////////////////////////////////
504/// return 2 when option match to current user name
505/// return 1 when option==all
506/// return 0 when option does not match user name
507
509{
510 const char *username = fCurrentArg ? fCurrentArg->GetUserName() : nullptr;
511
512 if (!username || !option || (*option == 0))
513 return 0;
514
515 if (strcmp(option, "all") == 0)
516 return 1;
517
518 if (strcmp(username, option) == 0)
519 return 2;
520
521 if (strstr(option, username) == 0)
522 return -1;
523
524 TObjArray *arr = TString(option).Tokenize(",");
525
526 Bool_t find = arr->FindObject(username) != nullptr;
527
528 delete arr;
529
530 return find ? 2 : -1;
531}
532
533////////////////////////////////////////////////////////////////////////////////
534/// Checked if restriction is applied to the item
535/// full_item_name should have full path to the item
536///
537/// Returns -1 - object invisible, cannot be accessed or listed
538/// 0 - no explicit restrictions, use default
539/// 1 - read-only access
540/// 2 - full access
541
542Int_t TRootSniffer::CheckRestriction(const char *full_item_name)
543{
544 if (!full_item_name || (*full_item_name == 0))
545 return 0;
546
547 const char *item_name = strrchr(full_item_name, '/');
548 if (item_name)
549 item_name++;
550 if (!item_name || (*item_name == 0))
551 item_name = full_item_name;
552
553 TString pattern1 = TString("*/") + item_name + "%%%";
554 TString pattern2 = TString(full_item_name) + "%%%";
555
556 const char *options = nullptr;
557 TIter iter(&fRestrictions);
558 TObject *obj;
559
560 while ((obj = iter()) != nullptr) {
561 const char *title = obj->GetTitle();
562
563 if (strstr(title, pattern1.Data()) == title) {
564 options = title + pattern1.Length();
565 break;
566 }
567 if (strstr(title, pattern2.Data()) == title) {
568 options = title + pattern2.Length();
569 break;
570 }
571 }
572
573 if (!options)
574 return 0;
575
576 TUrl url;
577 url.SetOptions(options);
578 url.ParseOptions();
579
580 Int_t can_see =
582
583 Int_t can_access =
585
586 if (can_access > 0)
587 return 2; // first of all, if access enabled, provide it
588 if (can_see < 0)
589 return -1; // if object to be hidden, do it
590
591 const char *methods = url.GetValueFromOptions("allow_method");
592 if (methods)
593 fCurrentAllowedMethods = methods;
594
595 if (can_access < 0)
596 return 1; // read-only access
597
598 return 0; // default behavior
599}
600
601////////////////////////////////////////////////////////////////////////////////
602/// scan object data members
603/// some members like enum or static members will be excluded
604
606{
607 if (!cl || !ptr || rec.Done())
608 return;
609
610 // ensure that real class data (including parents) exists
611 if (!(cl->Property() & kIsAbstract))
612 cl->BuildRealData();
613
614 // scan only real data
615 TObject *obj = nullptr;
616 TIter iter(cl->GetListOfRealData());
617 while ((obj = iter()) != nullptr) {
618 TRealData *rdata = dynamic_cast<TRealData *>(obj);
619 if (!rdata || strchr(rdata->GetName(), '.'))
620 continue;
621
622 TDataMember *member = rdata->GetDataMember();
623 // exclude enum or static variables
624 if (!member || (member->Property() & (kIsStatic | kIsEnum | kIsUnion)))
625 continue;
626 char *member_ptr = ptr + rdata->GetThisOffset();
627
628 if (member->IsaPointer())
629 member_ptr = *((char **)member_ptr);
630
632
633 if (chld.GoInside(rec, member, 0, this)) {
634
635 TClass *mcl = (member->IsBasic() || member->IsSTLContainer()) ? nullptr : gROOT->GetClass(member->GetTypeName());
636
637 Int_t coll_offset = mcl ? mcl->GetBaseClassOffset(TCollection::Class()) : -1;
638 if (coll_offset >= 0) {
639 chld.SetField(item_prop_more, "true", kFALSE);
640 chld.fHasMore = kTRUE;
641 }
642
643 if (chld.SetFoundResult(ptr, cl, member))
644 break;
645
646 const char *title = member->GetTitle();
647 if (title && (strlen(title) != 0))
648 chld.SetField(item_prop_title, title);
649
650 if (member->GetTypeName())
651 chld.SetField(item_prop_typename, member->GetTypeName());
652
653 if (member->GetArrayDim() > 0) {
654 // store array dimensions in form [N1,N2,N3,...]
655 TString dim("[");
656 for (Int_t n = 0; n < member->GetArrayDim(); n++) {
657 if (n > 0)
658 dim.Append(",");
659 dim.Append(TString::Format("%d", member->GetMaxIndex(n)));
660 }
661 dim.Append("]");
663 } else if (member->GetArrayIndex() != 0) {
664 TRealData *idata = cl->GetRealData(member->GetArrayIndex());
665 TDataMember *imember = idata ? idata->GetDataMember() : nullptr;
666 if (imember && (strcmp(imember->GetTrueTypeName(), "int") == 0)) {
667 Int_t arraylen = *((int *)(ptr + idata->GetThisOffset()));
668 chld.SetField(item_prop_arraydim, TString::Format("[%d]", arraylen), kFALSE);
669 }
670 }
671
672 chld.SetRootClass(mcl);
673
674 if (chld.CanExpandItem()) {
675 if (coll_offset >= 0) {
676 // chld.SetField("#members", "true", kFALSE);
677 ScanCollection(chld, (TCollection *)(member_ptr + coll_offset));
678 }
679 }
680
681 if (chld.SetFoundResult(ptr, cl, member))
682 break;
683 }
684 }
685}
686
687////////////////////////////////////////////////////////////////////////////////
688/// scans object properties
689/// here such fields as _autoload or _icon properties depending on class or object name could be assigned
690/// By default properties, coded in the Class title are scanned. Example:
691/// ClassDef(UserClassName, 1) // class comments *SNIFF* _field1=value _field2="string value"
692/// Here *SNIFF* mark is important. After it all expressions like field=value are parsed
693/// One could use double quotes to code string values with spaces.
694/// Fields separated from each other with spaces
695
697{
698 TClass *cl = obj ? obj->IsA() : nullptr;
699
700 const char *pos = strstr(cl ? cl->GetTitle() : "", "*SNIFF*");
701 if (!pos)
702 return;
703
704 pos += 7;
705 while (*pos != 0) {
706 if (*pos == ' ') {
707 pos++;
708 continue;
709 }
710 // first locate identifier
711 const char *pos0 = pos;
712 while ((*pos != 0) && (*pos != '='))
713 pos++;
714 if (*pos == 0)
715 return;
716 TString name(pos0, pos - pos0);
717 pos++;
718 Bool_t quotes = (*pos == '\"');
719 if (quotes)
720 pos++;
721 pos0 = pos;
722 // then value with or without quotes
723 while ((*pos != 0) && (*pos != (quotes ? '\"' : ' ')))
724 pos++;
725 TString value(pos0, pos - pos0);
726 rec.SetField(name, value);
727 if (quotes)
728 pos++;
729 pos++;
730 }
731}
732
733////////////////////////////////////////////////////////////////////////////////
734/// scans key properties
735/// in special cases load objects from the file
736
738{
739 if (strcmp(key->GetClassName(), "TDirectoryFile") == 0) {
740 if (rec.fLevel == 0) {
741 TDirectory *dir = dynamic_cast<TDirectory *>(key->ReadObj());
742 if (dir) {
743 obj = dir;
744 obj_class = dir->IsA();
745 }
746 } else {
747 rec.SetField(item_prop_more, "true", kFALSE);
748 rec.fHasMore = kTRUE;
749 }
750 }
751}
752
753////////////////////////////////////////////////////////////////////////////////
754/// scans object childs (if any)
755/// here one scans collection, branches, trees and so on
756
758{
759 if (obj->InheritsFrom(TFolder::Class())) {
760 ScanCollection(rec, ((TFolder *)obj)->GetListOfFolders());
761 } else if (obj->InheritsFrom(TDirectory::Class())) {
762 TDirectory *dir = (TDirectory *)obj;
763 ScanCollection(rec, dir->GetList(), nullptr, dir->GetListOfKeys());
764 }
765 if (rec.CanExpandItem()) {
766 ScanObjectMembers(rec, obj->IsA(), (char *)obj);
767 }
768}
769
770////////////////////////////////////////////////////////////////////////////////
771/// scan collection content
772
773void TRootSniffer::ScanCollection(TRootSnifferScanRec &rec, TCollection *lst, const char *foldername,
774 TCollection *keys_lst)
775{
776 if ((!lst || (lst->GetSize() == 0)) && (!keys_lst || (keys_lst->GetSize() == 0)))
777 return;
778
779 TRootSnifferScanRec folderrec;
780 if (foldername) {
781 if (!folderrec.GoInside(rec, nullptr, foldername, this))
782 return;
783 }
784
785 TRootSnifferScanRec &master = foldername ? folderrec : rec;
786
787 if (lst) {
788 TIter iter(lst);
789 TObject *next = iter();
790 Bool_t isany = kFALSE;
791
792 while (next) {
793 if (IsItemField(next)) {
794 // special case - in the beginning one could have items for master folder
795 if (!isany && (next->GetName() != nullptr) && ((*(next->GetName()) == '_') || master.ScanOnlyFields()))
796 master.SetField(next->GetName(), next->GetTitle());
797 next = iter();
798 continue;
799 }
800
801 isany = kTRUE;
802 TObject *obj = next;
803
805 if (!chld.GoInside(master, obj, nullptr, this)) {
806 next = iter();
807 continue;
808 }
809
810 if (chld.SetResult(obj, obj->IsA()))
811 return;
812
813 Bool_t has_kind(kFALSE), has_title(kFALSE);
814
815 ScanObjectProperties(chld, obj);
816 // now properties, coded as TNamed objects, placed after object in the hierarchy
817 while ((next = iter()) != nullptr) {
818 if (!IsItemField(next))
819 break;
820 if ((next->GetName() != nullptr) && ((*(next->GetName()) == '_') || chld.ScanOnlyFields())) {
821 // only fields starting with _ are stored
822 chld.SetField(next->GetName(), next->GetTitle());
823 if (strcmp(next->GetName(), item_prop_kind) == 0)
824 has_kind = kTRUE;
825 if (strcmp(next->GetName(), item_prop_title) == 0)
826 has_title = kTRUE;
827 }
828 }
829
830 if (!has_kind)
831 chld.SetRootClass(obj->IsA());
832 if (!has_title && obj->GetTitle())
833 chld.SetField(item_prop_title, obj->GetTitle());
834
835 ScanObjectChilds(chld, obj);
836
837 if (chld.SetResult(obj, obj->IsA()))
838 return;
839 }
840 }
841
842 if (keys_lst) {
843 TIter iter(keys_lst);
844 TObject *kobj = nullptr;
845
846 while ((kobj = iter()) != nullptr) {
847 TKey *key = dynamic_cast<TKey *>(kobj);
848 if (!key)
849 continue;
850 TObject *obj = lst ? lst->FindObject(key->GetName()) : nullptr;
851
852 // even object with the name exists, it should also match with class name
853 if (obj && (strcmp(obj->ClassName(), key->GetClassName()) != 0))
854 obj = nullptr;
855
856 // if object of that name and of that class already in the list, ignore appropriate key
857 if (obj && (master.fMask & TRootSnifferScanRec::kScan))
858 continue;
859
860 Bool_t iskey = kFALSE;
861 // if object not exists, provide key itself for the scan
862 if (!obj) {
863 obj = key;
864 iskey = kTRUE;
865 }
866
868 TString fullname = TString::Format("%s;%d", key->GetName(), key->GetCycle());
869
870 if (chld.GoInside(master, obj, fullname.Data(), this)) {
871
872 if (!chld.IsReadOnly(fReadOnly) && iskey && chld.IsReadyForResult()) {
873 TObject *keyobj = key->ReadObj();
874 if (keyobj)
875 if (chld.SetResult(keyobj, keyobj->IsA()))
876 return;
877 }
878
879 if (chld.SetResult(obj, obj->IsA()))
880 return;
881
882 TClass *obj_class = obj->IsA();
883
884 ScanObjectProperties(chld, obj);
885
886 if (obj->GetTitle())
887 chld.SetField(item_prop_title, obj->GetTitle());
888
889 // special handling of TKey class - in non-readonly mode
890 // sniffer allowed to fetch objects
891 if (!chld.IsReadOnly(fReadOnly) && iskey)
892 ScanKeyProperties(chld, key, obj, obj_class);
893
894 rec.SetRootClass(obj_class);
895
896 ScanObjectChilds(chld, obj);
897
898 // here we should know how many childs are accumulated
899 if (chld.SetResult(obj, obj_class))
900 return;
901 }
902 }
903 }
904}
905
906////////////////////////////////////////////////////////////////////////////////
907/// Create own TFolder structures independent from gROOT
908/// This allows to have many independent TRootSniffer instances
909/// At the same time such sniffer lost access to all global lists and folders
910
912{
913 if (fTopFolder) return;
914
916
917 // this only works with c++14, use ROOT wrapper
918 fTopFolder = std::make_unique<TFolder>("http","Dedicated instance");
919
920 // not sure if we have to add that private folder to global list of cleanups
921
922 // R__LOCKGUARD(gROOTMutex);
923 // gROOT->GetListOfCleanups()->Add(fTopFolder.get());
924
925}
926
927////////////////////////////////////////////////////////////////////////////////
928/// Returns top TFolder instance for the sniffer
929
931{
932 if (fTopFolder) return fTopFolder.get();
933
934 TFolder *topf = gROOT->GetRootFolder();
935
936 if (!topf) {
937 Error("RegisterObject", "Not found top ROOT folder!!!");
938 return nullptr;
939 }
940
941 TFolder *httpfold = dynamic_cast<TFolder *>(topf->FindObject("http"));
942 if (!httpfold) {
943 if (!force)
944 return nullptr;
945 httpfold = topf->AddFolder("http", "ROOT http server");
946 httpfold->SetBit(kCanDelete);
947 // register top folder in list of cleanups
949 gROOT->GetListOfCleanups()->Add(httpfold);
950 }
951
952 return httpfold;
953}
954
955////////////////////////////////////////////////////////////////////////////////
956/// scan complete ROOT objects hierarchy
957/// For the moment it includes objects in gROOT directory
958/// and list of canvases and files
959/// Also all registered objects are included.
960/// One could reimplement this method to provide alternative
961/// scan methods or to extend some collection kinds
962
964{
965 rec.SetField(item_prop_kind, "ROOT.Session");
968
969 // should be on the top while //root/http folder could have properties for itself
970 TFolder *topf = GetTopFolder();
971 if (topf) {
972 rec.SetField(item_prop_title, topf->GetTitle());
973 ScanCollection(rec, topf->GetListOfFolders());
974 }
975
976 if (HasStreamerInfo()) {
978 if (chld.GoInside(rec, nullptr, "StreamerInfo", this)) {
979 chld.SetField(item_prop_kind, "ROOT.TStreamerInfoList");
980 chld.SetField(item_prop_title, "List of streamer infos for binary I/O");
981 chld.SetField(item_prop_hidden, "true", kFALSE);
982 chld.SetField("_after_request", "JSROOT.markAsStreamerInfo");
983 }
984 }
985
986 if (IsScanGlobalDir()) {
987 ScanCollection(rec, gROOT->GetList());
988
989 ScanCollection(rec, gROOT->GetListOfCanvases(), "Canvases");
990
991 ScanCollection(rec, gROOT->GetListOfFiles(), "Files");
992 }
993}
994
995////////////////////////////////////////////////////////////////////////////////
996/// scan ROOT hierarchy with provided store object
997
998void TRootSniffer::ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store,
999 Bool_t only_fields)
1000{
1002 rec.fSearchPath = path;
1003 if (rec.fSearchPath) {
1004 while (*rec.fSearchPath == '/')
1005 rec.fSearchPath++;
1006 if (*rec.fSearchPath == 0)
1007 rec.fSearchPath = nullptr;
1008 }
1009
1010 // if path non-empty, we should find item first and than start scanning
1012 if (only_fields)
1014
1015 rec.fStore = store;
1016
1017 rec.CreateNode(topname);
1018
1019 if (!rec.fSearchPath)
1021
1022 if (!rec.fSearchPath && GetAutoLoad())
1024
1025 ScanRoot(rec);
1026
1027 rec.CloseNode();
1028}
1029
1030////////////////////////////////////////////////////////////////////////////////
1031/// Search element with specified path
1032/// Returns pointer on element
1033/// Optionally one could obtain element class, member description
1034/// and number of childs. When chld!=0, not only element is searched,
1035/// but also number of childs are counted. When member!=0, any object
1036/// will be scanned for its data members (disregard of extra options)
1037
1038void *TRootSniffer::FindInHierarchy(const char *path, TClass **cl, TDataMember **member, Int_t *chld)
1039{
1040 TRootSnifferStore store;
1041
1043 rec.fSearchPath = path;
1045 if (*rec.fSearchPath == '/')
1046 rec.fSearchPath++;
1047 rec.fStore = &store;
1048
1049 ScanRoot(rec);
1050
1051 TDataMember *res_member = store.GetResMember();
1052 TClass *res_cl = store.GetResClass();
1053 void *res = store.GetResPtr();
1054
1055 if (res_member && res_cl && !member) {
1056 res_cl = (res_member->IsBasic() || res_member->IsSTLContainer()) ? nullptr : gROOT->GetClass(res_member->GetTypeName());
1057 TRealData *rdata = res_cl ? res_cl->GetRealData(res_member->GetName()) : nullptr;
1058 if (rdata) {
1059 res = (char *)res + rdata->GetThisOffset();
1060 if (res_member->IsaPointer())
1061 res = *((char **)res);
1062 } else {
1063 res = nullptr; // should never happen
1064 }
1065 }
1066
1067 if (cl)
1068 *cl = res_cl;
1069 if (member)
1070 *member = res_member;
1071 if (chld)
1072 *chld = store.GetResNumChilds();
1073
1074 // remember current restriction
1076
1077 return res;
1078}
1079
1080////////////////////////////////////////////////////////////////////////////////
1081/// Search element in hierarchy, derived from TObject
1082
1084{
1085 TClass *cl = nullptr;
1086
1087 void *obj = FindInHierarchy(path, &cl);
1088
1089 return cl && (cl->GetBaseClassOffset(TObject::Class()) == 0) ? (TObject *)obj : nullptr;
1090}
1091
1092////////////////////////////////////////////////////////////////////////////////
1093/// Get hash function for specified item
1094/// used to detect any changes in the specified object
1095
1097{
1098 TObject *obj = FindTObjectInHierarchy(itemname);
1099
1100 return !obj ? 0 : TString::Hash(obj, obj->IsA()->Size());
1101}
1102
1103////////////////////////////////////////////////////////////////////////////////
1104/// Method verifies if object can be drawn
1105
1107{
1108 TClass *obj_cl = nullptr;
1109 void *res = FindInHierarchy(path, &obj_cl);
1110 return (res != nullptr) && CanDrawClass(obj_cl);
1111}
1112
1113////////////////////////////////////////////////////////////////////////////////
1114/// Method returns true when object has childs or
1115/// one could try to expand item
1116
1118{
1119 TClass *obj_cl = nullptr;
1120 Int_t obj_chld(-1);
1121 void *res = FindInHierarchy(path, &obj_cl, nullptr, &obj_chld);
1122 return res && (obj_chld > 0);
1123}
1124
1125////////////////////////////////////////////////////////////////////////////////
1126/// Produce JSON data for specified item
1127/// For object conversion TBufferJSON is used
1128
1129Bool_t TRootSniffer::ProduceJson(const std::string &path, const std::string &options, std::string &res)
1130{
1131 if (path.empty())
1132 return kFALSE;
1133
1134 const char *path_ = path.c_str();
1135 if (*path_ == '/')
1136 path_++;
1137
1138 TUrl url;
1139 url.SetOptions(options.c_str());
1140 url.ParseOptions();
1141 Int_t compact = -1;
1142 if (url.GetValueFromOptions("compact"))
1143 compact = url.GetIntValueFromOptions("compact");
1144
1145 TClass *obj_cl = nullptr;
1146 TDataMember *member = nullptr;
1147 void *obj_ptr = FindInHierarchy(path_, &obj_cl, &member);
1148 if (!obj_ptr || (!obj_cl && !member))
1149 return kFALSE;
1150
1151 // TODO: implement direct storage into std::string
1152 TString buf = TBufferJSON::ConvertToJSON(obj_ptr, obj_cl, compact >= 0 ? compact : 0, member ? member->GetName() : nullptr);
1153 res = buf.Data();
1154
1155 return !res.empty();
1156}
1157
1158////////////////////////////////////////////////////////////////////////////////
1159/// Execute command marked as _kind=='Command'
1160
1161Bool_t TRootSniffer::ExecuteCmd(const std::string &path, const std::string &options, std::string &res)
1162{
1163 TFolder *parent = nullptr;
1164 TObject *obj = GetItem(path.c_str(), parent, kFALSE, kFALSE);
1165
1166 const char *kind = GetItemField(parent, obj, item_prop_kind);
1167 if ((kind == 0) || (strcmp(kind, "Command") != 0)) {
1168 if (gDebug > 0)
1169 Info("ExecuteCmd", "Entry %s is not a command", path.c_str());
1170 res = "false";
1171 return kTRUE;
1172 }
1173
1174 const char *cmethod = GetItemField(parent, obj, "method");
1175 if (!cmethod || (strlen(cmethod) == 0)) {
1176 if (gDebug > 0)
1177 Info("ExecuteCmd", "Entry %s do not defines method for execution", path.c_str());
1178 res = "false";
1179 return kTRUE;
1180 }
1181
1182 // if read-only specified for the command, it is not allowed for execution
1183 if (fRestrictions.GetLast() >= 0) {
1184 FindInHierarchy(path.c_str()); // one need to call method to check access rights
1185 if (fCurrentRestrict == 1) {
1186 if (gDebug > 0)
1187 Info("ExecuteCmd", "Entry %s not allowed for specified user", path.c_str());
1188 res = "false";
1189 return kTRUE;
1190 }
1191 }
1192
1193 TString method = cmethod;
1194
1195 const char *cnumargs = GetItemField(parent, obj, "_numargs");
1196 Int_t numargs = cnumargs ? TString(cnumargs).Atoi() : 0;
1197 if (numargs > 0) {
1198 TUrl url;
1199 url.SetOptions(options.c_str());
1200 url.ParseOptions();
1201
1202 for (Int_t n = 0; n < numargs; n++) {
1203 TString argname = TString::Format("arg%d", n + 1);
1204 const char *argvalue = url.GetValueFromOptions(argname);
1205 if (!argvalue) {
1206 if (gDebug > 0)
1207 Info("ExecuteCmd", "For command %s argument %s not specified in options %s", path.c_str(), argname.Data(),
1208 options.c_str());
1209 res = "false";
1210 return kTRUE;
1211 }
1212
1213 TString svalue = DecodeUrlOptionValue(argvalue, kTRUE);
1214 argname = TString("%") + argname + TString("%");
1215 method.ReplaceAll(argname, svalue);
1216 }
1217 }
1218
1219 if (gDebug > 0)
1220 Info("ExecuteCmd", "Executing command %s method:%s", path.c_str(), method.Data());
1221
1222 TObject *item_obj = nullptr;
1223 Ssiz_t separ = method.Index("/->");
1224
1225 if (method.Index("this->") == 0) {
1226 // if command name started with this-> means method of sniffer will be executed
1227 item_obj = this;
1228 separ = 3;
1229 } else if (separ != kNPOS) {
1230 item_obj = FindTObjectInHierarchy(TString(method.Data(), separ).Data());
1231 }
1232
1233 if (item_obj) {
1234 method =
1235 TString::Format("((%s*)%lu)->%s", item_obj->ClassName(), (long unsigned)item_obj, method.Data() + separ + 3);
1236 if (gDebug > 2)
1237 Info("ExecuteCmd", "Executing %s", method.Data());
1238 }
1239
1240 Long_t v = gROOT->ProcessLineSync(method.Data());
1241
1242 res = std::to_string(v);
1243
1244 return kTRUE;
1245}
1246
1247////////////////////////////////////////////////////////////////////////////////
1248/// Produce JSON/XML for specified item
1249/// contrary to h.json request, only fields for specified item are stored
1250
1251Bool_t TRootSniffer::ProduceItem(const std::string &path, const std::string &options, std::string &res, Bool_t asjson)
1252{
1253 TString buf; // TODO: implement direct storage into std::string
1254 if (asjson) {
1255 TRootSnifferStoreJson store(buf, options.find("compact") != std::string::npos);
1256 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1257 } else {
1258 TRootSnifferStoreXml store(buf, options.find("compact") != std::string::npos);
1259 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1260 }
1261 res = buf.Data();
1262 return !res.empty();
1263}
1264
1265////////////////////////////////////////////////////////////////////////////////
1266/// Produce XML data for specified item
1267/// For object conversion TBufferXML is used
1268///
1269/// Method implemented only in TRootSnifferFull class
1270
1271Bool_t TRootSniffer::ProduceXml(const std::string &/* path */, const std::string & /* options */, std::string & /* res */)
1272{
1273 return kFALSE;
1274}
1275
1276////////////////////////////////////////////////////////////////////////////////
1277/// method replaces all kind of special symbols, which could appear in URL options
1278
1279TString TRootSniffer::DecodeUrlOptionValue(const char *value, Bool_t remove_quotes)
1280{
1281 if (!value || (strlen(value) == 0))
1282 return TString();
1283
1284 TString res = value;
1285
1286 res.ReplaceAll("%27", "\'");
1287 res.ReplaceAll("%22", "\"");
1288 res.ReplaceAll("%3E", ">");
1289 res.ReplaceAll("%3C", "<");
1290 res.ReplaceAll("%20", " ");
1291 res.ReplaceAll("%5B", "[");
1292 res.ReplaceAll("%5D", "]");
1293 res.ReplaceAll("%3D", "=");
1294
1295 if (remove_quotes && (res.Length() > 1) && ((res[0] == '\'') || (res[0] == '\"')) &&
1296 (res[0] == res[res.Length() - 1])) {
1297 res.Remove(res.Length() - 1);
1298 res.Remove(0, 1);
1299 }
1300
1301 return res;
1302}
1303
1304////////////////////////////////////////////////////////////////////////////////
1305/// Execute command for specified object
1306/// Options include method and extra list of parameters
1307/// sniffer should be not-readonly to allow execution of the commands
1308/// reskind defines kind of result 0 - debug, 1 - json, 2 - binary
1309///
1310/// Method implemented only in TRootSnifferFull class
1311
1312Bool_t TRootSniffer::ProduceExe(const std::string & /*path*/, const std::string & /*options*/, Int_t /*reskind*/,
1313 std::string & /*res*/)
1314{
1315 return kFALSE;
1316}
1317
1318////////////////////////////////////////////////////////////////////////////////
1319/// Process several requests, packing all results into binary or JSON buffer
1320/// Input parameters should be coded in the POST block and has
1321/// individual request relative to current path, separated with '\n' symbol like
1322/// item1/root.bin\n
1323/// item2/exe.bin?method=GetList\n
1324/// item3/exe.bin?method=GetTitle\n
1325/// Request requires 'number' URL option which contains number of requested items
1326///
1327/// In case of binary request output buffer looks like:
1328/// 4bytes length + payload, 4bytes length + payload, ...
1329/// In case of JSON request output is array with results for each item
1330/// multi.json request do not support binary requests for the items
1331
1332Bool_t TRootSniffer::ProduceMulti(const std::string &path, const std::string &options, std::string &str, Bool_t asjson)
1333{
1335 return kFALSE;
1336
1337 const char *args = (const char *)fCurrentArg->GetPostData();
1338 const char *ends = args + fCurrentArg->GetPostDataLength();
1339
1340 TUrl url;
1341 url.SetOptions(options.c_str());
1342
1343 Int_t number = 0;
1344 if (url.GetValueFromOptions("number"))
1345 number = url.GetIntValueFromOptions("number");
1346
1347 // binary buffers required only for binary requests, json output can be produced as is
1348 std::vector<std::string> mem;
1349
1350 if (asjson)
1351 str = "[";
1352
1353 for (Int_t n = 0; n < number; n++) {
1354 const char *next = args;
1355 while ((next < ends) && (*next != '\n'))
1356 next++;
1357 if (next == ends) {
1358 Error("ProduceMulti", "Not enough arguments in POST block");
1359 break;
1360 }
1361
1362 std::string file1(args, next - args);
1363 args = next + 1;
1364
1365 std::string path1, opt1;
1366
1367 // extract options
1368 std::size_t pos = file1.find_first_of('?');
1369 if (pos != std::string::npos) {
1370 opt1 = file1.substr(pos + 1, file1.length() - pos);
1371 file1.resize(pos);
1372 }
1373
1374 // extract extra path
1375 pos = file1.find_last_of('/');
1376 if (pos != std::string::npos) {
1377 path1 = file1.substr(0, pos);
1378 file1.erase(0, pos + 1);
1379 }
1380
1381 if (!path.empty())
1382 path1 = path + "/" + path1;
1383
1384 std::string res1;
1385
1386 // produce next item request
1387 Produce(path1, file1, opt1, res1);
1388
1389 if (asjson) {
1390 if (n > 0)
1391 str.append(", ");
1392 if (res1.empty())
1393 str.append("null");
1394 else
1395 str.append(res1);
1396 } else {
1397 mem.emplace_back(std::move(res1));
1398 }
1399 }
1400
1401 if (asjson) {
1402 str.append("]");
1403 } else {
1404 Int_t length = 0;
1405 for (unsigned n = 0; n < mem.size(); n++)
1406 length += 4 + mem[n].length();
1407 str.resize(length);
1408 char *curr = (char *)str.data();
1409 for (unsigned n = 0; n < mem.size(); n++) {
1410 Long_t l = mem[n].length();
1411 *curr++ = (char)(l & 0xff);
1412 l = l >> 8;
1413 *curr++ = (char)(l & 0xff);
1414 l = l >> 8;
1415 *curr++ = (char)(l & 0xff);
1416 l = l >> 8;
1417 *curr++ = (char)(l & 0xff);
1418 if (!mem[n].empty())
1419 memcpy(curr, mem[n].data(), mem[n].length());
1420 curr += mem[n].length();
1421 }
1422 }
1423
1424 return kTRUE;
1425}
1426
1427////////////////////////////////////////////////////////////////////////////////
1428/// Produce binary data for specified item
1429/// if "zipped" option specified in query, buffer will be compressed
1430///
1431/// Implemented only in TRootSnifferFull class
1432
1433Bool_t TRootSniffer::ProduceBinary(const std::string & /*path*/, const std::string & /*query*/, std::string & /*res*/)
1434{
1435 return kFALSE;
1436}
1437
1438////////////////////////////////////////////////////////////////////////////////
1439/// Method to produce image from specified object
1440///
1441/// Parameters:
1442/// kind - image kind TImage::kPng, TImage::kJpeg, TImage::kGif
1443/// path - path to object
1444/// options - extra options
1445///
1446/// By default, image 300x200 is produced
1447/// In options string one could provide following parameters:
1448/// w - image width
1449/// h - image height
1450/// opt - draw options
1451/// For instance:
1452/// http://localhost:8080/Files/hsimple.root/hpx/get.png?w=500&h=500&opt=lego1
1453///
1454/// Return is memory with produced image
1455/// Memory must be released by user with free(ptr) call
1456///
1457/// Method implemented only in TRootSnifferFull class
1458
1459Bool_t TRootSniffer::ProduceImage(Int_t /*kind*/, const std::string & /*path*/, const std::string & /*options*/, std::string & /*res*/)
1460{
1461 return kFALSE;
1462}
1463
1464////////////////////////////////////////////////////////////////////////////////
1465/// Method produce different kind of data out of object
1466/// Parameter 'path' specifies object or object member
1467/// Supported 'file' (case sensitive):
1468/// "root.bin" - binary data
1469/// "root.png" - png image
1470/// "root.jpeg" - jpeg image
1471/// "root.gif" - gif image
1472/// "root.xml" - xml representation
1473/// "root.json" - json representation
1474/// "exe.json" - method execution with json reply
1475/// "exe.bin" - method execution with binary reply
1476/// "exe.txt" - method execution with debug output
1477/// "cmd.json" - execution of registered commands
1478/// Result returned in std::string - can be binary or text.
1479
1480Bool_t TRootSniffer::Produce(const std::string &path, const std::string &file, const std::string &options, std::string &res)
1481{
1482 if (file.empty())
1483 return kFALSE;
1484
1485 if (file == "root.bin")
1486 return ProduceBinary(path, options, res);
1487
1488 if (file == "root.png")
1489 return ProduceImage(TImage::kPng, path, options, res);
1490
1491 if (file == "root.jpeg")
1492 return ProduceImage(TImage::kJpeg, path, options, res);
1493
1494 if (file == "root.gif")
1495 return ProduceImage(TImage::kGif, path, options, res);
1496
1497 if (file == "exe.bin")
1498 return ProduceExe(path, options, 2, res);
1499
1500 if (file == "root.xml")
1501 return ProduceXml(path, options, res);
1502
1503 if (file == "root.json")
1504 return ProduceJson(path, options, res);
1505
1506 // used for debugging
1507 if (file == "exe.txt")
1508 return ProduceExe(path, options, 0, res);
1509
1510 if (file == "exe.json")
1511 return ProduceExe(path, options, 1, res);
1512
1513 if (file == "cmd.json")
1514 return ExecuteCmd(path, options, res);
1515
1516 if (file == "item.json")
1517 return ProduceItem(path, options, res, kTRUE);
1518
1519 if (file == "item.xml")
1520 return ProduceItem(path, options, res, kFALSE);
1521
1522 if (file == "multi.bin")
1523 return ProduceMulti(path, options, res, kFALSE);
1524
1525 if (file == "multi.json")
1526 return ProduceMulti(path, options, res, kTRUE);
1527
1528 return kFALSE;
1529}
1530
1531////////////////////////////////////////////////////////////////////////////////
1532/// return item from the subfolders structure
1533
1534TObject *TRootSniffer::GetItem(const char *fullname, TFolder *&parent, Bool_t force, Bool_t within_objects)
1535{
1536 TFolder *httpfold = GetTopFolder(force);
1537 if (!httpfold) return nullptr;
1538
1539 parent = httpfold;
1540 TObject *obj = httpfold;
1541
1542 if (!fullname)
1543 return httpfold;
1544
1545 // when full path started not with slash, "Objects" subfolder is appended
1546 TString path = fullname;
1547 if (within_objects && ((path.Length() == 0) || (path[0] != '/')))
1548 path = fObjectsPath + "/" + path;
1549
1550 TString tok;
1551 Ssiz_t from(0);
1552
1553 while (path.Tokenize(tok, from, "/")) {
1554 if (tok.Length() == 0)
1555 continue;
1556
1557 TFolder *fold = dynamic_cast<TFolder *>(obj);
1558 if (!fold)
1559 return nullptr;
1560
1561 TIter iter(fold->GetListOfFolders());
1562 while ((obj = iter()) != nullptr) {
1563 if (IsItemField(obj))
1564 continue;
1565 if (tok.CompareTo(obj->GetName()) == 0)
1566 break;
1567 }
1568
1569 if (!obj) {
1570 if (!force)
1571 return nullptr;
1572 obj = fold->AddFolder(tok, "sub-folder");
1573 obj->SetBit(kCanDelete);
1574 }
1575
1576 parent = fold;
1577 }
1578
1579 return obj;
1580}
1581
1582////////////////////////////////////////////////////////////////////////////////
1583/// creates subfolder where objects can be registered
1584
1585TFolder *TRootSniffer::GetSubFolder(const char *subfolder, Bool_t force)
1586{
1587 TFolder *parent = nullptr;
1588
1589 return dynamic_cast<TFolder *>(GetItem(subfolder, parent, force));
1590}
1591
1592////////////////////////////////////////////////////////////////////////////////
1593/// Register object in subfolder structure
1594/// subfolder parameter can have many levels like:
1595///
1596/// TRootSniffer* sniff = new TRootSniffer("sniff");
1597/// sniff->RegisterObject("my/sub/subfolder", h1);
1598///
1599/// Such objects can be later found in "Objects" folder of sniffer like
1600///
1601/// h1 = sniff->FindTObjectInHierarchy("/Objects/my/sub/subfolder/h1");
1602///
1603/// If subfolder name starts with '/', object will be registered starting from top folder.
1604///
1605/// One could provide additional fields for registered objects
1606/// For instance, setting "_more" field to true let browser
1607/// explore objects members. For instance:
1608///
1609/// TEvent* ev = new TEvent("ev");
1610/// sniff->RegisterObject("Events", ev);
1611/// sniff->SetItemField("Events/ev", "_more", "true");
1612
1613Bool_t TRootSniffer::RegisterObject(const char *subfolder, TObject *obj)
1614{
1615 TFolder *f = GetSubFolder(subfolder, kTRUE);
1616 if (!f)
1617 return kFALSE;
1618
1619 // If object will be destroyed, it will be removed from the folders automatically
1620 obj->SetBit(kMustCleanup);
1621
1622 f->Add(obj);
1623
1624 return kTRUE;
1625}
1626
1627////////////////////////////////////////////////////////////////////////////////
1628/// unregister (remove) object from folders structures
1629/// folder itself will remain even when it will be empty
1630
1632{
1633 if (!obj)
1634 return kTRUE;
1635
1636 TFolder *topf = GetTopFolder();
1637
1638 if (!topf) {
1639 Error("UnregisterObject", "Not found top folder");
1640 return kFALSE;
1641 }
1642
1643 // TODO - probably we should remove all set properties as well
1644 topf->RecursiveRemove(obj);
1645
1646 return kTRUE;
1647}
1648
1649////////////////////////////////////////////////////////////////////////////////
1650/// create item element
1651
1652Bool_t TRootSniffer::CreateItem(const char *fullname, const char *title)
1653{
1654 TFolder *f = GetSubFolder(fullname, kTRUE);
1655 if (!f)
1656 return kFALSE;
1657
1658 if (title)
1659 f->SetTitle(title);
1660
1661 return kTRUE;
1662}
1663
1664////////////////////////////////////////////////////////////////////////////////
1665/// return true when object is TNamed with kItemField bit set
1666/// such objects used to keep field values for item
1667
1669{
1670 return (obj != nullptr) && (obj->IsA() == TNamed::Class()) && obj->TestBit(kItemField);
1671}
1672
1673////////////////////////////////////////////////////////////////////////////////
1674/// set or get field for the child
1675/// each field coded as TNamed object, placed after chld in the parent hierarchy
1676
1677Bool_t TRootSniffer::AccessField(TFolder *parent, TObject *chld, const char *name, const char *value, TNamed **only_get)
1678{
1679 if (!parent)
1680 return kFALSE;
1681
1682 if (!chld) {
1683 Info("AccessField", "Should be special case for top folder, support later");
1684 return kFALSE;
1685 }
1686
1687 TIter iter(parent->GetListOfFolders());
1688
1689 TObject *obj = nullptr;
1690 Bool_t find(kFALSE), last_find(kFALSE);
1691 // this is special case of top folder - fields are on very top
1692 if (parent == chld) {
1693 last_find = find = kTRUE;
1694 }
1695 TNamed *curr = nullptr;
1696 while ((obj = iter()) != nullptr) {
1697 if (IsItemField(obj)) {
1698 if (last_find && obj->GetName() && !strcmp(name, obj->GetName()))
1699 curr = (TNamed *)obj;
1700 } else {
1701 last_find = (obj == chld);
1702 if (last_find)
1703 find = kTRUE;
1704 if (find && !last_find)
1705 break; // no need to continue
1706 }
1707 }
1708
1709 // object must be in childs list
1710 if (!find)
1711 return kFALSE;
1712
1713 if (only_get) {
1714 *only_get = curr;
1715 return curr != nullptr;
1716 }
1717
1718 if (curr) {
1719 if (value) {
1720 curr->SetTitle(value);
1721 } else {
1722 parent->Remove(curr);
1723 delete curr;
1724 }
1725 return kTRUE;
1726 }
1727
1728 curr = new TNamed(name, value);
1729 curr->SetBit(kItemField);
1730
1731 if (last_find) {
1732 // object is on last place, therefore just add property
1733 parent->Add(curr);
1734 return kTRUE;
1735 }
1736
1737 // only here we do dynamic cast to the TList to use AddAfter
1738 TList *lst = dynamic_cast<TList *>(parent->GetListOfFolders());
1739 if (!lst) {
1740 Error("AccessField", "Fail cast to TList");
1741 return kFALSE;
1742 }
1743
1744 if (parent == chld)
1745 lst->AddFirst(curr);
1746 else
1747 lst->AddAfter(chld, curr);
1748
1749 return kTRUE;
1750}
1751
1752////////////////////////////////////////////////////////////////////////////////
1753/// set field for specified item
1754
1755Bool_t TRootSniffer::SetItemField(const char *fullname, const char *name, const char *value)
1756{
1757 if (!fullname || !name)
1758 return kFALSE;
1759
1760 TFolder *parent = nullptr;
1761 TObject *obj = GetItem(fullname, parent);
1762
1763 if (!parent || !obj)
1764 return kFALSE;
1765
1766 if (strcmp(name, item_prop_title) == 0) {
1767 TNamed *n = dynamic_cast<TNamed *>(obj);
1768 if (n) {
1769 n->SetTitle(value);
1770 return kTRUE;
1771 }
1772 }
1773
1774 return AccessField(parent, obj, name, value);
1775}
1776
1777////////////////////////////////////////////////////////////////////////////////
1778/// return field for specified item
1779
1780const char *TRootSniffer::GetItemField(TFolder *parent, TObject *obj, const char *name)
1781{
1782 if (!parent || !obj || !name)
1783 return nullptr;
1784
1785 TNamed *field = nullptr;
1786
1787 if (!AccessField(parent, obj, name, nullptr, &field))
1788 return nullptr;
1789
1790 return field ? field->GetTitle() : nullptr;
1791}
1792
1793////////////////////////////////////////////////////////////////////////////////
1794/// return field for specified item
1795
1796const char *TRootSniffer::GetItemField(const char *fullname, const char *name)
1797{
1798 if (!fullname)
1799 return nullptr;
1800
1801 TFolder *parent = nullptr;
1802 TObject *obj = GetItem(fullname, parent);
1803
1804 return GetItemField(parent, obj, name);
1805}
1806
1807////////////////////////////////////////////////////////////////////////////////
1808/// Register command which can be executed from web interface
1809///
1810/// As method one typically specifies string, which is executed with
1811/// gROOT->ProcessLine() method. For instance
1812/// serv->RegisterCommand("Invoke","InvokeFunction()");
1813///
1814/// Or one could specify any method of the object which is already registered
1815/// to the server. For instance:
1816/// serv->Register("/", hpx);
1817/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
1818/// Here symbols '/->' separates item name from method to be executed
1819///
1820/// One could specify additional arguments in the command with
1821/// syntax like %arg1%, %arg2% and so on. For example:
1822/// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
1823/// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
1824/// Such parameter(s) will be requested when command clicked in the browser.
1825///
1826/// Once command is registered, one could specify icon which will appear in the browser:
1827/// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
1828///
1829/// One also can set extra property '_fastcmd', that command appear as
1830/// tool button on the top of the browser tree:
1831/// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
1832/// Or it is equivalent to specifying extra argument when register command:
1833/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
1834
1835Bool_t TRootSniffer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
1836{
1837 CreateItem(cmdname, Form("command %s", method));
1838 SetItemField(cmdname, "_kind", "Command");
1839 if (icon) {
1840 if (strncmp(icon, "button;", 7) == 0) {
1841 SetItemField(cmdname, "_fastcmd", "true");
1842 icon += 7;
1843 }
1844 if (*icon != 0)
1845 SetItemField(cmdname, "_icon", icon);
1846 }
1847 SetItemField(cmdname, "method", method);
1848 Int_t numargs = 0;
1849 do {
1850 TString nextname = TString::Format("%sarg%d%s", "%", numargs + 1, "%");
1851 if (strstr(method, nextname.Data()) == nullptr)
1852 break;
1853 numargs++;
1854 } while (numargs < 100);
1855 if (numargs > 0)
1856 SetItemField(cmdname, "_numargs", TString::Format("%d", numargs));
1857
1858 return kTRUE;
1859}
#define f(i)
Definition RSha256.hxx:104
#define ROOT_VERSION_CODE
Definition RVersion.h:21
const Ssiz_t kNPOS
Definition RtypesCore.h:115
const Bool_t kFALSE
Definition RtypesCore.h:92
unsigned long ULong_t
Definition RtypesCore.h:55
long Long_t
Definition RtypesCore.h:54
bool Bool_t
Definition RtypesCore.h:63
const Bool_t kTRUE
Definition RtypesCore.h:91
#define ClassImp(name)
Definition Rtypes.h:364
@ kIsEnum
Definition TDictionary.h:68
@ kIsAbstract
Definition TDictionary.h:71
@ kIsStatic
Definition TDictionary.h:80
@ kIsUnion
Definition TDictionary.h:67
char name[80]
Definition TGX11.cxx:110
Int_t gDebug
Definition TROOT.cxx:590
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:406
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,...)
#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:80
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2020
TList * GetListOfRealData() const
Definition TClass.h:450
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition TClass.cxx:2780
Long_t Property() const
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6063
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition TClass.cxx:3480
Collection abstract base class.
Definition TCollection.h:63
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
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 full type description of data member, e,g.: "class TDirectory*".
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 type of data member, e,g.: "class TDirectory*" -> "TDirectory".
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Describe directory structure in memory.
Definition TDirectory.h:45
virtual TList * GetList() const
Definition TDirectory.h:176
virtual TList * GetListOfKeys() const
Definition TDirectory.h:177
A TFolder object is a collection of objects and folders.
Definition TFolder.h:30
TFolder * AddFolder(const char *name, const char *title, TCollection *collection=0)
Create a new folder and add it to the list of folders of this folder, return a pointer to the created...
Definition TFolder.cxx:188
TCollection * GetListOfFolders() const
Definition TFolder.h:55
virtual void Add(TObject *obj)
Add object to this folder. obj must be a TObject or a TFolder.
Definition TFolder.cxx:172
virtual TObject * FindObject(const char *name) const
Search object identified by name in the tree of folders inside this folder.
Definition TFolder.cxx:312
virtual void RecursiveRemove(TObject *obj)
Recursively remove object from a folder.
Definition TFolder.cxx:460
virtual void Remove(TObject *obj)
Remove object from this folder. obj must be a TObject or a TFolder.
Definition TFolder.cxx:468
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
@ kPng
Definition TImage.h:40
@ kJpeg
Definition TImage.h:41
@ kGif
Definition TImage.h:48
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
virtual const char * GetClassName() const
Definition TKey.h:76
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:750
A doubly linked list.
Definition TList.h:44
virtual void Add(TObject *obj)
Definition TList.h:87
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
Definition TList.cxx:100
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition TList.cxx:578
virtual void AddAfter(const TObject *after, TObject *obj)
Insert object after object after in the list.
Definition TList.cxx:250
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
TNamed()
Definition TNamed.h:36
virtual const char * GetTitle() const
Returns title of object.
Definition TNamed.h:48
virtual const char * GetName() const
Returns name of object.
Definition TNamed.h:47
An array of TObjects.
Definition TObjArray.h:37
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:37
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:359
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:187
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:130
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:696
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:445
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:893
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:403
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:58
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:60
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:867
The TRealData class manages the effective list of all data members for a given class.
Definition TRealData.h:30
TDataMember * GetDataMember() const
Definition TRealData.h:53
virtual const char * GetName() const
Returns name of object.
Definition TRealData.h:52
Long_t GetThisOffset() const
Definition TRealData.h:55
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
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.
@ 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
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)
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.
void SetCurrentCallArg(THttpCallArg *arg)
set current http arguments, which then used in different process methods For instance,...
TList fRestrictions
! list of restrictions for different locations
Bool_t RegisterObject(const char *subfolder, TObject *obj)
Register object in subfolder structure subfolder parameter can have many levels like:
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 folder itself will remain even when it will be emp...
virtual void ScanKeyProperties(TRootSnifferScanRec &rec, TKey *key, TObject *&obj, TClass *&obj_class)
scans key 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 Parameter 'path' specifies object or object membe...
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 Options include method and extra list of parameters sniffer shou...
virtual Bool_t ProduceXml(const std::string &path, const std::string &options, std::string &res)
Produce XML data for specified item For object conversion TBufferXML is used.
TString DecodeUrlOptionValue(const char *value, Bool_t remove_quotes=kTRUE)
method replaces all kind of special symbols, which could appear in URL options
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 contrary to h.json request, only fields for specified item are st...
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.
Bool_t IsItemField(TObject *obj) const
return true when object is TNamed with kItemField bit set such objects used to keep field values for ...
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 if "zipped" option specified in query, buffer will be compress...
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 each field coded as TNamed object, placed after chld in the parent hie...
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 Input parameters should be c...
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:136
Ssiz_t Length() const
Definition TString.h:410
int CompareTo(const char *cs, ECaseCompare cmp=kExact) const
Compare a string to char *cs2.
Definition TString.cxx:438
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:1941
const char * Data() const
Definition TString.h:369
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:692
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2217
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition TString.cxx:658
TString & Remove(Ssiz_t pos)
Definition TString.h:673
TString & Append(const char *cs)
Definition TString.h:564
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:2331
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2309
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:639
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:659
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:671
void SetOptions(const char *opt)
Definition TUrl.h:87
void ParseOptions() const
Parse URL options into a key/value map.
Definition TUrl.cxx:625
const Int_t n
Definition legend1.C:16
Definition file.py:1
TCanvas * slash()
Definition slash.C:1
auto * l
Definition textangle.C:4