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 "TInterpreter.h"
20#include "TFolder.h"
21#include "TClass.h"
22#include "TRealData.h"
23#include "TDataMember.h"
24#include "TDataType.h"
25#include "TObjString.h"
26#include "TObjArray.h"
27#include "TUrl.h"
28#include "TVirtualMutex.h"
29#include "TRootSnifferStore.h"
30#include "THttpCallArg.h"
31
32#include <cstdlib>
33#include <memory>
34#include <vector>
35#include <cstring>
36#include <cctype>
37
38
39const char *item_prop_kind = "_kind";
40const char *item_prop_more = "_more";
41const char *item_prop_title = "_title";
42const char *item_prop_hidden = "_hidden";
43const char *item_prop_typename = "_typename";
44const char *item_prop_arraydim = "_arraydim";
45const char *item_prop_realname = "_realname"; // real object name
46const char *item_prop_user = "_username";
47const char *item_prop_autoload = "_autoload";
48const char *item_prop_rootversion = "_root_version";
49
50/** \class TRootSnifferScanRec
51
52Structure used to scan hierarchies of ROOT objects
53
54Represents single level of hierarchy
55*/
56
57////////////////////////////////////////////////////////////////////////////////
58/// constructor
59
64
65////////////////////////////////////////////////////////////////////////////////
66/// destructor
67
72
73////////////////////////////////////////////////////////////////////////////////
74/// record field for current element
75
82
83////////////////////////////////////////////////////////////////////////////////
84/// Indicates that new child for current element will be started
85
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
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
143{
144 if (!CanSetFields())
145 return;
146
148
149 if (fParent)
151
152 if (fStore)
154}
155
156////////////////////////////////////////////////////////////////////////////////
157/// Close started node
158
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
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
303{
304 if (super.Done())
305 return kFALSE;
306
307 if (obj && !obj_name)
308 obj_name = obj->GetName();
309
310 // exclude zero names
311 if (!obj_name || (*obj_name == 0))
312 return kFALSE;
313
314 const char *full_name = nullptr;
315
316 // remove slashes from file names
317 if (obj && obj->InheritsFrom(TDirectoryFile::Class())) {
318 const char *slash = strrchr(obj_name, '/');
319 if (slash) {
321 obj_name = slash + 1;
322 if (*obj_name == 0)
323 obj_name = "file";
324 }
325 }
326
327 super.MakeItemName(obj_name, fItemName);
328
329 if (sniffer && sniffer->HasRestriction(fItemName.Data())) {
330 // check restriction more precisely
331 TString fullname;
332 BuildFullName(fullname, &super);
333 fRestriction = sniffer->CheckRestriction(fullname.Data());
334 if (fRestriction < 0)
335 return kFALSE;
336 }
337
338 fParent = &super;
339 fLevel = super.fLevel;
340 fStore = super.fStore;
341 fSearchPath = super.fSearchPath;
342 fMask = super.fMask & kActions;
343 if (fRestriction == 0)
344 fRestriction = super.fRestriction; // get restriction from parent
346
347 if (fMask & kScan) {
348 // if scanning only fields, ignore all childs
349 if (super.ScanOnlyFields())
350 return kFALSE;
351 // only when doing scan, increment level, used for text formatting
352 fLevel++;
353 } else {
354 if (!fSearchPath)
355 return kFALSE;
356
358 return kFALSE;
359
360 const char *separ = fSearchPath + fItemName.Length();
361
363 while (*separ == '/') {
364 separ++;
365 isslash = kTRUE;
366 }
367
368 if (*separ == 0) {
369 fSearchPath = nullptr;
370 if (fMask & kExpand) {
373 fHasMore = (fMask & kOnlyFields) == 0;
374 }
375 } else {
376 if (!isslash)
377 return kFALSE;
379 }
380 }
381
383
384 if (obj_name && (fItemName != obj_name))
386
387 if (full_name)
388 SetField("_fullname", full_name);
389
390 if (topelement)
391 SetField(item_prop_rootversion, TString::Format("%d", gROOT->GetVersionCode()), kFALSE);
392
393 if (topelement && sniffer->GetAutoLoad())
394 SetField(item_prop_autoload, sniffer->GetAutoLoad());
395
396 return kTRUE;
397}
398
399
400/** \class TRootSniffer
401
402Sniffer of ROOT objects, data provider for THttpServer
403
404Provides methods to scan different structures like folders,
405directories, files and collections. Can locate objects (or its data member) per name.
406Can be extended to application-specific classes.
407
408Normally TRootSnifferFull class is used which able to access data from trees, canvases, histograms.
409*/
410
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
427
428////////////////////////////////////////////////////////////////////////////////
429/// set current http arguments, which then used in different process methods
430/// For instance, if user authorized with some user name,
431/// depending from restrictions some objects will be invisible
432/// or user get full access to the element
433/// Returns previous argument which was set before
434
436{
437 auto res = fCurrentArg;
438 fCurrentArg = arg;
441 return res;
442}
443
444////////////////////////////////////////////////////////////////////////////////
445/// Restrict access to the specified location
446///
447/// Hides or provides read-only access to different parts of the hierarchy
448/// Restriction done base on user-name specified with http requests
449/// Options can be specified in URL style (separated with &)
450/// Following parameters can be specified:
451///
452/// visible = [all|user(s)] - make item visible for all users or only specified user
453/// hidden = [all|user(s)] - make item hidden from all users or only specified user
454/// readonly = [all|user(s)] - make item read-only for all users or only specified user
455/// allow = [all|user(s)] - make full access for all users or only specified user
456/// allow_method = method(s) - allow method(s) execution even when readonly flag specified for the object
457///
458/// Like make command seen by all but can be executed only by admin
459///
460/// sniff->Restrict("/CmdReset","allow=admin");
461///
462/// Or fully hide command from guest account
463///
464/// sniff->Restrict("/CmdRebin","hidden=guest");
465
466void TRootSniffer::Restrict(const char *path, const char *options)
467{
468 const char *rslash = strrchr(path, '/');
469 if (rslash)
470 rslash++;
471 if (!rslash || (*rslash == 0))
472 rslash = path;
473
474 fRestrictions.Add(new TNamed(rslash, TString::Format("%s%s%s", path, "%%%", options).Data()));
475}
476
477////////////////////////////////////////////////////////////////////////////////
478/// When specified, _autoload attribute will be always add
479/// to top element of h.json/h.hml requests
480/// Used to instruct browser automatically load special code
481
483{
484 fAutoLoad = scripts ? scripts : "";
485}
486
487////////////////////////////////////////////////////////////////////////////////
488/// return name of configured autoload scripts (or 0)
489
490const char *TRootSniffer::GetAutoLoad() const
491{
492 return fAutoLoad.Length() > 0 ? fAutoLoad.Data() : nullptr;
493}
494
495////////////////////////////////////////////////////////////////////////////////
496/// Made fast check if item with specified name is in restriction list
497/// If returns true, requires precise check with CheckRestriction() method
498
500{
501 if (!item_name || (*item_name == 0) || !fCurrentArg)
502 return kFALSE;
503
504 return fRestrictions.FindObject(item_name) != nullptr;
505}
506
507////////////////////////////////////////////////////////////////////////////////
508/// return 2 when option match to current user name
509/// return 1 when option==all
510/// return 0 when option does not match user name
511
513{
514 const char *username = fCurrentArg ? fCurrentArg->GetUserName() : nullptr;
515
516 if (!username || !option || (*option == 0))
517 return 0;
518
519 if (strcmp(option, "all") == 0)
520 return 1;
521
522 if (strcmp(username, option) == 0)
523 return 2;
524
525 if (strstr(option, username) == 0)
526 return -1;
527
529
530 Bool_t find = arr->FindObject(username) != nullptr;
531
532 delete arr;
533
534 return find ? 2 : -1;
535}
536
537////////////////////////////////////////////////////////////////////////////////
538/// Checked if restriction is applied to the item full_item_name
539/// should have full path to the item. Returns:
540///
541/// * -1 - object invisible, cannot be accessed or listed
542/// * 0 - no explicit restrictions, use default
543/// * 1 - read-only access
544/// * 2 - full access
545
547{
548 if (!full_item_name || (*full_item_name == 0))
549 return 0;
550
551 const char *item_name = strrchr(full_item_name, '/');
552 if (item_name)
553 item_name++;
554 if (!item_name || (*item_name == 0))
556
557 TString pattern1 = TString("*/") + item_name + "%%%";
559
560 const char *options = nullptr;
561 TIter iter(&fRestrictions);
562
563 while (auto obj = iter()) {
564 const char *title = obj->GetTitle();
565
566 if (strstr(title, pattern1.Data()) == title) {
567 options = title + pattern1.Length();
568 break;
569 }
570 if (strstr(title, pattern2.Data()) == title) {
571 options = title + pattern2.Length();
572 break;
573 }
574 }
575
576 if (!options)
577 return 0;
578
579 TUrl url;
580 url.SetOptions(options);
581 url.ParseOptions();
582
583 Int_t can_see =
584 WithCurrentUserName(url.GetValueFromOptions("visible")) - WithCurrentUserName(url.GetValueFromOptions("hidden"));
585
587 WithCurrentUserName(url.GetValueFromOptions("allow")) - WithCurrentUserName(url.GetValueFromOptions("readonly"));
588
589 if (can_access > 0)
590 return 2; // first of all, if access enabled, provide it
591 if (can_see < 0)
592 return -1; // if object to be hidden, do it
593
594 const char *methods = url.GetValueFromOptions("allow_method");
595 if (methods)
597
598 if (can_access < 0)
599 return 1; // read-only access
600
601 return 0; // default behavior
602}
603
604////////////////////////////////////////////////////////////////////////////////
605/// scan object data members
606/// some members like enum or static members will be excluded
607
609{
610 if (!cl || !ptr || rec.Done())
611 return;
612
613 // ensure that real class data (including parents) exists
614 if (!(cl->Property() & kIsAbstract))
615 cl->BuildRealData();
616
617 // scan only real data
618 TIter iter(cl->GetListOfRealData());
619 while (auto obj = iter()) {
620 TRealData *rdata = dynamic_cast<TRealData *>(obj);
621 if (!rdata || strchr(rdata->GetName(), '.'))
622 continue;
623
624 TDataMember *member = rdata->GetDataMember();
625 // exclude enum or static variables
626 if (!member || (member->Property() & (kIsStatic | kIsEnum | kIsUnion)))
627 continue;
628 char *member_ptr = ptr + rdata->GetThisOffset();
629
630 if (member->IsaPointer())
631 member_ptr = *((char **)member_ptr);
632
634
635 if (chld.GoInside(rec, member, 0, this)) {
636
637 TClass *mcl = (member->IsBasic() || member->IsSTLContainer()) ? nullptr : gROOT->GetClass(member->GetTypeName());
638
639 Int_t coll_offset = mcl ? mcl->GetBaseClassOffset(TCollection::Class()) : -1;
640 if (coll_offset >= 0) {
641 chld.SetField(item_prop_more, "true", kFALSE);
642 chld.fHasMore = kTRUE;
643 }
644
645 if (chld.SetFoundResult(ptr, cl, member))
646 break;
647
648 const char *title = member->GetTitle();
649 if (title && *title)
650 chld.SetField(item_prop_title, title);
651
652 if (member->GetTypeName())
653 chld.SetField(item_prop_typename, member->GetTypeName());
654
655 if (member->GetArrayDim() > 0) {
656 // store array dimensions in form [N1,N2,N3,...]
657 TString dim("[");
658 for (Int_t n = 0; n < member->GetArrayDim(); n++) {
659 if (n > 0)
660 dim.Append(",");
661 dim.Append(TString::Format("%d", member->GetMaxIndex(n)));
662 }
663 dim.Append("]");
664 chld.SetField(item_prop_arraydim, dim, kFALSE);
665 } else if (member->GetArrayIndex() != 0) {
666 TRealData *idata = cl->GetRealData(member->GetArrayIndex());
667 TDataMember *imember = idata ? idata->GetDataMember() : nullptr;
668 if (imember && (strcmp(imember->GetTrueTypeName(), "int") == 0)) {
669 Int_t arraylen = *((int *)(ptr + idata->GetThisOffset()));
671 }
672 }
673
674 chld.SetRootClass(mcl);
675
676 if (chld.CanExpandItem()) {
677 if (coll_offset >= 0) {
678 // chld.SetField("#members", "true", kFALSE);
680 }
681 }
682
683 if (chld.SetFoundResult(ptr, cl, member))
684 break;
685 }
686 }
687}
688
689////////////////////////////////////////////////////////////////////////////////
690/// Scans object properties
691/// here such fields as _autoload or _icon properties depending on class or object name could be assigned
692/// By default properties, coded in the Class title are scanned. Example:
693///
694/// ClassDef(UserClassName, 1) // class comments *SNIFF* _field1=value _field2="string value"
695///
696/// Here *SNIFF* mark is important. After it all expressions like field=value are parsed
697/// One could use double quotes to code string values with spaces.
698/// Fields separated from each other with spaces
699
701{
702 TClass *cl = obj ? obj->IsA() : nullptr;
703
704 const char *pos = strstr(cl ? cl->GetTitle() : "", "*SNIFF*");
705 if (!pos)
706 return;
707
708 pos += 7;
709 while (*pos) {
710 if (*pos == ' ') {
711 pos++;
712 continue;
713 }
714 // first locate identifier
715 const char *pos0 = pos;
716 while (*pos && (*pos != '='))
717 pos++;
718 if (*pos == 0)
719 return;
720 TString name(pos0, pos - pos0);
721 pos++;
722 Bool_t quotes = (*pos == '\"');
723 if (quotes)
724 pos++;
725 pos0 = pos;
726 // then value with or without quotes
727 while (*pos && (*pos != (quotes ? '\"' : ' ')))
728 pos++;
729 TString value(pos0, pos - pos0);
730 rec.SetField(name, value);
731 if (quotes)
732 pos++;
733 pos++;
734 }
735}
736
737////////////////////////////////////////////////////////////////////////////////
738/// Scans TKey properties
739/// in special cases load objects from the file
740
742{
743 if (strcmp(key->GetClassName(), "TDirectoryFile") == 0) {
744 if (rec.fLevel == 0) {
745 auto dir = key->ReadObject<TDirectory>();
746 if (dir) {
747 obj = dir;
748 obj_class = dir->IsA();
749 }
750 } else {
751 rec.SetField(item_prop_more, "true", kFALSE);
752 rec.fHasMore = kTRUE;
753 }
754 }
755}
756
757////////////////////////////////////////////////////////////////////////////////
758/// scans object childs (if any)
759/// here one scans collection, branches, trees and so on
760
762{
763 if (obj->InheritsFrom(TFolder::Class())) {
764 ScanCollection(rec, ((TFolder *)obj)->GetListOfFolders());
765 } else if (obj->InheritsFrom(TDirectory::Class())) {
766 TDirectory *dir = (TDirectory *)obj;
767 ScanCollection(rec, dir->GetList(), nullptr, dir->GetListOfKeys());
768 } else if (rec.CanExpandItem()) {
769 ScanObjectMembers(rec, obj->IsA(), (char *)obj);
770 }
771}
772
773////////////////////////////////////////////////////////////////////////////////
774/// Scan collection content
775
778{
779 if ((!lst || (lst->GetSize() == 0)) && (!keys_lst || (keys_lst->GetSize() == 0)))
780 return;
781
783 if (foldername) {
784 if (!folderrec.GoInside(rec, nullptr, foldername, this))
785 return;
786 }
787
789
790 if (lst) {
791 TIter iter(lst);
792 TObject *next = iter();
794
795 while (next) {
796 if (IsItemField(next)) {
797 // special case - in the beginning one could have items for master folder
798 if (!isany && (next->GetName() != nullptr) && ((*(next->GetName()) == '_') || master.ScanOnlyFields()))
799 master.SetField(next->GetName(), next->GetTitle());
800 next = iter();
801 continue;
802 }
803
804 isany = kTRUE;
805 TObject *obj = next;
806
808 if (!chld.GoInside(master, obj, nullptr, this)) {
809 next = iter();
810 continue;
811 }
812
813 if (chld.SetResult(obj, obj->IsA()))
814 return;
815
817
819 // now properties, coded as TNamed objects, placed after object in the hierarchy
820 while ((next = iter()) != nullptr) {
821 if (!IsItemField(next))
822 break;
823 if ((next->GetName() != nullptr) && ((*(next->GetName()) == '_') || chld.ScanOnlyFields())) {
824 // only fields starting with _ are stored
825 chld.SetField(next->GetName(), next->GetTitle());
826 if (strcmp(next->GetName(), item_prop_kind) == 0)
827 has_kind = kTRUE;
828 if (strcmp(next->GetName(), item_prop_title) == 0)
830 }
831 }
832
833 if (!has_kind)
834 chld.SetRootClass(obj->IsA());
835 if (!has_title && obj->GetTitle())
836 chld.SetField(item_prop_title, obj->GetTitle());
837
839
840 if (chld.SetResult(obj, obj->IsA()))
841 return;
842 }
843 }
844
845 if (keys_lst) {
846 TIter iter(keys_lst);
847
848 while (auto kobj = iter()) {
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
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
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
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
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,
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())
1026 rec.SetField(item_prop_autoload, 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
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
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{
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;
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
1197
1198 const char *cnumargs = GetItemField(parent, obj, "_numargs");
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 argname = TString("%") + argname + TString("%");
1217 auto p = method.Index(argname);
1218 if (p == kNPOS)
1219 continue;
1220
1221 method.Remove(p, argname.Length());
1222
1223 if ((p > 0) && (p < method.Length()) && (method.Length() > 1) && (method[p-1] == '"') && (method[p] == '"')) {
1224 // command definition has quotes around argument
1225 // one can insert value from URL removing quotes
1227 continue;
1228 }
1229
1230 // extract argument without removing quotes
1232
1233 if ((svalue.Length() > 1) && (svalue[0] == '"') && (svalue[svalue.Length() - 1] == '"')) {
1234 // if value itself has quotes, all special symbols already escaped and one can insert it as is
1235 method.Insert(p, svalue);
1236 continue;
1237 }
1238
1240 // expect decimal, hex or float values here, E/e also belong to hex
1241 for(Size_t i = 0; is_numeric && (i < svalue.Length()); ++i)
1242 is_numeric = std::isxdigit(svalue[i]) || std::strchr(".+-", svalue[i]);
1243
1244 // always quote content which not numeric
1245 if (!is_numeric)
1246 svalue = "\"" + svalue + "\"";
1247 else if (svalue.IsNull())
1248 svalue = "0";
1249
1250 method.Insert(p, svalue);
1251 }
1252 }
1253
1254 if (gDebug > 0)
1255 Info("ExecuteCmd", "Executing command %s method:%s", path.c_str(), method.Data());
1256
1257 TObject *item_obj = nullptr;
1258 Ssiz_t separ = method.Index("/->");
1259
1260 if (method.Index("this->") == 0) {
1261 // if command name started with this-> means method of sniffer will be executed
1262 item_obj = this;
1263 separ = 3;
1264 } else if (separ != kNPOS) {
1266 }
1267
1268 if (item_obj) {
1269 method = TString::Format("((%s*)%zu)->%s", item_obj->ClassName(), (size_t)item_obj, method.Data() + separ + 3);
1270 if (gDebug > 2)
1271 Info("ExecuteCmd", "Executing %s", method.Data());
1272 }
1273
1274 Int_t err = 0;
1275 auto v = gROOT->ProcessLineSync(method.Data(), &err);
1276 if (err == TInterpreter::kProcessing) {
1277 gInterpreter->ProcessLine(".@");
1278 if (gDebug > 0)
1279 Info("ExecuteCmd", "Unbalanced braces in %s", method.Data());
1280 res = "false";
1281 return kTRUE;
1282 }
1283
1284 res = std::to_string(v);
1285
1286 return kTRUE;
1287}
1288
1289////////////////////////////////////////////////////////////////////////////////
1290/// Produce JSON/XML for specified item
1291///
1292/// Contrary to h.json request, only fields for specified item are stored
1293
1294Bool_t TRootSniffer::ProduceItem(const std::string &path, const std::string &options, std::string &res, Bool_t asjson)
1295{
1296 TString buf; // TODO: implement direct storage into std::string
1297 if (asjson) {
1298 TRootSnifferStoreJson store(buf, options.find("compact") != std::string::npos);
1299 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1300 } else {
1301 TRootSnifferStoreXml store(buf, options.find("compact") != std::string::npos);
1302 ScanHierarchy("top", path.c_str(), &store, kTRUE);
1303 }
1304 res = buf.Data();
1305 return !res.empty();
1306}
1307
1308////////////////////////////////////////////////////////////////////////////////
1309/// Produce XML data for specified item
1310///
1311/// For object conversion TBufferXML is used
1312/// Method implemented only in TRootSnifferFull class
1313
1314Bool_t TRootSniffer::ProduceXml(const std::string &/* path */, const std::string & /* options */, std::string & /* res */)
1315{
1316 return kFALSE;
1317}
1318
1319////////////////////////////////////////////////////////////////////////////////
1320/// Method replaces all kind of special symbols, which could appear in URL options
1321
1323{
1324 if (!value || !*value)
1325 return "";
1326
1327 TString res = value;
1328
1329 // discard too large URL options, they should not appear at all
1330 if (res.Length() > 1024)
1331 return "";
1332
1333 res.ReplaceAll("%27", "\'");
1334 res.ReplaceAll("%22", "\"");
1335 res.ReplaceAll("%3E", ">");
1336 res.ReplaceAll("%3C", "<");
1337 res.ReplaceAll("%20", " ");
1338 res.ReplaceAll("%5B", "[");
1339 res.ReplaceAll("%5D", "]");
1340 res.ReplaceAll("%3D", "=");
1341
1342 Char_t quote = 0;
1343
1344 if ((res.Length() > 1) && ((res[0] == '\'') || (res[0] == '\"')) && (res[0] == res[res.Length() - 1]))
1345 quote = res[0];
1346
1347 // first remove quotes
1348 if (quote) {
1349 res.Remove(res.Length() - 1);
1350 res.Remove(0, 1);
1351 }
1352
1354 return res;
1355
1356 // we expect normal content here, no special symbols, no unescaped quotes
1357 TString clean;
1358 for (Ssiz_t i = 0; i < res.Length(); ++i) {
1359 char c = res[i];
1360 if (c == '"' || c == '\\') {
1361 // escape quotes and slahes
1362 clean.Append('\\');
1363 clean.Append(c);
1364 } else if (!std::iscntrl(c))
1365 // ignore all special symbols
1366 clean.Append(c);
1367 }
1368
1369 if (quote && !remove_quotes) {
1370 // return string with quotes - when desired
1371 res = "";
1372 res.Append(quote);
1373 res.Append(clean);
1374 res.Append(quote);
1375 return res;
1376 }
1377
1378 return clean;
1379}
1380
1381////////////////////////////////////////////////////////////////////////////////
1382/// Execute command for specified object
1383///
1384/// Options include method and extra list of parameters
1385/// sniffer should be not-readonly to allow execution of the commands
1386/// reskind defines kind of result 0 - debug, 1 - json, 2 - binary
1387///
1388/// Method implemented only in TRootSnifferFull class
1389
1390Bool_t TRootSniffer::ProduceExe(const std::string & /*path*/, const std::string & /*options*/, Int_t /*reskind*/,
1391 std::string & /*res*/)
1392{
1393 return kFALSE;
1394}
1395
1396////////////////////////////////////////////////////////////////////////////////
1397/// Process several requests, packing all results into binary or JSON buffer
1398///
1399/// Input parameters should be coded in the POST block and has
1400/// individual request relative to current path, separated with '\n' symbol like
1401/// item1/root.bin\n
1402/// item2/exe.bin?method=GetList\n
1403/// item3/exe.bin?method=GetTitle\n
1404/// Request requires 'number' URL option which contains number of requested items
1405///
1406/// In case of binary request output buffer looks like:
1407///
1408/// 4bytes length + payload,
1409/// 4bytes length + payload, ...
1410///
1411/// In case of JSON request output is array with results for each item
1412/// multi.json request do not support binary requests for the items
1413
1414Bool_t TRootSniffer::ProduceMulti(const std::string &path, const std::string &options, std::string &str, Bool_t asjson)
1415{
1417 return kFALSE;
1418
1419 const char *args = (const char *)fCurrentArg->GetPostData();
1420 const char *ends = args + fCurrentArg->GetPostDataLength();
1421
1422 TUrl url;
1423 url.SetOptions(options.c_str());
1424
1425 Int_t number = 0;
1426 if (url.GetValueFromOptions("number"))
1427 number = url.GetIntValueFromOptions("number");
1428
1429 // binary buffers required only for binary requests, json output can be produced as is
1430 std::vector<std::string> mem;
1431
1432 if (asjson)
1433 str = "[";
1434
1435 for (Int_t n = 0; n < number; n++) {
1436 const char *next = args;
1437 while ((next < ends) && (*next != '\n'))
1438 next++;
1439 if (next == ends) {
1440 Error("ProduceMulti", "Not enough arguments in POST block");
1441 break;
1442 }
1443
1444 std::string file1(args, next - args);
1445 args = next + 1;
1446
1447 std::string path1, opt1;
1448
1449 // extract options
1450 std::size_t pos = file1.find_first_of('?');
1451 if (pos != std::string::npos) {
1452 opt1 = file1.substr(pos + 1, file1.length() - pos);
1453 file1.resize(pos);
1454 }
1455
1456 // extract extra path
1457 pos = file1.find_last_of('/');
1458 if (pos != std::string::npos) {
1459 path1 = file1.substr(0, pos);
1460 file1.erase(0, pos + 1);
1461 }
1462
1463 if (!path.empty())
1464 path1 = path + "/" + path1;
1465
1466 std::string res1;
1467
1468 // produce next item request
1470
1471 if (asjson) {
1472 if (n > 0)
1473 str.append(", ");
1474 if (res1.empty())
1475 str.append("null");
1476 else
1477 str.append(res1);
1478 } else {
1479 mem.emplace_back(std::move(res1));
1480 }
1481 }
1482
1483 if (asjson) {
1484 str.append("]");
1485 } else {
1486 Int_t length = 0;
1487 for (unsigned n = 0; n < mem.size(); n++)
1488 length += 4 + mem[n].length();
1489 str.resize(length);
1490 char *curr = (char *)str.data();
1491 for (unsigned n = 0; n < mem.size(); n++) {
1492 Long_t l = mem[n].length();
1493 *curr++ = (char)(l & 0xff);
1494 l = l >> 8;
1495 *curr++ = (char)(l & 0xff);
1496 l = l >> 8;
1497 *curr++ = (char)(l & 0xff);
1498 l = l >> 8;
1499 *curr++ = (char)(l & 0xff);
1500 if (!mem[n].empty())
1501 memcpy(curr, mem[n].data(), mem[n].length());
1502 curr += mem[n].length();
1503 }
1504 }
1505
1506 return kTRUE;
1507}
1508
1509////////////////////////////////////////////////////////////////////////////////
1510/// Produce binary data for specified item
1511///
1512/// If "zipped" option specified in query, buffer will be compressed
1513///
1514/// Implemented only in TRootSnifferFull class
1515
1516Bool_t TRootSniffer::ProduceBinary(const std::string & /*path*/, const std::string & /*query*/, std::string & /*res*/)
1517{
1518 return kFALSE;
1519}
1520
1521////////////////////////////////////////////////////////////////////////////////
1522/// Produce ROOT file for specified item
1523///
1524/// Implemented only in TRootSnifferFull class
1525
1526Bool_t TRootSniffer::ProduceRootFile(const std::string & /*path*/, const std::string & /*query*/, std::string & /*res*/)
1527{
1528 return kFALSE;
1529}
1530
1531////////////////////////////////////////////////////////////////////////////////
1532/// Method to produce image from specified object
1533///
1534/// Parameters:
1535///
1536/// kind - image kind TImage::kPng, TImage::kJpeg, TImage::kGif
1537/// path - path to object
1538/// options - extra options
1539///
1540/// By default, image 300x200 is produced
1541/// In options string one could provide following parameters:
1542///
1543/// w - image width
1544/// h - image height
1545/// opt - draw options
1546///
1547/// For instance:
1548///
1549/// http://localhost:8080/Files/hsimple.root/hpx/get.png?w=500&h=500&opt=lego1
1550///
1551/// Returns produced image in the res string
1552///
1553/// Method implemented only in TRootSnifferFull class
1554
1555Bool_t TRootSniffer::ProduceImage(Int_t /*kind*/, const std::string & /*path*/, const std::string & /*options*/, std::string & /*res*/)
1556{
1557 return kFALSE;
1558}
1559
1560////////////////////////////////////////////////////////////////////////////////
1561/// Invokes TRootSniffer::ProduceIamge, converting kind into TImage::EImageFileTypes type
1562
1563Bool_t TRootSniffer::CallProduceImage(const std::string &/*kind*/, const std::string &/*path*/, const std::string &/*options*/, std::string &/*res*/)
1564{
1565 return kFALSE;
1566}
1567
1568////////////////////////////////////////////////////////////////////////////////
1569/// Method produce different kind of data out of object
1570///
1571/// @param path specifies object or object member
1572/// @param file can be:
1573///
1574/// * "root.bin" - binary data
1575/// * "root.png" - png image
1576/// * "root.jpeg" - jpeg image
1577/// * "root.gif" - gif image
1578/// * "root.xml" - xml representation
1579/// * "root.json" - json representation
1580/// * "file.root" - ROOT file with stored object
1581/// * "exe.json" - method execution with json reply
1582/// * "exe.bin" - method execution with binary reply
1583/// * "exe.txt" - method execution with debug output
1584/// * "cmd.json" - execution of registered commands
1585///
1586/// @param options specific options
1587/// @param res returns result - binary or text.
1588
1589Bool_t TRootSniffer::Produce(const std::string &path, const std::string &file, const std::string &options, std::string &res)
1590{
1591 if (file.empty())
1592 return kFALSE;
1593
1594 if (file == "root.bin")
1595 return ProduceBinary(path, options, res);
1596
1597 if (file == "root.png")
1598 return CallProduceImage("png", path, options, res);
1599
1600 if (file == "root.jpeg")
1601 return CallProduceImage("jpeg", path, options, res);
1602
1603 if (file == "root.gif")
1604 return CallProduceImage("gif", path, options, res);
1605
1606 if (file == "exe.bin")
1607 return ProduceExe(path, options, 2, res);
1608
1609 if (file == "root.xml")
1610 return ProduceXml(path, options, res);
1611
1612 if (file == "root.json")
1613 return ProduceJson(path, options, res);
1614
1615 if (file == "file.root")
1616 return ProduceRootFile(path, options, res);
1617
1618 // used for debugging
1619 if (file == "exe.txt")
1620 return ProduceExe(path, options, 0, res);
1621
1622 if (file == "exe.json")
1623 return ProduceExe(path, options, 1, res);
1624
1625 if (file == "cmd.json")
1626 return ExecuteCmd(path, options, res);
1627
1628 if (file == "item.json")
1629 return ProduceItem(path, options, res, kTRUE);
1630
1631 if (file == "item.xml")
1632 return ProduceItem(path, options, res, kFALSE);
1633
1634 if (file == "multi.bin")
1635 return ProduceMulti(path, options, res, kFALSE);
1636
1637 if (file == "multi.json")
1638 return ProduceMulti(path, options, res, kTRUE);
1639
1640 return kFALSE;
1641}
1642
1643////////////////////////////////////////////////////////////////////////////////
1644/// Return item from the subfolders structure
1645
1647{
1649 if (!httpfold) return nullptr;
1650
1651 parent = httpfold;
1652 TObject *obj = httpfold;
1653
1654 if (!fullname)
1655 return httpfold;
1656
1657 // when full path started not with slash, "Objects" subfolder is appended
1658 TString path = fullname;
1659 if (within_objects && ((path.Length() == 0) || (path[0] != '/')))
1660 path = fObjectsPath + "/" + path;
1661
1662 TString tok;
1663 Ssiz_t from = 0;
1664
1665 while (path.Tokenize(tok, from, "/")) {
1666 if (tok.Length() == 0)
1667 continue;
1668
1669 TFolder *fold = dynamic_cast<TFolder *>(obj);
1670 if (!fold)
1671 return nullptr;
1672
1673 TIter iter(fold->GetListOfFolders());
1674 while ((obj = iter()) != nullptr) {
1675 if (IsItemField(obj))
1676 continue;
1677 if (tok.CompareTo(obj->GetName()) == 0)
1678 break;
1679 }
1680
1681 if (!obj) {
1682 if (!force)
1683 return nullptr;
1684 obj = fold->AddFolder(tok, "sub-folder");
1685 obj->SetBit(kCanDelete);
1686 }
1687
1688 parent = fold;
1689 }
1690
1691 return obj;
1692}
1693
1694////////////////////////////////////////////////////////////////////////////////
1695/// Creates subfolder where objects can be registered
1696
1698{
1699 TFolder *parent = nullptr;
1700
1701 return dynamic_cast<TFolder *>(GetItem(subfolder, parent, force));
1702}
1703
1704////////////////////////////////////////////////////////////////////////////////
1705/// Register object in subfolder structure
1706///
1707/// @param obj pointer to TObject
1708/// @param subfolder can have many levels like:
1709///
1710/// TRootSniffer* sniff = new TRootSniffer("sniff");
1711/// sniff->RegisterObject("my/sub/subfolder", h1);
1712///
1713/// Such objects can be later found in "Objects" folder of sniffer like
1714///
1715/// auto h1 = sniff->FindTObjectInHierarchy("/Objects/my/sub/subfolder/h1");
1716///
1717/// If subfolder name starts with '/', object will be registered starting from top folder.
1718///
1719/// One could provide additional fields for registered objects
1720/// For instance, setting "_more" field to true let browser
1721/// explore objects members. For instance:
1722///
1723/// TEvent* ev = new TEvent("ev");
1724/// sniff->RegisterObject("Events", ev);
1725/// sniff->SetItemField("Events/ev", "_more", "true");
1726
1728{
1730 if (!f)
1731 return kFALSE;
1732
1733 // If object will be destroyed, it will be removed from the folders automatically
1734 obj->SetBit(kMustCleanup);
1735
1736 f->Add(obj);
1737
1738 return kTRUE;
1739}
1740
1741////////////////////////////////////////////////////////////////////////////////
1742/// Unregister (remove) object from folders structures
1743///
1744/// Folder itself will remain even when it will be empty
1745
1747{
1748 if (!obj)
1749 return kTRUE;
1750
1752
1753 if (!topf) {
1754 Error("UnregisterObject", "Not found top folder");
1755 return kFALSE;
1756 }
1757
1758 // TODO - probably we should remove all set properties as well
1759 topf->RecursiveRemove(obj);
1760
1761 return kTRUE;
1762}
1763
1764////////////////////////////////////////////////////////////////////////////////
1765/// Create item element
1766
1767Bool_t TRootSniffer::CreateItem(const char *fullname, const char *title)
1768{
1769 TFolder *f = GetSubFolder(fullname, kTRUE);
1770 if (!f)
1771 return kFALSE;
1772
1773 if (title)
1774 f->SetTitle(title);
1775
1776 return kTRUE;
1777}
1778
1779////////////////////////////////////////////////////////////////////////////////
1780/// Return true when object is TNamed with kItemField bit set
1781///
1782/// such objects used to keep field values for item
1783
1785{
1786 return (obj != nullptr) && (obj->IsA() == TNamed::Class()) && obj->TestBit(kItemField);
1787}
1788
1789////////////////////////////////////////////////////////////////////////////////
1790/// Set or get field for the child
1791///
1792/// each field coded as TNamed object, placed after chld in the parent hierarchy
1793
1795{
1796 if (!parent)
1797 return kFALSE;
1798
1799 if (!chld) {
1800 Info("AccessField", "Should be special case for top folder, support later");
1801 return kFALSE;
1802 }
1803
1804 TIter iter(parent->GetListOfFolders());
1805
1806 Bool_t find = kFALSE, last_find = kFALSE;
1807 // this is special case of top folder - fields are on very top
1808 if (parent == chld)
1809 last_find = find = kTRUE;
1810
1811 TNamed *curr = nullptr;
1812 while (auto obj = iter()) {
1813 if (IsItemField(obj)) {
1814 if (last_find && obj->GetName() && !strcmp(name, obj->GetName()))
1815 curr = (TNamed *)obj;
1816 } else {
1817 last_find = (obj == chld);
1818 if (last_find)
1819 find = kTRUE;
1820 if (find && !last_find)
1821 break; // no need to continue
1822 }
1823 }
1824
1825 // object must be in childs list
1826 if (!find)
1827 return kFALSE;
1828
1829 if (only_get) {
1830 *only_get = curr;
1831 return curr != nullptr;
1832 }
1833
1834 if (curr) {
1835 if (value) {
1836 curr->SetTitle(value);
1837 } else {
1838 parent->Remove(curr);
1839 delete curr;
1840 }
1841 return kTRUE;
1842 }
1843
1844 curr = new TNamed(name, value);
1845 curr->SetBit(kItemField);
1846
1847 if (last_find) {
1848 // object is on last place, therefore just add property
1849 parent->Add(curr);
1850 return kTRUE;
1851 }
1852
1853 // only here we do dynamic cast to the TList to use AddAfter
1854 TList *lst = dynamic_cast<TList *>(parent->GetListOfFolders());
1855 if (!lst) {
1856 Error("AccessField", "Fail cast to TList");
1857 return kFALSE;
1858 }
1859
1860 if (parent == chld)
1861 lst->AddFirst(curr);
1862 else
1863 lst->AddAfter(chld, curr);
1864
1865 return kTRUE;
1866}
1867
1868////////////////////////////////////////////////////////////////////////////////
1869/// Set field for specified item
1870
1871Bool_t TRootSniffer::SetItemField(const char *fullname, const char *name, const char *value)
1872{
1873 if (!fullname || !name)
1874 return kFALSE;
1875
1876 TFolder *parent = nullptr;
1877 TObject *obj = GetItem(fullname, parent);
1878
1879 if (!parent || !obj)
1880 return kFALSE;
1881
1882 if (strcmp(name, item_prop_title) == 0) {
1883 TNamed *n = dynamic_cast<TNamed *>(obj);
1884 if (n) {
1885 n->SetTitle(value);
1886 return kTRUE;
1887 }
1888 }
1889
1890 return AccessField(parent, obj, name, value);
1891}
1892
1893////////////////////////////////////////////////////////////////////////////////
1894/// Return field for specified item
1895
1896const char *TRootSniffer::GetItemField(TFolder *parent, TObject *obj, const char *name)
1897{
1898 if (!parent || !obj || !name)
1899 return nullptr;
1900
1901 TNamed *field = nullptr;
1902
1903 if (!AccessField(parent, obj, name, nullptr, &field))
1904 return nullptr;
1905
1906 return field ? field->GetTitle() : nullptr;
1907}
1908
1909////////////////////////////////////////////////////////////////////////////////
1910/// Return field for specified item
1911
1912const char *TRootSniffer::GetItemField(const char *fullname, const char *name)
1913{
1914 if (!fullname)
1915 return nullptr;
1916
1917 TFolder *parent = nullptr;
1918 TObject *obj = GetItem(fullname, parent);
1919
1920 return GetItemField(parent, obj, name);
1921}
1922
1923////////////////////////////////////////////////////////////////////////////////
1924/// Register command which can be executed from web interface
1925///
1926/// As method one typically specifies string, which is executed with
1927/// gROOT->ProcessLine() method. For instance:
1928///
1929/// serv->RegisterCommand("Invoke","InvokeFunction()");
1930///
1931/// Or one could specify any method of the object which is already registered
1932/// to the server. For instance:
1933///
1934/// serv->Register("/", hpx);
1935/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
1936///
1937/// Here symbols '/->' separates item name from method to be executed
1938///
1939/// One could specify additional arguments in the command with
1940/// syntax like %arg1%, %arg2% and so on. For example:
1941///
1942/// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
1943/// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
1944///
1945/// Such parameter(s) will be requested when command clicked in the browser.
1946///
1947/// Once command is registered, one could specify icon which will appear in the browser:
1948///
1949/// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
1950///
1951/// One also can set extra property '_fastcmd', that command appear as
1952/// tool button on the top of the browser tree:
1953///
1954/// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
1955///
1956/// Or it is equivalent to specifying extra argument when register command:
1957///
1958/// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
1959
1960Bool_t TRootSniffer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
1961{
1962 CreateItem(cmdname, TString::Format("command %s", method).Data());
1963 SetItemField(cmdname, "_kind", "Command");
1964 if (icon) {
1965 if (strncmp(icon, "button;", 7) == 0) {
1966 SetItemField(cmdname, "_fastcmd", "true");
1967 icon += 7;
1968 }
1969 if (*icon)
1970 SetItemField(cmdname, "_icon", icon);
1971 }
1972 SetItemField(cmdname, "method", method);
1973 Int_t numargs = 0;
1974 do {
1975 TString nextname = TString::Format("%sarg%d%s", "%", numargs + 1, "%");
1976 if (strstr(method, nextname.Data()) == nullptr)
1977 break;
1978 numargs++;
1979 } while (numargs < 100);
1980 if (numargs > 0)
1981 SetItemField(cmdname, "_numargs", TString::Format("%d", numargs));
1982
1983 return kTRUE;
1984}
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define ROOT_VERSION_CODE
Definition RVersion.hxx:24
float Size_t
Attribute size (float)
Definition RtypesCore.h:103
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:51
unsigned long ULong_t
Unsigned long integer 4 bytes (unsigned long). Size depends on architecture.
Definition RtypesCore.h:69
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
@ kIsEnum
Definition TDictionary.h:68
@ kIsAbstract
Definition TDictionary.h:71
@ kIsStatic
Definition TDictionary.h:80
@ kIsUnion
Definition TDictionary.h:67
winID h TVirtualViewer3D TVirtualGLPainter p
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:148
#define gInterpreter
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:777
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:417
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
#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:84
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2038
TList * GetListOfRealData() const
Definition TClass.h:468
Int_t GetBaseClassOffset(const TClass *toBase, void *address=nullptr, bool isDerivedObject=true)
Definition TClass.cxx:2812
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6191
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition TClass.cxx:3565
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.
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
static TClass * Class()
Describe directory structure in memory.
Definition TDirectory.h:45
static TClass * Class()
virtual TList * GetList() const
Definition TDirectory.h:223
virtual TList * GetListOfKeys() const
Definition TDirectory.h:224
<div class="legacybox"><h2>Legacy Code</h2> TFolder is a legacy interface: there will be no bug fixes...
Definition TFolder.h:30
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:165
static TClass * Class()
virtual void Remove(TObject *obj)
Remove object from this folder. obj must be a TObject or a TFolder.
Definition TFolder.cxx:456
Contains arguments for single HTTP call.
const char * GetUserName() const
return authenticated user name (0 - when no authentication)
const void * GetPostData() const
return pointer on posted with request data
Long_t GetPostDataLength() const
return length of posted with request data
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
T * ReadObject()
To read an object (non deriving from TObject) from the file.
Definition TKey.h:105
virtual const char * GetClassName() const
Definition TKey.h:77
Short_t GetCycle() const
Return cycle number associated to this key.
Definition TKey.cxx:623
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition TKey.cxx:804
A doubly linked list.
Definition TList.h:38
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:708
void Add(TObject *obj) override
Definition TList.h:81
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
TNamed()
Definition TNamed.h:38
static TClass * Class()
An array of TObjects.
Definition TObjArray.h:31
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:42
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:462
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:227
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:888
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:549
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1098
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:507
virtual TClass * IsA() const
Definition TObject.h:248
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:71
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:73
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1072
The TRealData class manages the effective list of all data members for a given class.
Definition TRealData.h:30
Structure used to scan hierarchies of ROOT objects.
TString fItemName
! name of current item
Int_t fLevel
! current level of hierarchy
Int_t fRestriction
! restriction 0 - default, 1 - read-only, 2 - full access
Bool_t CanExpandItem()
Returns true when item can be expanded.
TRootSnifferStore * fStore
! object to store results
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
@ 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 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.
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.
TRootSniffer(const char *name="sniff", const char *objpath="Objects")
constructor
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 DecodeUrlOptionValue(const char *value, Bool_t remove_quotes=kTRUE, Bool_t escape_special=kTRUE)
Method replaces all kind of special symbols, which could appear in URL options.
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'.
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.
THttpCallArg * SetCurrentCallArg(THttpCallArg *arg)
set current http arguments, which then used in different process methods For instance,...
void Restrict(const char *path, const char *options)
Restrict access to the specified location.
virtual ULong_t GetItemHash(const char *itemname)
Get hash function for specified item used to detect any changes in the specified object.
Bool_t fReadOnly
! indicate if sniffer allowed to change ROOT structures - like read objects from file
void SetScanGlobalDir(Bool_t on=kTRUE)
When enabled (default), sniffer scans gROOT for files, canvases, histograms.
TObject * GetItem(const char *fullname, TFolder *&parent, Bool_t force=kFALSE, Bool_t within_objects=kTRUE)
Return item from the subfolders structure.
THttpCallArg * fCurrentArg
! current http arguments (if any)
virtual Bool_t ProduceImage(Int_t kind, const std::string &path, const std::string &options, std::string &res)
Method to produce image from specified object.
TObject * FindTObjectInHierarchy(const char *path)
Search element in hierarchy, derived from TObject.
void SetAutoLoad(const char *scripts="")
When specified, _autoload attribute will be always add to top element of h.json/h....
virtual void * FindInHierarchy(const char *path, TClass **cl=nullptr, TDataMember **member=nullptr, Int_t *chld=nullptr)
Search element with specified path Returns pointer on element Optionally one could obtain element cla...
virtual Bool_t ProduceItem(const std::string &path, const std::string &options, std::string &res, Bool_t asjson=kTRUE)
Produce JSON/XML for specified item.
Int_t CheckRestriction(const char *item_name)
Checked if restriction is applied to the item full_item_name should have full path to the item.
virtual Bool_t CallProduceImage(const std::string &kind, const std::string &path, const std::string &options, std::string &res)
Invokes TRootSniffer::ProduceIamge, converting kind into TImage::EImageFileTypes type.
Bool_t IsItemField(TObject *obj) const
Return true when object is TNamed with kItemField bit set.
virtual ~TRootSniffer()
destructor
virtual Bool_t CanDrawClass(TClass *)
Int_t fCurrentRestrict
! current restriction for last-found object
TFolder * GetTopFolder(Bool_t force=kFALSE)
Returns top TFolder instance for the sniffer.
const char * GetItemField(TFolder *parent, TObject *item, const char *name)
Return field for specified item.
std::unique_ptr< TFolder > fTopFolder
! own top TFolder object, used for registering objects
Bool_t CanExploreItem(const char *path)
Method returns true when object has childs or one could try to expand item.
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
Set field for specified item.
Int_t WithCurrentUserName(const char *option)
return 2 when option match to current user name return 1 when option==all return 0 when option does n...
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon)
Register command which can be executed from web interface.
TString fAutoLoad
! scripts names, which are add as _autoload parameter to h.json request
Bool_t IsScanGlobalDir() const
Returns true when sniffer allowed to scan global directories.
virtual Bool_t ProduceBinary(const std::string &path, const std::string &options, std::string &res)
Produce binary data for specified item.
TFolder * GetSubFolder(const char *foldername, Bool_t force=kFALSE)
Creates subfolder where objects can be registered.
virtual Bool_t ProduceRootFile(const std::string &path, const std::string &options, std::string &res)
Produce ROOT file for specified item.
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:138
Ssiz_t Length() const
Definition TString.h:425
Int_t Atoi() const
Return integer value of string.
Definition TString.cxx:1994
const char * Data() const
Definition TString.h:384
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:713
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2270
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition TString.cxx:684
TString & Remove(Ssiz_t pos)
Definition TString.h:694
TString & Append(const char *cs)
Definition TString.h:581
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:2385
This class represents a WWW compatible URL.
Definition TUrl.h:33
const Int_t n
Definition legend1.C:16
TCanvas * slash()
Definition slash.C:1
TLine l
Definition textangle.C:4