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