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
32#include <stdlib.h>
33#include <memory>
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 } else if (rec.CanExpandItem()) {
765 ScanObjectMembers(rec, obj->IsA(), (char *)obj);
766 }
767}
768
769////////////////////////////////////////////////////////////////////////////////
770/// scan collection content
771
772void TRootSniffer::ScanCollection(TRootSnifferScanRec &rec, TCollection *lst, const char *foldername,
773 TCollection *keys_lst)
774{
775 if ((!lst || (lst->GetSize() == 0)) && (!keys_lst || (keys_lst->GetSize() == 0)))
776 return;
777
778 TRootSnifferScanRec folderrec;
779 if (foldername) {
780 if (!folderrec.GoInside(rec, nullptr, foldername, this))
781 return;
782 }
783
784 TRootSnifferScanRec &master = foldername ? folderrec : rec;
785
786 if (lst) {
787 TIter iter(lst);
788 TObject *next = iter();
789 Bool_t isany = kFALSE;
790
791 while (next) {
792 if (IsItemField(next)) {
793 // special case - in the beginning one could have items for master folder
794 if (!isany && (next->GetName() != nullptr) && ((*(next->GetName()) == '_') || master.ScanOnlyFields()))
795 master.SetField(next->GetName(), next->GetTitle());
796 next = iter();
797 continue;
798 }
799
800 isany = kTRUE;
801 TObject *obj = next;
802
804 if (!chld.GoInside(master, obj, nullptr, this)) {
805 next = iter();
806 continue;
807 }
808
809 if (chld.SetResult(obj, obj->IsA()))
810 return;
811
812 Bool_t has_kind(kFALSE), has_title(kFALSE);
813
814 ScanObjectProperties(chld, obj);
815 // now properties, coded as TNamed objects, placed after object in the hierarchy
816 while ((next = iter()) != nullptr) {
817 if (!IsItemField(next))
818 break;
819 if ((next->GetName() != nullptr) && ((*(next->GetName()) == '_') || chld.ScanOnlyFields())) {
820 // only fields starting with _ are stored
821 chld.SetField(next->GetName(), next->GetTitle());
822 if (strcmp(next->GetName(), item_prop_kind) == 0)
823 has_kind = kTRUE;
824 if (strcmp(next->GetName(), item_prop_title) == 0)
825 has_title = kTRUE;
826 }
827 }
828
829 if (!has_kind)
830 chld.SetRootClass(obj->IsA());
831 if (!has_title && obj->GetTitle())
832 chld.SetField(item_prop_title, obj->GetTitle());
833
834 ScanObjectChilds(chld, obj);
835
836 if (chld.SetResult(obj, obj->IsA()))
837 return;
838 }
839 }
840
841 if (keys_lst) {
842 TIter iter(keys_lst);
843 TObject *kobj = nullptr;
844
845 while ((kobj = iter()) != nullptr) {
846 TKey *key = dynamic_cast<TKey *>(kobj);
847 if (!key)
848 continue;
849 TObject *obj = lst ? lst->FindObject(key->GetName()) : nullptr;
850
851 // even object with the name exists, it should also match with class name
852 if (obj && (strcmp(obj->ClassName(), key->GetClassName()) != 0))
853 obj = nullptr;
854
855 // if object of that name and of that class already in the list, ignore appropriate key
856 if (obj && (master.fMask & TRootSnifferScanRec::kScan))
857 continue;
858
859 Bool_t iskey = kFALSE;
860 // if object not exists, provide key itself for the scan
861 if (!obj) {
862 obj = key;
863 iskey = kTRUE;
864 }
865
867 TString fullname = TString::Format("%s;%d", key->GetName(), key->GetCycle());
868
869 if (chld.GoInside(master, obj, fullname.Data(), this)) {
870
871 if (!chld.IsReadOnly(fReadOnly) && iskey && chld.IsReadyForResult()) {
872 TObject *keyobj = key->ReadObj();
873 if (keyobj)
874 if (chld.SetResult(keyobj, keyobj->IsA()))
875 return;
876 }
877
878 if (chld.SetResult(obj, obj->IsA()))
879 return;
880
881 TClass *obj_class = obj->IsA();
882
883 ScanObjectProperties(chld, obj);
884
885 if (obj->GetTitle())
886 chld.SetField(item_prop_title, obj->GetTitle());
887
888 // special handling of TKey class - in non-readonly mode
889 // sniffer allowed to fetch objects
890 if (!chld.IsReadOnly(fReadOnly) && iskey)
891 ScanKeyProperties(chld, key, obj, obj_class);
892
893 rec.SetRootClass(obj_class);
894
895 ScanObjectChilds(chld, obj);
896
897 // here we should know how many childs are accumulated
898 if (chld.SetResult(obj, obj_class))
899 return;
900 }
901 }
902 }
903}
904
905////////////////////////////////////////////////////////////////////////////////
906/// Create own TFolder structures independent from gROOT
907/// This allows to have many independent TRootSniffer instances
908/// At the same time such sniffer lost access to all global lists and folders
909
911{
912 if (fTopFolder) return;
913
915
916 // this only works with c++14, use ROOT wrapper
917 fTopFolder = std::make_unique<TFolder>("http","Dedicated instance");
918
919 // not sure if we have to add that private folder to global list of cleanups
920
921 // R__LOCKGUARD(gROOTMutex);
922 // gROOT->GetListOfCleanups()->Add(fTopFolder.get());
923
924}
925
926////////////////////////////////////////////////////////////////////////////////
927/// Returns top TFolder instance for the sniffer
928
930{
931 if (fTopFolder) return fTopFolder.get();
932
933 TFolder *topf = gROOT->GetRootFolder();
934
935 if (!topf) {
936 Error("RegisterObject", "Not found top ROOT folder!!!");
937 return nullptr;
938 }
939
940 TFolder *httpfold = dynamic_cast<TFolder *>(topf->FindObject("http"));
941 if (!httpfold) {
942 if (!force)
943 return nullptr;
944 httpfold = topf->AddFolder("http", "ROOT http server");
945 httpfold->SetBit(kCanDelete);
946 // register top folder in list of cleanups
948 gROOT->GetListOfCleanups()->Add(httpfold);
949 }
950
951 return httpfold;
952}
953
954////////////////////////////////////////////////////////////////////////////////
955/// scan complete ROOT objects hierarchy
956/// For the moment it includes objects in gROOT directory
957/// and list of canvases and files
958/// Also all registered objects are included.
959/// One could reimplement this method to provide alternative
960/// scan methods or to extend some collection kinds
961
963{
964 rec.SetField(item_prop_kind, "ROOT.Session");
967
968 // should be on the top while //root/http folder could have properties for itself
969 TFolder *topf = GetTopFolder();
970 if (topf) {
971 rec.SetField(item_prop_title, topf->GetTitle());
972 ScanCollection(rec, topf->GetListOfFolders());
973 }
974
975 if (HasStreamerInfo()) {
977 if (chld.GoInside(rec, nullptr, "StreamerInfo", this)) {
978 chld.SetField(item_prop_kind, "ROOT.TStreamerInfoList");
979 chld.SetField(item_prop_title, "List of streamer infos for binary I/O");
980 chld.SetField(item_prop_hidden, "true", kFALSE);
981 chld.SetField("_after_request", "JSROOT.markAsStreamerInfo");
982 }
983 }
984
985 if (IsScanGlobalDir()) {
986 ScanCollection(rec, gROOT->GetList());
987
988 ScanCollection(rec, gROOT->GetListOfCanvases(), "Canvases");
989
990 ScanCollection(rec, gROOT->GetListOfFiles(), "Files");
991 }
992}
993
994////////////////////////////////////////////////////////////////////////////////
995/// scan ROOT hierarchy with provided store object
996
997void TRootSniffer::ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store,
998 Bool_t only_fields)
999{
1001 rec.fSearchPath = path;
1002 if (rec.fSearchPath) {
1003 while (*rec.fSearchPath == '/')
1004 rec.fSearchPath++;
1005 if (*rec.fSearchPath == 0)
1006 rec.fSearchPath = nullptr;
1007 }
1008
1009 // if path non-empty, we should find item first and than start scanning
1011 if (only_fields)
1013
1014 rec.fStore = store;
1015
1016 rec.CreateNode(topname);
1017
1018 if (!rec.fSearchPath)
1020
1021 if (!rec.fSearchPath && GetAutoLoad())
1023
1024 ScanRoot(rec);
1025
1026 rec.CloseNode();
1027}
1028
1029////////////////////////////////////////////////////////////////////////////////
1030/// Search element with specified path
1031/// Returns pointer on element
1032/// Optionally one could obtain element class, member description
1033/// and number of childs. When chld!=0, not only element is searched,
1034/// but also number of childs are counted. When member!=0, any object
1035/// will be scanned for its data members (disregard of extra options)
1036
1037void *TRootSniffer::FindInHierarchy(const char *path, TClass **cl, TDataMember **member, Int_t *chld)
1038{
1039 TRootSnifferStore store;
1040
1042 rec.fSearchPath = path;
1044 if (*rec.fSearchPath == '/')
1045 rec.fSearchPath++;
1046 rec.fStore = &store;
1047
1048 ScanRoot(rec);
1049
1050 TDataMember *res_member = store.GetResMember();
1051 TClass *res_cl = store.GetResClass();
1052 void *res = store.GetResPtr();
1053
1054 if (res_member && res_cl && !member) {
1055 res_cl = (res_member->IsBasic() || res_member->IsSTLContainer()) ? nullptr : gROOT->GetClass(res_member->GetTypeName());
1056 TRealData *rdata = res_cl ? res_cl->GetRealData(res_member->GetName()) : nullptr;
1057 if (rdata) {
1058 res = (char *)res + rdata->GetThisOffset();
1059 if (res_member->IsaPointer())
1060 res = *((char **)res);
1061 } else {
1062 res = nullptr; // should never happen
1063 }
1064 }
1065
1066 if (cl)
1067 *cl = res_cl;
1068 if (member)
1069 *member = res_member;
1070 if (chld)
1071 *chld = store.GetResNumChilds();
1072
1073 // remember current restriction
1075
1076 return res;
1077}
1078
1079////////////////////////////////////////////////////////////////////////////////
1080/// Search element in hierarchy, derived from TObject
1081
1083{
1084 TClass *cl = nullptr;
1085
1086 void *obj = FindInHierarchy(path, &cl);
1087
1088 return cl && (cl->GetBaseClassOffset(TObject::Class()) == 0) ? (TObject *)obj : nullptr;
1089}
1090
1091////////////////////////////////////////////////////////////////////////////////
1092/// Get hash function for specified item
1093/// used to detect any changes in the specified object
1094
1096{
1097 TObject *obj = FindTObjectInHierarchy(itemname);
1098
1099 return !obj ? 0 : TString::Hash(obj, obj->IsA()->Size());
1100}
1101
1102////////////////////////////////////////////////////////////////////////////////
1103/// Method verifies if object can be drawn
1104
1106{
1107 TClass *obj_cl = nullptr;
1108 void *res = FindInHierarchy(path, &obj_cl);
1109 return (res != nullptr) && CanDrawClass(obj_cl);
1110}
1111
1112////////////////////////////////////////////////////////////////////////////////
1113/// Method returns true when object has childs or
1114/// one could try to expand item
1115
1117{
1118 TClass *obj_cl = nullptr;
1119 Int_t obj_chld(-1);
1120 void *res = FindInHierarchy(path, &obj_cl, nullptr, &obj_chld);
1121 return res && (obj_chld > 0);
1122}
1123
1124////////////////////////////////////////////////////////////////////////////////
1125/// Produce JSON data for specified item
1126/// For object conversion TBufferJSON is used
1127
1128Bool_t TRootSniffer::ProduceJson(const std::string &path, const std::string &options, std::string &res)
1129{
1130 if (path.empty())
1131 return kFALSE;
1132
1133 const char *path_ = path.c_str();
1134 if (*path_ == '/')
1135 path_++;
1136
1137 TUrl url;
1138 url.SetOptions(options.c_str());
1139 url.ParseOptions();
1140 Int_t compact = -1;
1141 if (url.GetValueFromOptions("compact"))
1142 compact = url.GetIntValueFromOptions("compact");
1143
1144 TClass *obj_cl = nullptr;
1145 TDataMember *member = nullptr;
1146 void *obj_ptr = FindInHierarchy(path_, &obj_cl, &member);
1147 if (!obj_ptr || (!obj_cl && !member))
1148 return kFALSE;
1149
1150 // TODO: implement direct storage into std::string
1151 TString buf = TBufferJSON::ConvertToJSON(obj_ptr, obj_cl, compact >= 0 ? compact : 0, member ? member->GetName() : nullptr);
1152 res = buf.Data();
1153
1154 return !res.empty();
1155}
1156
1157////////////////////////////////////////////////////////////////////////////////
1158/// Execute command marked as _kind=='Command'
1159
1160Bool_t TRootSniffer::ExecuteCmd(const std::string &path, const std::string &options, std::string &res)
1161{
1162 TFolder *parent = nullptr;
1163 TObject *obj = GetItem(path.c_str(), parent, kFALSE, kFALSE);
1164
1165 const char *kind = GetItemField(parent, obj, item_prop_kind);
1166 if ((kind == 0) || (strcmp(kind, "Command") != 0)) {
1167 if (gDebug > 0)
1168 Info("ExecuteCmd", "Entry %s is not a command", path.c_str());
1169 res = "false";
1170 return kTRUE;
1171 }
1172
1173 const char *cmethod = GetItemField(parent, obj, "method");
1174 if (!cmethod || (strlen(cmethod) == 0)) {
1175 if (gDebug > 0)
1176 Info("ExecuteCmd", "Entry %s do not defines method for execution", path.c_str());
1177 res = "false";
1178 return kTRUE;
1179 }
1180
1181 // if read-only specified for the command, it is not allowed for execution
1182 if (fRestrictions.GetLast() >= 0) {
1183 FindInHierarchy(path.c_str()); // one need to call method to check access rights
1184 if (fCurrentRestrict == 1) {
1185 if (gDebug > 0)
1186 Info("ExecuteCmd", "Entry %s not allowed for specified user", path.c_str());
1187 res = "false";
1188 return kTRUE;
1189 }
1190 }
1191
1192 TString method = cmethod;
1193
1194 const char *cnumargs = GetItemField(parent, obj, "_numargs");
1195 Int_t numargs = cnumargs ? TString(cnumargs).Atoi() : 0;
1196 if (numargs > 0) {
1197 TUrl url;
1198 url.SetOptions(options.c_str());
1199 url.ParseOptions();
1200
1201 for (Int_t n = 0; n < numargs; n++) {
1202 TString argname = TString::Format("arg%d", n + 1);
1203 const char *argvalue = url.GetValueFromOptions(argname);
1204 if (!argvalue) {
1205 if (gDebug > 0)
1206 Info("ExecuteCmd", "For command %s argument %s not specified in options %s", path.c_str(), argname.Data(),
1207 options.c_str());
1208 res = "false";
1209 return kTRUE;
1210 }
1211
1212 TString svalue = DecodeUrlOptionValue(argvalue, kTRUE);
1213 argname = TString("%") + argname + TString("%");
1214 method.ReplaceAll(argname, svalue);
1215 }
1216 }
1217
1218 if (gDebug > 0)
1219 Info("ExecuteCmd", "Executing command %s method:%s", path.c_str(), method.Data());
1220
1221 TObject *item_obj = nullptr;
1222 Ssiz_t separ = method.Index("/->");
1223
1224 if (method.Index("this->") == 0) {
1225 // if command name started with this-> means method of sniffer will be executed
1226 item_obj = this;
1227 separ = 3;
1228 } else if (separ != kNPOS) {
1229 item_obj = FindTObjectInHierarchy(TString(method.Data(), separ).Data());
1230 }
1231
1232 if (item_obj) {
1233 method =
1234 TString::Format("((%s*)%zu)->%s", item_obj->ClassName(), (size_t)item_obj, method.Data() + separ + 3);
1235 if (gDebug > 2)
1236 Info("ExecuteCmd", "Executing %s", method.Data());
1237 }
1238
1239 Long_t v = gROOT->ProcessLineSync(method.Data());
1240
1241 res = std::to_string(v);
1242
1243 return kTRUE;
1244}
1245
1246////////////////////////////////////////////////////////////////////////////////
1247/// Produce JSON/XML for specified item
1248/// contrary to h.json request, only fields for specified item are stored
1249
1250Bool_t TRootSniffer::ProduceItem(const std::string &path, const std::string &options, std::string &res, Bool_t asjson)
1251{
1252 TString buf; // TODO: implement direct storage into std::string
1253 if (asjson) {
1254 TRootSnifferStoreJson store(buf, options.find("compact") != std::string::npos);
1255 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1256 } else {
1257 TRootSnifferStoreXml store(buf, options.find("compact") != std::string::npos);
1258 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1259 }
1260 res = buf.Data();
1261 return !res.empty();
1262}
1263
1264////////////////////////////////////////////////////////////////////////////////
1265/// Produce XML data for specified item
1266/// For object conversion TBufferXML is used
1267///
1268/// Method implemented only in TRootSnifferFull class
1269
1270Bool_t TRootSniffer::ProduceXml(const std::string &/* path */, const std::string & /* options */, std::string & /* res */)
1271{
1272 return kFALSE;
1273}
1274
1275////////////////////////////////////////////////////////////////////////////////
1276/// method replaces all kind of special symbols, which could appear in URL options
1277
1278TString TRootSniffer::DecodeUrlOptionValue(const char *value, Bool_t remove_quotes)
1279{
1280 if (!value || (strlen(value) == 0))
1281 return TString();
1282
1283 TString res = value;
1284
1285 res.ReplaceAll("%27", "\'");
1286 res.ReplaceAll("%22", "\"");
1287 res.ReplaceAll("%3E", ">");
1288 res.ReplaceAll("%3C", "<");
1289 res.ReplaceAll("%20", " ");
1290 res.ReplaceAll("%5B", "[");
1291 res.ReplaceAll("%5D", "]");
1292 res.ReplaceAll("%3D", "=");
1293
1294 if (remove_quotes && (res.Length() > 1) && ((res[0] == '\'') || (res[0] == '\"')) &&
1295 (res[0] == res[res.Length() - 1])) {
1296 res.Remove(res.Length() - 1);
1297 res.Remove(0, 1);
1298 }
1299
1300 return res;
1301}
1302
1303////////////////////////////////////////////////////////////////////////////////
1304/// Execute command for specified object
1305/// Options include method and extra list of parameters
1306/// sniffer should be not-readonly to allow execution of the commands
1307/// reskind defines kind of result 0 - debug, 1 - json, 2 - binary
1308///
1309/// Method implemented only in TRootSnifferFull class
1310
1311Bool_t TRootSniffer::ProduceExe(const std::string & /*path*/, const std::string & /*options*/, Int_t /*reskind*/,
1312 std::string & /*res*/)
1313{
1314 return kFALSE;
1315}
1316
1317////////////////////////////////////////////////////////////////////////////////
1318/// Process several requests, packing all results into binary or JSON buffer
1319/// Input parameters should be coded in the POST block and has
1320/// individual request relative to current path, separated with '\n' symbol like
1321/// item1/root.bin\n
1322/// item2/exe.bin?method=GetList\n
1323/// item3/exe.bin?method=GetTitle\n
1324/// Request requires 'number' URL option which contains number of requested items
1325///
1326/// In case of binary request output buffer looks like:
1327/// 4bytes length + payload, 4bytes length + payload, ...
1328/// In case of JSON request output is array with results for each item
1329/// multi.json request do not support binary requests for the items
1330
1331Bool_t TRootSniffer::ProduceMulti(const std::string &path, const std::string &options, std::string &str, Bool_t asjson)
1332{
1334 return kFALSE;
1335
1336 const char *args = (const char *)fCurrentArg->GetPostData();
1337 const char *ends = args + fCurrentArg->GetPostDataLength();
1338
1339 TUrl url;
1340 url.SetOptions(options.c_str());
1341
1342 Int_t number = 0;
1343 if (url.GetValueFromOptions("number"))
1344 number = url.GetIntValueFromOptions("number");
1345
1346 // binary buffers required only for binary requests, json output can be produced as is
1347 std::vector<std::string> mem;
1348
1349 if (asjson)
1350 str = "[";
1351
1352 for (Int_t n = 0; n < number; n++) {
1353 const char *next = args;
1354 while ((next < ends) && (*next != '\n'))
1355 next++;
1356 if (next == ends) {
1357 Error("ProduceMulti", "Not enough arguments in POST block");
1358 break;
1359 }
1360
1361 std::string file1(args, next - args);
1362 args = next + 1;
1363
1364 std::string path1, opt1;
1365
1366 // extract options
1367 std::size_t pos = file1.find_first_of('?');
1368 if (pos != std::string::npos) {
1369 opt1 = file1.substr(pos + 1, file1.length() - pos);
1370 file1.resize(pos);
1371 }
1372
1373 // extract extra path
1374 pos = file1.find_last_of('/');
1375 if (pos != std::string::npos) {
1376 path1 = file1.substr(0, pos);
1377 file1.erase(0, pos + 1);
1378 }
1379
1380 if (!path.empty())
1381 path1 = path + "/" + path1;
1382
1383 std::string res1;
1384
1385 // produce next item request
1386 Produce(path1, file1, opt1, res1);
1387
1388 if (asjson) {
1389 if (n > 0)
1390 str.append(", ");
1391 if (res1.empty())
1392 str.append("null");
1393 else
1394 str.append(res1);
1395 } else {
1396 mem.emplace_back(std::move(res1));
1397 }
1398 }
1399
1400 if (asjson) {
1401 str.append("]");
1402 } else {
1403 Int_t length = 0;
1404 for (unsigned n = 0; n < mem.size(); n++)
1405 length += 4 + mem[n].length();
1406 str.resize(length);
1407 char *curr = (char *)str.data();
1408 for (unsigned n = 0; n < mem.size(); n++) {
1409 Long_t l = mem[n].length();
1410 *curr++ = (char)(l & 0xff);
1411 l = l >> 8;
1412 *curr++ = (char)(l & 0xff);
1413 l = l >> 8;
1414 *curr++ = (char)(l & 0xff);
1415 l = l >> 8;
1416 *curr++ = (char)(l & 0xff);
1417 if (!mem[n].empty())
1418 memcpy(curr, mem[n].data(), mem[n].length());
1419 curr += mem[n].length();
1420 }
1421 }
1422
1423 return kTRUE;
1424}
1425
1426////////////////////////////////////////////////////////////////////////////////
1427/// Produce binary data for specified item
1428/// if "zipped" option specified in query, buffer will be compressed
1429///
1430/// Implemented only in TRootSnifferFull class
1431
1432Bool_t TRootSniffer::ProduceBinary(const std::string & /*path*/, const std::string & /*query*/, std::string & /*res*/)
1433{
1434 return kFALSE;
1435}
1436
1437////////////////////////////////////////////////////////////////////////////////
1438/// Method to produce image from specified object
1439///
1440/// Parameters:
1441/// kind - image kind TImage::kPng, TImage::kJpeg, TImage::kGif
1442/// path - path to object
1443/// options - extra options
1444///
1445/// By default, image 300x200 is produced
1446/// In options string one could provide following parameters:
1447/// w - image width
1448/// h - image height
1449/// opt - draw options
1450/// For instance:
1451/// http://localhost:8080/Files/hsimple.root/hpx/get.png?w=500&h=500&opt=lego1
1452///
1453/// Return is memory with produced image
1454/// Memory must be released by user with free(ptr) call
1455///
1456/// Method implemented only in TRootSnifferFull class
1457
1458Bool_t TRootSniffer::ProduceImage(Int_t /*kind*/, const std::string & /*path*/, const std::string & /*options*/, std::string & /*res*/)
1459{
1460 return kFALSE;
1461}
1462
1463////////////////////////////////////////////////////////////////////////////////
1464/// Method produce different kind of data out of object
1465/// Parameter 'path' specifies object or object member
1466/// Supported 'file' (case sensitive):
1467/// "root.bin" - binary data
1468/// "root.png" - png image
1469/// "root.jpeg" - jpeg image
1470/// "root.gif" - gif image
1471/// "root.xml" - xml representation
1472/// "root.json" - json representation
1473/// "exe.json" - method execution with json reply
1474/// "exe.bin" - method execution with binary reply
1475/// "exe.txt" - method execution with debug output
1476/// "cmd.json" - execution of registered commands
1477/// Result returned in std::string - can be binary or text.
1478
1479Bool_t TRootSniffer::Produce(const std::string &path, const std::string &file, const std::string &options, std::string &res)
1480{
1481 if (file.empty())
1482 return kFALSE;
1483
1484 if (file == "root.bin")
1485 return ProduceBinary(path, options, res);
1486
1487 if (file == "root.png")
1488 return ProduceImage(TImage::kPng, path, options, res);
1489
1490 if (file == "root.jpeg")
1491 return ProduceImage(TImage::kJpeg, path, options, res);
1492
1493 if (file == "root.gif")
1494 return ProduceImage(TImage::kGif, path, options, res);
1495
1496 if (file == "exe.bin")
1497 return ProduceExe(path, options, 2, res);
1498
1499 if (file == "root.xml")
1500 return ProduceXml(path, options, res);
1501
1502 if (file == "root.json")
1503 return ProduceJson(path, options, res);
1504
1505 // used for debugging
1506 if (file == "exe.txt")
1507 return ProduceExe(path, options, 0, res);
1508
1509 if (file == "exe.json")
1510 return ProduceExe(path, options, 1, res);
1511
1512 if (file == "cmd.json")
1513 return ExecuteCmd(path, options, res);
1514
1515 if (file == "item.json")
1516 return ProduceItem(path, options, res, kTRUE);
1517
1518 if (file == "item.xml")
1519 return ProduceItem(path, options, res, kFALSE);
1520
1521 if (file == "multi.bin")
1522 return ProduceMulti(path, options, res, kFALSE);
1523
1524 if (file == "multi.json")
1525 return ProduceMulti(path, options, res, kTRUE);
1526
1527 return kFALSE;
1528}
1529
1530////////////////////////////////////////////////////////////////////////////////
1531/// return item from the subfolders structure
1532
1533TObject *TRootSniffer::GetItem(const char *fullname, TFolder *&parent, Bool_t force, Bool_t within_objects)
1534{
1535 TFolder *httpfold = GetTopFolder(force);
1536 if (!httpfold) return nullptr;
1537
1538 parent = httpfold;
1539 TObject *obj = httpfold;
1540
1541 if (!fullname)
1542 return httpfold;
1543
1544 // when full path started not with slash, "Objects" subfolder is appended
1545 TString path = fullname;
1546 if (within_objects && ((path.Length() == 0) || (path[0] != '/')))
1547 path = fObjectsPath + "/" + path;
1548
1549 TString tok;
1550 Ssiz_t from(0);
1551
1552 while (path.Tokenize(tok, from, "/")) {
1553 if (tok.Length() == 0)
1554 continue;
1555
1556 TFolder *fold = dynamic_cast<TFolder *>(obj);
1557 if (!fold)
1558 return nullptr;
1559
1560 TIter iter(fold->GetListOfFolders());
1561 while ((obj = iter()) != nullptr) {
1562 if (IsItemField(obj))
1563 continue;
1564 if (tok.CompareTo(obj->GetName()) == 0)
1565 break;
1566 }
1567
1568 if (!obj) {
1569 if (!force)
1570 return nullptr;
1571 obj = fold->AddFolder(tok, "sub-folder");
1572 obj->SetBit(kCanDelete);
1573 }
1574
1575 parent = fold;
1576 }
1577
1578 return obj;
1579}
1580
1581////////////////////////////////////////////////////////////////////////////////
1582/// creates subfolder where objects can be registered
1583
1584TFolder *TRootSniffer::GetSubFolder(const char *subfolder, Bool_t force)
1585{
1586 TFolder *parent = nullptr;
1587
1588 return dynamic_cast<TFolder *>(GetItem(subfolder, parent, force));
1589}
1590
1591////////////////////////////////////////////////////////////////////////////////
1592/// Register object in subfolder structure
1593/// subfolder parameter can have many levels like:
1594///
1595/// TRootSniffer* sniff = new TRootSniffer("sniff");
1596/// sniff->RegisterObject("my/sub/subfolder", h1);
1597///
1598/// Such objects can be later found in "Objects" folder of sniffer like
1599///
1600/// h1 = sniff->FindTObjectInHierarchy("/Objects/my/sub/subfolder/h1");
1601///
1602/// If subfolder name starts with '/', object will be registered starting from top folder.
1603///
1604/// One could provide additional fields for registered objects
1605/// For instance, setting "_more" field to true let browser
1606/// explore objects members. For instance:
1607///
1608/// TEvent* ev = new TEvent("ev");
1609/// sniff->RegisterObject("Events", ev);
1610/// sniff->SetItemField("Events/ev", "_more", "true");
1611
1612Bool_t TRootSniffer::RegisterObject(const char *subfolder, TObject *obj)
1613{
1614 TFolder *f = GetSubFolder(subfolder, kTRUE);
1615 if (!f)
1616 return kFALSE;
1617
1618 // If object will be destroyed, it will be removed from the folders automatically
1619 obj->SetBit(kMustCleanup);
1620
1621 f->Add(obj);
1622
1623 return kTRUE;
1624}
1625
1626////////////////////////////////////////////////////////////////////////////////
1627/// unregister (remove) object from folders structures
1628/// folder itself will remain even when it will be empty
1629
1631{
1632 if (!obj)
1633 return kTRUE;
1634
1635 TFolder *topf = GetTopFolder();
1636
1637 if (!topf) {
1638 Error("UnregisterObject", "Not found top folder");
1639 return kFALSE;
1640 }
1641
1642 // TODO - probably we should remove all set properties as well
1643 topf->RecursiveRemove(obj);
1644
1645 return kTRUE;
1646}
1647
1648////////////////////////////////////////////////////////////////////////////////
1649/// create item element
1650
1651Bool_t TRootSniffer::CreateItem(const char *fullname, const char *title)
1652{
1653 TFolder *f = GetSubFolder(fullname, kTRUE);
1654 if (!f)
1655 return kFALSE;
1656
1657 if (title)
1658 f->SetTitle(title);
1659
1660 return kTRUE;
1661}
1662
1663////////////////////////////////////////////////////////////////////////////////
1664/// return true when object is TNamed with kItemField bit set
1665/// such objects used to keep field values for item
1666
1668{
1669 return (obj != nullptr) && (obj->IsA() == TNamed::Class()) && obj->TestBit(kItemField);
1670}
1671
1672////////////////////////////////////////////////////////////////////////////////
1673/// set or get field for the child
1674/// each field coded as TNamed object, placed after chld in the parent hierarchy
1675
1676Bool_t TRootSniffer::AccessField(TFolder *parent, TObject *chld, const char *name, const char *value, TNamed **only_get)
1677{
1678 if (!parent)
1679 return kFALSE;
1680
1681 if (!chld) {
1682 Info("AccessField", "Should be special case for top folder, support later");
1683 return kFALSE;
1684 }
1685
1686 TIter iter(parent->GetListOfFolders());
1687
1688 TObject *obj = nullptr;
1689 Bool_t find(kFALSE), last_find(kFALSE);
1690 // this is special case of top folder - fields are on very top
1691 if (parent == chld) {
1692 last_find = find = kTRUE;
1693 }
1694 TNamed *curr = nullptr;
1695 while ((obj = iter()) != nullptr) {
1696 if (IsItemField(obj)) {
1697 if (last_find && obj->GetName() && !strcmp(name, obj->GetName()))
1698 curr = (TNamed *)obj;
1699 } else {
1700 last_find = (obj == chld);
1701 if (last_find)
1702 find = kTRUE;
1703 if (find && !last_find)
1704 break; // no need to continue
1705 }
1706 }
1707
1708 // object must be in childs list
1709 if (!find)
1710 return kFALSE;
1711
1712 if (only_get) {
1713 *only_get = curr;
1714 return curr != nullptr;
1715 }
1716
1717 if (curr) {
1718 if (value) {
1719 curr->SetTitle(value);
1720 } else {
1721 parent->Remove(curr);
1722 delete curr;
1723 }
1724 return kTRUE;
1725 }
1726
1727 curr = new TNamed(name, value);
1728 curr->SetBit(kItemField);
1729
1730 if (last_find) {
1731 // object is on last place, therefore just add property
1732 parent->Add(curr);
1733 return kTRUE;
1734 }
1735
1736 // only here we do dynamic cast to the TList to use AddAfter
1737 TList *lst = dynamic_cast<TList *>(parent->GetListOfFolders());
1738 if (!lst) {
1739 Error("AccessField", "Fail cast to TList");
1740 return kFALSE;
1741 }
1742
1743 if (parent == chld)
1744 lst->AddFirst(curr);
1745 else
1746 lst->AddAfter(chld, curr);
1747
1748 return kTRUE;
1749}
1750
1751////////////////////////////////////////////////////////////////////////////////
1752/// set field for specified item
1753
1754Bool_t TRootSniffer::SetItemField(const char *fullname, const char *name, const char *value)
1755{
1756 if (!fullname || !name)
1757 return kFALSE;
1758
1759 TFolder *parent = nullptr;
1760 TObject *obj = GetItem(fullname, parent);
1761
1762 if (!parent || !obj)
1763 return kFALSE;
1764
1765 if (strcmp(name, item_prop_title) == 0) {
1766 TNamed *n = dynamic_cast<TNamed *>(obj);
1767 if (n) {
1768 n->SetTitle(value);
1769 return kTRUE;
1770 }
1771 }
1772
1773 return AccessField(parent, obj, name, value);
1774}
1775
1776////////////////////////////////////////////////////////////////////////////////
1777/// return field for specified item
1778
1779const char *TRootSniffer::GetItemField(TFolder *parent, TObject *obj, const char *name)
1780{
1781 if (!parent || !obj || !name)
1782 return nullptr;
1783
1784 TNamed *field = nullptr;
1785
1786 if (!AccessField(parent, obj, name, nullptr, &field))
1787 return nullptr;
1788
1789 return field ? field->GetTitle() : nullptr;
1790}
1791
1792////////////////////////////////////////////////////////////////////////////////
1793/// return field for specified item
1794
1795const char *TRootSniffer::GetItemField(const char *fullname, const char *name)
1796{
1797 if (!fullname)
1798 return nullptr;
1799
1800 TFolder *parent = nullptr;
1801 TObject *obj = GetItem(fullname, parent);
1802
1803 return GetItemField(parent, obj, name);
1804}
1805
1806////////////////////////////////////////////////////////////////////////////////
1807/// Register command which can be executed from web interface
1808///
1809/// As method one typically specifies string, which is executed with
1810/// gROOT->ProcessLine() method. For instance
1811/// serv->RegisterCommand("Invoke","InvokeFunction()");
1812///
1813/// Or one could specify any method of the object which is already registered
1814/// to the server. For instance:
1815/// serv->Register("/", hpx);
1816/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
1817/// Here symbols '/->' separates item name from method to be executed
1818///
1819/// One could specify additional arguments in the command with
1820/// syntax like %arg1%, %arg2% and so on. For example:
1821/// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
1822/// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
1823/// Such parameter(s) will be requested when command clicked in the browser.
1824///
1825/// Once command is registered, one could specify icon which will appear in the browser:
1826/// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
1827///
1828/// One also can set extra property '_fastcmd', that command appear as
1829/// tool button on the top of the browser tree:
1830/// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
1831/// Or it is equivalent to specifying extra argument when register command:
1832/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
1833
1834Bool_t TRootSniffer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
1835{
1836 CreateItem(cmdname, Form("command %s", method));
1837 SetItemField(cmdname, "_kind", "Command");
1838 if (icon) {
1839 if (strncmp(icon, "button;", 7) == 0) {
1840 SetItemField(cmdname, "_fastcmd", "true");
1841 icon += 7;
1842 }
1843 if (*icon != 0)
1844 SetItemField(cmdname, "_icon", icon);
1845 }
1846 SetItemField(cmdname, "method", method);
1847 Int_t numargs = 0;
1848 do {
1849 TString nextname = TString::Format("%sarg%d%s", "%", numargs + 1, "%");
1850 if (strstr(method, nextname.Data()) == nullptr)
1851 break;
1852 numargs++;
1853 } while (numargs < 100);
1854 if (numargs > 0)
1855 SetItemField(cmdname, "_numargs", TString::Format("%d", numargs));
1856
1857 return kTRUE;
1858}
#define f(i)
Definition RSha256.hxx:104
#define ROOT_VERSION_CODE
Definition RVersion.h:21
const Ssiz_t kNPOS
Definition RtypesCore.h:124
const Bool_t kFALSE
Definition RtypesCore.h:101
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:100
#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:592
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:404
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:2029
TList * GetListOfRealData() const
Definition TClass.h:450
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition TClass.cxx:2789
Long_t Property() const
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6072
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition TClass.cxx:3489
Collection abstract base class.
Definition TCollection.h:65
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:222
virtual TList * GetListOfKeys() const
Definition TDirectory.h:223
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:455
virtual void Remove(TObject *obj)
Remove object from this folder. obj must be a TObject or a TFolder.
Definition TFolder.cxx:463
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:38
virtual void Add(TObject *obj)
Definition TList.h:81
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:31
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:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:429
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:201
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:200
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:766
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:515
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:963
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:473
@ 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:937
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.
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
@ 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
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:442
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:1946
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:2222
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition TString.cxx:662
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:2336
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2314
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