Logo ROOT  
Reference Guide
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}
void Class()
Definition: Class.C:29
#define f(i)
Definition: RSha256.hxx:104
#define ROOT_VERSION_CODE
Definition: RVersion.h:21
const Ssiz_t kNPOS
Definition: RtypesCore.h:124
int Int_t
Definition: RtypesCore.h:45
int Ssiz_t
Definition: RtypesCore.h:67
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:61
#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:2018
TList * GetListOfRealData() const
Definition: TClass.h:450
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2778
Long_t Property() const
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition: TClass.cxx:6038
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3456
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.
Definition: TCollection.h:184
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:213
virtual TList * GetListOfKeys() const
Definition: TDirectory.h:214
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)
Definition: THttpCallArg.h:152
const void * GetPostData() const
return pointer on posted with request data
Definition: THttpCallArg.h:140
Long_t GetPostDataLength() const
return length of posted with request data
Definition: THttpCallArg.h:143
@ 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.
Definition: TObjArray.cxx:415
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
Definition: TRootSniffer.h:47
Int_t fLevel
! current level of hierarchy
Definition: TRootSniffer.h:46
Int_t fRestriction
! restriction 0 - default, 1 - read-only, 2 - full access
Definition: TRootSniffer.h:49
Bool_t CanExpandItem()
Returns true when item can be expanded.
TRootSnifferStore * fStore
! object to store results
Definition: TRootSniffer.h:51
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
Definition: TRootSniffer.h:64
UInt_t fMask
! defines operation kind
Definition: TRootSniffer.h:44
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
Definition: TRootSniffer.h:52
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
Definition: TRootSniffer.h:43
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
Definition: TRootSniffer.h:55
Int_t fNumFields
! number of fields
Definition: TRootSniffer.h:54
Bool_t fNodeStarted
! indicate if node was started
Definition: TRootSniffer.h:53
Bool_t SetFoundResult(void *obj, TClass *cl, TDataMember *member=nullptr)
Set found element with class and datamember (optional)
const char * fSearchPath
! current path searched
Definition: TRootSniffer.h:45
Int_t Depth() const
Returns depth of hierarchy.
TList fItemsNames
! list of created items names, need to avoid duplication
Definition: TRootSniffer.h:48
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
Definition: TRootSniffer.h:67
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)
Definition: TRootSniffer.h:37
@ kOnlyFields
if set, only fields for specified item will be set (but all fields)
Definition: TRootSniffer.h:39
@ kExpand
expand of specified item - allowed to scan object members
Definition: TRootSniffer.h:36
@ kCheckChilds
check if there childs, very similar to search
Definition: TRootSniffer.h:38
@ kScan
normal scan of hierarchy
Definition: TRootSniffer.h:35
@ kActions
mask for actions, only actions copied to child rec
Definition: TRootSniffer.h:40
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
Definition: TRootSniffer.h:121
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
Definition: TRootSniffer.h:128
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
Definition: TRootSniffer.h:127
virtual Bool_t HasStreamerInfo() const
Definition: TRootSniffer.h:160
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
Definition: TRootSniffer.h:122
void SetScanGlobalDir(Bool_t on=kTRUE)
When enabled (default), sniffer scans gROOT for files, canvases, histograms.
Definition: TRootSniffer.h:202
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)
Definition: TRootSniffer.h:125
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 *)
Definition: TRootSniffer.h:158
Int_t fCurrentRestrict
! current restriction for last-found object
Definition: TRootSniffer.h:126
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
Definition: TRootSniffer.h:124
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
Definition: TRootSniffer.h:129
Bool_t IsScanGlobalDir() const
Returns true when sniffer allowed to scan global directories.
Definition: TRootSniffer.h:209
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
const char * cnt
Definition: TXMLSetup.cxx:75
TCanvas * slash()
Definition: slash.C:1
auto * l
Definition: textangle.C:4