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