Logo ROOT   6.21/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 "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 
36 const char *item_prop_kind = "_kind";
37 const char *item_prop_more = "_more";
38 const char *item_prop_title = "_title";
39 const char *item_prop_hidden = "_hidden";
40 const char *item_prop_typename = "_typename";
41 const char *item_prop_arraydim = "_arraydim";
42 const char *item_prop_realname = "_realname"; // real object name
43 const char *item_prop_user = "_username";
44 const char *item_prop_autoload = "_autoload";
45 const 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 
75 void 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 
98 void 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 
141 void 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())
174  SetField(item_prop_kind, TString::Format("ROOT.%s", cl->GetName()));
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 
301 Bool_t
302 TRootSnifferScanRec::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;
372  fMask = (fMask & kOnlyFields) | kScan;
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 
418 TRootSniffer::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;
440  fCurrentRestrict = 0;
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 
461 void 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 
477 void TRootSniffer::SetAutoLoad(const char *scripts)
478 {
479  fAutoLoad = scripts ? scripts : "";
480 }
481 
482 ////////////////////////////////////////////////////////////////////////////////
483 /// return name of configured autoload scripts (or 0)
484 
485 const 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 
494 Bool_t TRootSniffer::HasRestriction(const char *item_name)
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 
541 Int_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 
630  TRootSnifferScanRec chld;
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("]");
661  chld.SetField(item_prop_arraydim, dim, kFALSE);
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 
772 void 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 
803  TRootSnifferScanRec chld;
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 
866  TRootSnifferScanRec chld;
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()) {
976  TRootSnifferScanRec chld;
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 
997 void TRootSniffer::ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store,
998  Bool_t only_fields)
999 {
1000  TRootSnifferScanRec rec;
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 
1037 void *TRootSniffer::FindInHierarchy(const char *path, TClass **cl, TDataMember **member, Int_t *chld)
1038 {
1039  TRootSnifferStore store;
1040 
1041  TRootSnifferScanRec rec;
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
1074  fCurrentRestrict = store.GetResRestrict();
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 
1095 ULong_t TRootSniffer::GetItemHash(const char *itemname)
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 
1128 Bool_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 
1160 Bool_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 
1250 Bool_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 
1270 Bool_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 
1278 TString 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 
1311 Bool_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 
1331 Bool_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 
1432 Bool_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 
1458 Bool_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 
1479 Bool_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 
1533 TObject *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 
1584 TFolder *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 
1612 Bool_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 
1651 Bool_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 
1676 Bool_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 
1754 Bool_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 
1779 const 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 
1795 const 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 
1834 Bool_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 }
TString fItemName
! name of current item
Definition: TRootSniffer.h:46
Bool_t RegisterObject(const char *subfolder, TObject *obj)
Register object in subfolder structure subfolder parameter can have many levels like: ...
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
const char * item_prop_user
A TFolder object is a collection of objects and folders.
Definition: TFolder.h:30
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. ...
An array of TObjects.
Definition: TObjArray.h:37
void ScanCollection(TRootSnifferScanRec &rec, TCollection *lst, const char *foldername=nullptr, TCollection *keys_lst=nullptr)
scan collection content
Bool_t CanExploreItem(const char *path)
Method returns true when object has childs or one could try to expand item.
virtual TList * GetListOfKeys() const
Definition: TDirectory.h:160
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
virtual ULong_t GetItemHash(const char *itemname)
Get hash function for specified item used to detect any changes in the specified object.
Bool_t IsItemField(TObject *obj) const
return true when object is TNamed with kItemField bit set such objects used to keep field values for ...
UInt_t fMask
! defines operation kind
Definition: TRootSniffer.h:43
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.
void BeforeNextChild()
indicates that new child for current element will be started
TClass * GetResClass() const
Collectable string class.
Definition: TObjString.h:28
Bool_t IsReadyForResult() const
Checks if result will be accepted.
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 &#39;path&#39; specifies object or object membe...
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...
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
Storage of hierarchy scan in TRootSniffer in JSON format.
const Ssiz_t kNPOS
Definition: RtypesCore.h:111
This class represents a WWW compatible URL.
Definition: TUrl.h:35
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:687
normal scan of hierarchy
Definition: TRootSniffer.h:34
virtual const char * GetClassName() const
Definition: TKey.h:72
void * GetResPtr() const
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
virtual Bool_t CanDrawClass(TClass *)
Definition: TRootSniffer.h:157
const char * GetAutoLoad() const
return name of configured autoload scripts (or 0)
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
virtual void Remove(TObject *obj)
Remove object from this folder. obj must be a TObject or a TFolder.
Definition: TFolder.cxx:466
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
Definition: TList.cxx:97
TString DecodeUrlOptionValue(const char *value, Bool_t remove_quotes=kTRUE)
method replaces all kind of special symbols, which could appear in URL options
Bool_t SetFoundResult(void *obj, TClass *cl, TDataMember *member=nullptr)
Set found element with class and datamember (optional)
#define gROOT
Definition: TROOT.h:415
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
Bool_t HasRestriction(const char *item_name)
Made fast check if item with specified name is in restriction list If returns true, requires precise check with CheckRestriction() method.
Basic string class.
Definition: TString.h:131
#define f(i)
Definition: RSha256.hxx:104
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:59
search for specified item (only objects and collections)
Definition: TRootSniffer.h:36
virtual void BeforeNextChild(Int_t, Int_t, Int_t)
void Restrict(const char *path, const char *options)
Restrict access to the specified location.
Bool_t UnregisterObject(TObject *obj)
unregister (remove) object from folders structures folder itself will remain even when it will be emp...
#define ROOT_VERSION_CODE
Definition: RVersion.h:21
Int_t fRestriction
! restriction 0 - default, 1 - read-only, 2 - full access
Definition: TRootSniffer.h:48
Abstract interface for storage of hierarchy scan in TRootSniffer.
TString fCurrentAllowedMethods
! list of allowed methods, extracted when analyzed object restrictions
Definition: TRootSniffer.h:126
Bool_t CreateItem(const char *fullname, const char *title)
create item element
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition: TString.cxx:638
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:575
expand of specified item - allowed to scan object members
Definition: TRootSniffer.h:35
if object in a list can be deleted
Definition: TObject.h:58
Bool_t SetResult(void *obj, TClass *cl, TDataMember *member=nullptr)
Obsolete, use SetFoundResult instead.
void CloseNode()
close started node
Bool_t CanExpandItem()
Returns true when item can be expanded.
TFolder * GetTopFolder(Bool_t force=kFALSE)
Returns top TFolder instance for the sniffer.
const char * item_prop_rootversion
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2729
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
Bool_t IsReadOnly(Bool_t dflt=kTRUE)
Returns read-only flag for current item.
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:128
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
virtual void ScanObjectChilds(TRootSnifferScanRec &rec, TObject *obj)
scans object childs (if any) here one scans collection, branches, trees and so on ...
Bool_t SetItemField(const char *fullname, const char *name, const char *value)
set field for specified item
void Class()
Definition: Class.C:29
THttpCallArg * fCurrentArg
! current http arguments (if any)
Definition: TRootSniffer.h:124
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:414
Bool_t fReadOnly
! indicate if sniffer allowed to change ROOT structures - like read objects from file ...
Definition: TRootSniffer.h:121
Bool_t ScanOnlyFields() const
return true when only fields are scanned by the sniffer
Definition: TRootSniffer.h:66
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...
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
virtual void ScanKeyProperties(TRootSnifferScanRec &rec, TKey *key, TObject *&obj, TClass *&obj_class)
scans key properties in special cases load objects from the file
const char * item_prop_kind
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...
Bool_t CanDrawItem(const char *path)
Method verifies if object can be drawn.
const char * item_prop_typename
TFolder * GetSubFolder(const char *foldername, Bool_t force=kFALSE)
creates subfolder where objects can be registered
TString & Append(const char *cs)
Definition: TString.h:559
virtual void Add(TObject *obj)
Add object to this folder. obj must be a TObject or a TFolder.
Definition: TFolder.cxx:170
Long_t GetThisOffset() const
Definition: TRealData.h:55
const char * fSearchPath
! current path searched
Definition: TRootSniffer.h:44
const char * GetUserName() const
return authenticated user name (0 - when no authentication)
Definition: THttpCallArg.h:149
virtual void RecursiveRemove(TObject *obj)
Recursively remove object from a folder.
Definition: TFolder.cxx:458
virtual TList * GetList() const
Definition: TDirectory.h:159
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:24
void SetRootClass(TClass *cl)
Mark item with ROOT class and correspondent streamer info.
const char * GetValueFromOptions(const char *key) const
Return a value for a given key from the URL options.
Definition: TUrl.cxx:651
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
Int_t fNumChilds
! number of childs
Definition: TRootSniffer.h:54
virtual ~TRootSniffer()
destructor
TCollection * GetListOfFolders() const
Definition: TFolder.h:55
Storage of hierarchy scan in TRootSniffer in XML format.
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
A doubly linked list.
Definition: TList.h:44
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...
Int_t GetResNumChilds() const
virtual Bool_t ExecuteCmd(const std::string &path, const std::string &options, std::string &res)
Execute command marked as _kind==&#39;Command&#39;.
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition: TClass.cxx:1961
Int_t GetResRestrict() const
const char * item_prop_arraydim
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.
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...
const char * item_prop_hidden
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
const void * GetPostData() const
return pointer on posted with request data
Definition: THttpCallArg.h:137
TRootSniffer(const char *name, const char *objpath="Objects")
constructor
Int_t fLevel
! current level of hierarchy
Definition: TRootSniffer.h:45
const char * item_prop_realname
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:443
TDataMember * GetDataMember() const
Definition: TRealData.h:53
Collection abstract base class.
Definition: TCollection.h:63
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2289
const char * item_prop_title
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.
TString fObjectsPath
! default path for registered objects
Definition: TRootSniffer.h:120
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon)
Register command which can be executed from web interface.
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
char * Form(const char *fmt,...)
Ssiz_t Length() const
Definition: TString.h:405
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...
Int_t fNumFields
! number of fields
Definition: TRootSniffer.h:53
The TRealData class manages the effective list of all data members for a given class.
Definition: TRealData.h:30
Int_t GetArrayDim() const
Return number of array dimensions.
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
virtual void ScanRoot(TRootSnifferScanRec &rec)
scan complete ROOT objects hierarchy For the moment it includes objects in gROOT directory and list o...
mask for actions, only actions copied to child rec
Definition: TRootSniffer.h:39
virtual ~TRootSnifferScanRec()
destructor
Long_t Property() const
Set TObject::fBits and fStreamerType to cache information about the class.
Definition: TClass.cxx:5833
void ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store, Bool_t only_fields=kFALSE)
Method scans normal objects, registered in ROOT.
if object destructor must call RecursiveRemove()
Definition: TObject.h:60
TString fAutoLoad
! scripts names, which are add as _autoload parameter to h.json request
Definition: TRootSniffer.h:128
void ScanObjectMembers(TRootSnifferScanRec &rec, TClass *cl, char *ptr)
scan object data members some members like enum or static members will be excluded ...
TRootSnifferScanRec()
constructor
const Bool_t kFALSE
Definition: RtypesCore.h:88
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
TString & Remove(Ssiz_t pos)
Definition: TString.h:668
long Long_t
Definition: RtypesCore.h:50
int Ssiz_t
Definition: RtypesCore.h:63
TList fItemsNames
! list of created items names, need to avoid duplication
Definition: TRootSniffer.h:47
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2197
void BuildFullName(TString &buf, TRootSnifferScanRec *prnt=nullptr)
Produces full name for the current item.
#define ClassImp(name)
Definition: Rtypes.h:365
TDataMember * GetResMember() const
TRootSnifferStore * fStore
! object to store results
Definition: TRootSniffer.h:50
Describe directory structure in memory.
Definition: TDirectory.h:34
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...
TList * GetListOfRealData() const
Definition: TClass.h:418
TNamed()
Definition: TNamed.h:36
unsigned long ULong_t
Definition: RtypesCore.h:51
TRootSnifferScanRec * fParent
! pointer on parent record
Definition: TRootSniffer.h:42
#define R__LOCKGUARD(mutex)
virtual void CreateNode(Int_t, const char *)
int CompareTo(const char *cs, ECaseCompare cmp=kExact) const
Compare a string to char *cs2.
Definition: TString.cxx:418
void ParseOptions() const
Parse URL options into a key/value map.
Definition: TUrl.cxx:617
TCanvas * slash()
Definition: slash.C:1
virtual TObject * FindObject(const char *name) const
Search object identified by name in the tree of folders inside this folder.
Definition: TFolder.cxx:310
Bool_t Done() const
Method indicates that scanning can be interrupted while result is set.
virtual void AddAfter(const TObject *after, TObject *obj)
Insert object after object after in the list.
Definition: TList.cxx:247
Mother of all ROOT objects.
Definition: TObject.h:37
Int_t Depth() const
Returns depth of hierarchy.
virtual void SetField(Int_t, const char *, const char *, Bool_t)
Int_t IsSTLContainer()
The return type is defined in TDictionary (kVector, kList, etc.)
void SetField(const char *name, const char *value, Bool_t with_quotes=kTRUE)
Set item field only when creating is specified.
void SetAutoLoad(const char *scripts="")
When specified, _autoload attribute will be always add to top element of h.json/h.hml requests Used to instruct browser automatically load special code.
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:401
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition: TKey.cxx:732
virtual void Add(TObject *obj)
Definition: TList.h:87
auto * l
Definition: textangle.C:4
Definition: file.py:1
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
Bool_t CanSetFields() const
return true when fields could be set to the hierarchy item
Definition: TRootSniffer.h:63
virtual void CloseNode(Int_t, Int_t)
void SetOptions(const char *opt)
Definition: TUrl.h:89
Bool_t fHasMore
! indicates that potentially there are more items can be found
Definition: TRootSniffer.h:51
const char * item_prop_more
virtual Int_t GetLast() const
Returns index of last object in collection.
virtual Bool_t HasStreamerInfo() const
Definition: TRootSniffer.h:159
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
R__EXTERN Int_t gDebug
Definition: Rtypes.h:91
Int_t Atoi() const
Return integer value of string.
Definition: TString.cxx:1921
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...
void CreateOwnTopFolder()
Create own TFolder structures independent from gROOT This allows to have many independent TRootSniffe...
Bool_t fNodeStarted
! indicate if node was started
Definition: TRootSniffer.h:52
const char * item_prop_autoload
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:663
Short_t GetCycle() const
Return cycle number associated to this key.
Definition: TKey.cxx:571
virtual void ScanObjectProperties(TRootSnifferScanRec &rec, TObject *obj)
scans object properties here such fields as _autoload or _icon properties depending on class or objec...
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:357
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
void MakeItemName(const char *objname, TString &itemname)
Construct item name, using object name as basis.
virtual const char * GetName() const
Returns name of object.
Definition: TRealData.h:52
void SetCurrentCallArg(THttpCallArg *arg)
set current http arguments, which then used in different process methods For instance, if user authorized with some user name, depending from restrictions some objects will be invisible or user get full access to the element
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:164
Bool_t IsaPointer() const
Return true if data member is a pointer.
Long_t GetPostDataLength() const
return length of posted with request data
Definition: THttpCallArg.h:140
const Bool_t kTRUE
Definition: RtypesCore.h:87
void SetScanGlobalDir(Bool_t on=kTRUE)
When enabled (default), sniffer scans gROOT for files, canvases, histograms.
Definition: TRootSniffer.h:201
if set, only fields for specified item will be set (but all fields)
Definition: TRootSniffer.h:38
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 fCurrentRestrict
! current restriction for last-found object
Definition: TRootSniffer.h:125
const Int_t n
Definition: legend1.C:16
Bool_t IsScanGlobalDir() const
Returns true when sniffer allowed to scan global directories.
Definition: TRootSniffer.h:208
const char * GetItemField(TFolder *parent, TObject *item, const char *name)
return field for specified item
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3363
check if there childs, very similar to search
Definition: TRootSniffer.h:37
char name[80]
Definition: TGX11.cxx:109
const char * cnt
Definition: TXMLSetup.cxx:74
void CreateNode(const char *_node_name)
Starts new node, must be closed at the end.
TObject * GetItem(const char *fullname, TFolder *&parent, Bool_t force=kFALSE, Bool_t within_objects=kTRUE)
return item from the subfolders structure
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
TList fRestrictions
! list of restrictions for different locations
Definition: TRootSniffer.h:127
TObject * FindTObjectInHierarchy(const char *path)
Search element in hierarchy, derived from TObject.
const char * Data() const
Definition: TString.h:364
std::unique_ptr< TFolder > fTopFolder
! own top TFolder object, used for registering objects
Definition: TRootSniffer.h:123