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