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