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