Logo ROOT   6.07/09
Reference Guide
TRootSniffer.cxx
Go to the documentation of this file.
1 // $Id$
2 // Author: Sergey Linev 22/12/2013
3 
4 #include "TRootSniffer.h"
5 
6 #include "TH1.h"
7 #include "TGraph.h"
8 #include "TProfile.h"
9 #include "TCanvas.h"
10 #include "TFile.h"
11 #include "TKey.h"
12 #include "TList.h"
13 #include "TMemFile.h"
14 #include "TStreamerInfo.h"
15 #include "TBufferFile.h"
16 #include "TBufferJSON.h"
17 #include "TBufferXML.h"
18 #include "TROOT.h"
19 #include "TTimer.h"
20 #include "TFolder.h"
21 #include "TTree.h"
22 #include "TBranch.h"
23 #include "TLeaf.h"
24 #include "TClass.h"
25 #include "TMethod.h"
26 #include "TFunction.h"
27 #include "TMethodArg.h"
28 #include "TMethodCall.h"
29 #include "TRealData.h"
30 #include "TDataMember.h"
31 #include "TDataType.h"
32 #include "TBaseClass.h"
33 #include "TObjString.h"
34 #include "TUrl.h"
35 #include "TImage.h"
36 #include "RZip.h"
37 #include "RVersion.h"
38 #include "TRootSnifferStore.h"
39 #include "THttpCallArg.h"
40 
41 #include <stdlib.h>
42 #include <vector>
43 #include <string.h>
44 
45 const char *item_prop_kind = "_kind";
46 const char *item_prop_more = "_more";
47 const char *item_prop_title = "_title";
48 const char *item_prop_hidden = "_hidden";
49 const char *item_prop_typename = "_typename";
50 const char *item_prop_arraydim = "_arraydim";
51 const char *item_prop_realname = "_realname"; // real object name
52 const char *item_prop_user = "_username";
53 const char *item_prop_autoload = "_autoload";
54 const char *item_prop_rootversion = "_root_version";
55 
56 
57 // ============================================================================
58 
59 //////////////////////////////////////////////////////////////////////////
60 // //
61 // TRootSnifferScanRec //
62 // //
63 // Structure used to scan hierarchies of ROOT objects //
64 // Represents single level of hierarchy //
65 // //
66 //////////////////////////////////////////////////////////////////////////
67 
68 ////////////////////////////////////////////////////////////////////////////////
69 /// constructor
70 
72  fParent(0),
73  fMask(0),
74  fSearchPath(0),
75  fLevel(0),
76  fItemName(),
77  fItemsNames(),
78  fRestriction(0),
79  fStore(0),
80  fHasMore(kFALSE),
81  fNodeStarted(kFALSE),
82  fNumFields(0),
83  fNumChilds(0)
84 {
86 }
87 
88 ////////////////////////////////////////////////////////////////////////////////
89 /// destructor
90 
92 {
93  CloseNode();
94 }
95 
96 ////////////////////////////////////////////////////////////////////////////////
97 /// record field for current element
98 
99 void TRootSnifferScanRec::SetField(const char *name, const char *value, Bool_t with_quotes)
100 {
101  if (CanSetFields()) fStore->SetField(fLevel, name, value, with_quotes);
102  fNumFields++;
103 }
104 
105 ////////////////////////////////////////////////////////////////////////////////
106 /// indicates that new child for current element will be started
107 
109 {
111  fNumChilds++;
112 }
113 
114 ////////////////////////////////////////////////////////////////////////////////
115 /// constructs item name from object name
116 /// if special symbols like '/', '#', ':', '&', '?' are used in object name
117 /// they will be replaced with '_'.
118 /// To avoid item name duplication, additional id number can be appended
119 
120 void TRootSnifferScanRec::MakeItemName(const char *objname, TString &itemname)
121 {
122  std::string nnn = objname;
123 
124  size_t pos;
125 
126  // replace all special symbols which can make problem to navigate in hierarchy
127  while ((pos = nnn.find_first_of("- []<>#:&?/\'\"\\")) != std::string::npos)
128  nnn.replace(pos, 1, "_");
129 
130  itemname = nnn.c_str();
131  Int_t cnt = 0;
132 
133  while (fItemsNames.FindObject(itemname.Data())) {
134  itemname.Form("%s_%d", nnn.c_str(), cnt++);
135  }
136 
137  fItemsNames.Add(new TObjString(itemname.Data()));
138 }
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// Produce full name, including all parents
142 
144 {
145  if (!prnt) prnt = fParent;
146 
147  if (prnt) {
148  prnt->BuildFullName(buf);
149 
150  buf.Append("/");
151  buf.Append(fItemName);
152  }
153 }
154 
155 
156 ////////////////////////////////////////////////////////////////////////////////
157 /// creates new node with specified name
158 /// if special symbols like "[]&<>" are used, node name
159 /// will be replaced by default name like "extra_item_N" and
160 /// original node name will be recorded as "_original_name" field
161 /// Optionally, object name can be recorded as "_realname" field
162 
163 void TRootSnifferScanRec::CreateNode(const char *_node_name)
164 {
165  if (!CanSetFields()) return;
166 
168 
170 
171  if (fStore) fStore->CreateNode(fLevel, _node_name);
172 }
173 
174 ////////////////////////////////////////////////////////////////////////////////
175 /// close started node
176 
178 {
179  if (fStore && fNodeStarted) {
182  }
183 }
184 
185 ////////////////////////////////////////////////////////////////////////////////
186 /// set root class name as node kind
187 /// in addition, path to master item (streamer info) specified
188 /// Such master item required to correctly unstream data on JavaScript
189 
191 {
192  if ((cl != 0) && CanSetFields())
193  SetField(item_prop_kind, TString::Format("ROOT.%s", cl->GetName()));
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 /// returns true if scanning is done
198 /// Can happen when searched element is found
199 
201 {
202  if (fStore == 0)
203  return kFALSE;
204 
205  if ((fMask & kSearch) && fStore->GetResPtr())
206  return kTRUE;
207 
208  if ((fMask & kCheckChilds) && fStore->GetResPtr() &&
209  (fStore->GetResNumChilds() >= 0))
210  return kTRUE;
211 
212  return kFALSE;
213 }
214 
215 ////////////////////////////////////////////////////////////////////////////////
216 /// Checks if result will be accepted.
217 /// Used to verify if sniffer should read object from the file
218 
220 {
221  if (Done()) return kFALSE;
222 
223  // only when doing search, result will be propagated
224  if ((fMask & (kSearch | kCheckChilds)) == 0) return kFALSE;
225 
226  // only when full search path is scanned
227  if (fSearchPath != 0) return kFALSE;
228 
229  if (fStore == 0) return kFALSE;
230 
231  return kTRUE;
232 }
233 
234 ////////////////////////////////////////////////////////////////////////////////
235 /// set results of scanning
236 /// when member should be specified, use SetFoundResult instead
237 
239 {
240  if (member==0) return SetFoundResult(obj, cl);
241 
242  fStore->Error("SetResult", "When member specified, pointer on object (not member) should be provided; use SetFoundResult");
243  return kFALSE;
244 }
245 
246 ////////////////////////////////////////////////////////////////////////////////
247 /// set results of scanning
248 /// when member specified, obj is pointer on object to which member belongs
249 
251 {
252  if (Done()) return kTRUE;
253 
254  if (!IsReadyForResult()) return kFALSE;
255 
256  fStore->SetResult(obj, cl, member, fNumChilds, fRestriction);
257 
258  return Done();
259 }
260 
261 
262 ////////////////////////////////////////////////////////////////////////////////
263 /// returns current depth of scanned hierarchy
264 
266 {
267  Int_t cnt = 0;
268  const TRootSnifferScanRec *rec = this;
269  while (rec->fParent) {
270  rec = rec->fParent;
271  cnt++;
272  }
273 
274  return cnt;
275 }
276 
277 ////////////////////////////////////////////////////////////////////////////////
278 /// returns true if current item can be expanded - means one could explore
279 /// objects members
280 
282 {
283  if (fMask & (kExpand | kSearch | kCheckChilds)) return kTRUE;
284 
285  if (!fHasMore) return kFALSE;
286 
287  // if parent has expand mask, allow to expand item
288  if (fParent && (fParent->fMask & kExpand)) return kTRUE;
289 
290  return kFALSE;
291 }
292 
293 ////////////////////////////////////////////////////////////////////////////////
294 /// returns read-only flag for current item
295 /// Depends from default value and current restrictions
296 
298 {
299  if (fRestriction==0) return dflt;
300 
301  return fRestriction!=2;
302 }
303 
304 ////////////////////////////////////////////////////////////////////////////////
305 /// Method verifies if new level of hierarchy
306 /// should be started with provided object.
307 /// If required, all necessary nodes and fields will be created
308 /// Used when different collection kinds should be scanned
309 
311  const char *obj_name, TRootSniffer* sniffer)
312 {
313  if (super.Done()) return kFALSE;
314 
315  if ((obj != 0) && (obj_name == 0)) obj_name = obj->GetName();
316 
317  // exclude zero names
318  if ((obj_name == 0) || (*obj_name == 0)) return kFALSE;
319 
320  const char *full_name = 0;
321 
322  // remove slashes from file names
323  if (obj && obj->InheritsFrom(TDirectoryFile::Class())) {
324  const char *slash = strrchr(obj_name, '/');
325  if (slash != 0) {
326  full_name = obj_name;
327  obj_name = slash + 1;
328  if (*obj_name == 0) 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) return kFALSE;
340  }
341 
342  fParent = &super;
343  fLevel = super.fLevel;
344  fStore = super.fStore;
345  fSearchPath = super.fSearchPath;
346  fMask = super.fMask & kActions;
347  if (fRestriction==0) fRestriction = super.fRestriction; // get restriction from parent
348  Bool_t topelement(kFALSE);
349 
350  if (fMask & kScan) {
351  // if scanning only fields, ignore all childs
352  if (super.ScanOnlyFields()) return kFALSE;
353  // only when doing scan, increment level, used for text formatting
354  fLevel++;
355  } else {
356  if (fSearchPath == 0) return kFALSE;
357 
358  if (strncmp(fSearchPath, fItemName.Data(), fItemName.Length()) != 0)
359  return kFALSE;
360 
361  const char *separ = fSearchPath + fItemName.Length();
362 
363  Bool_t isslash = kFALSE;
364  while (*separ == '/') {
365  separ++;
366  isslash = kTRUE;
367  }
368 
369  if (*separ == 0) {
370  fSearchPath = 0;
371  if (fMask & kExpand) {
372  topelement = kTRUE;
373  fMask = (fMask & kOnlyFields) | kScan;
374  fHasMore = (fMask & kOnlyFields) == 0;
375  }
376  } else {
377  if (!isslash) return kFALSE;
378  fSearchPath = separ;
379  }
380  }
381 
383 
384  if ((obj_name != 0) && (fItemName != obj_name))
385  SetField(item_prop_realname, obj_name);
386 
387  if (full_name != 0)
388  SetField("_fullname", full_name);
389 
390  if (topelement)
392 
393  if (topelement && sniffer->GetAutoLoad())
395 
396  return kTRUE;
397 }
398 
399 
400 // ====================================================================
401 
402 //////////////////////////////////////////////////////////////////////////
403 // //
404 // TRootSniffer //
405 // //
406 // Sniffer of ROOT objects, data provider for THttpServer //
407 // Provides methods to scan different structures like folders, //
408 // directories, files, trees, collections //
409 // Can locate objects (or its data member) per name //
410 // Can be extended to application-specific classes //
411 // //
412 //////////////////////////////////////////////////////////////////////////
413 
415 
416 ////////////////////////////////////////////////////////////////////////////////
417 /// constructor
418 
419 TRootSniffer::TRootSniffer(const char *name, const char *objpath) :
420  TNamed(name, "sniffer of root objects"),
421  fObjectsPath(objpath),
422  fMemFile(0),
423  fSinfo(0),
424  fReadOnly(kTRUE),
425  fScanGlobalDir(kTRUE),
426  fCurrentArg(0),
427  fCurrentRestrict(0),
428  fCurrentAllowedMethods(0),
429  fRestrictions(),
430  fAutoLoad()
431 {
432  fRestrictions.SetOwner(kTRUE);
433 }
434 
435 ////////////////////////////////////////////////////////////////////////////////
436 /// destructor
437 
439 {
440  if (fSinfo) {
441  delete fSinfo;
442  fSinfo = 0;
443  }
444 
445  if (fMemFile) {
446  delete fMemFile;
447  fMemFile = 0;
448  }
449 }
450 
451 ////////////////////////////////////////////////////////////////////////////////
452 /// set current http arguments, which then used in different process methods
453 /// For instance, if user authorized with some user name,
454 /// depending from restrictions some objects will be invisible
455 /// or user get full access to the element
456 
458 {
459  fCurrentArg = arg;
460  fCurrentRestrict = 0;
461  fCurrentAllowedMethods = "";
462 }
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 /// Restrict access to the specified location
466 ///
467 /// Hides or provides read-only access to different parts of the hierarchy
468 /// Restriction done base on user-name specified with http requests
469 /// Options can be specified in URL style (separated with &)
470 /// Following parameters can be specified:
471 /// visible = [all|user(s)] - make item visible for all users or only specified user
472 /// hidden = [all|user(s)] - make item hidden from all users or only specified user
473 /// readonly = [all|user(s)] - make item read-only for all users or only specified user
474 /// allow = [all|user(s)] - make full access for all users or only specified user
475 /// allow_method = method(s) - allow method(s) execution even when readonly flag specified for the object
476 /// Like make command seen by all but can be executed only by admin
477 /// sniff->Restrict("/CmdReset","allow=admin");
478 /// Or fully hide command from guest account
479 /// sniff->Restrict("/CmdRebin","hidden=guest");
480 
481 void TRootSniffer::Restrict(const char* path, const char* options)
482 {
483  const char* rslash = strrchr(path,'/');
484  if (rslash) rslash++;
485  if ((rslash==0) || (*rslash==0)) rslash = path;
486 
487  fRestrictions.Add(new TNamed(rslash, TString::Format("%s%s%s", path,"%%%",options).Data()));
488 }
489 
490 ////////////////////////////////////////////////////////////////////////////////
491 /// When specified, _autoload attribute will be always add
492 /// to top element of h.json/h.hml requests
493 /// Used to instruct browser automatically load special code
494 
495 void TRootSniffer::SetAutoLoad(const char* scripts)
496 {
497  fAutoLoad = scripts!=0 ? scripts : "";
498 }
499 
500 ////////////////////////////////////////////////////////////////////////////////
501 /// return name of configured autoload scripts (or 0)
502 
503 const char* TRootSniffer::GetAutoLoad() const
504 {
505  return fAutoLoad.Length() > 0 ? fAutoLoad.Data() : 0;
506 }
507 
508 ////////////////////////////////////////////////////////////////////////////////
509 /// Made fast check if item with specified name is in restriction list
510 /// If returns true, requires precise check with CheckRestriction() method
511 
512 Bool_t TRootSniffer::HasRestriction(const char* item_name)
513 {
514  if ((item_name==0) || (*item_name==0) || (fCurrentArg==0)) return kFALSE;
515 
516  return fRestrictions.FindObject(item_name)!=0;
517 }
518 
519 ////////////////////////////////////////////////////////////////////////////////
520 /// return 2 when option match to current user name
521 /// return 1 when option==all
522 /// return 0 when option does not match user name
523 
525 {
526  const char* username = fCurrentArg ? fCurrentArg->GetUserName() : 0;
527 
528  if ((username==0) || (option == 0) || (*option==0)) return 0;
529 
530  if (strcmp(option,"all") == 0) return 1;
531 
532  if (strcmp(username, option) == 0) return 2;
533 
534  if (strstr(option, username) == 0) return -1;
535 
536  TObjArray* arr = TString(option).Tokenize(",");
537 
538  Bool_t find = arr->FindObject(username) != 0;
539 
540  delete arr;
541 
542  return find ? 2 : -1;
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// Checked if restriction is applied to the item
547 /// full_item_name should have full path to the item
548 ///
549 /// Returns -1 - object invisible, cannot be accessed or listed
550 /// 0 - no explicit restrictions, use default
551 /// 1 - read-only access
552 /// 2 - full access
553 
554 Int_t TRootSniffer::CheckRestriction(const char* full_item_name)
555 {
556  if ((full_item_name==0) || (*full_item_name==0)) return 0;
557 
558  const char* item_name = strrchr(full_item_name,'/');
559  if (item_name) item_name++;
560  if ((item_name==0) || (*item_name==0)) item_name = full_item_name;
561 
562  TString pattern1 = TString("*/") + item_name + "%%%";
563  TString pattern2 = TString(full_item_name) + "%%%";
564 
565  const char* options = 0;
566  TIter iter(&fRestrictions);
567  TObject* obj;
568 
569  while ((obj = iter()) != 0) {
570  const char* title = obj->GetTitle();
571 
572  if (strstr(title,pattern1.Data())==title) { options = title + pattern1.Length(); break; }
573  if (strstr(title,pattern2.Data())==title) { options = title + pattern2.Length(); break; }
574  }
575 
576  if (options==0) return 0;
577 
578  TUrl url;
579  url.SetOptions(options);
580  url.ParseOptions();
581 
582  Int_t can_see = WithCurrentUserName(url.GetValueFromOptions("visible")) -
583  WithCurrentUserName(url.GetValueFromOptions("hidden"));
584 
585  Int_t can_access = WithCurrentUserName(url.GetValueFromOptions("allow")) -
586  WithCurrentUserName(url.GetValueFromOptions("readonly"));
587 
588  if (can_access > 0) return 2; // first of all, if access enabled, provide it
589  if (can_see < 0) return -1; // if object to be hidden, do it
590 
591  const char* methods = url.GetValueFromOptions("allow_method");
592  if (methods!=0) fCurrentAllowedMethods = methods;
593 
594  if (can_access < 0) return 1; // read-only access
595 
596  return 0; // default behavior
597 }
598 
599 ////////////////////////////////////////////////////////////////////////////////
600 /// scan object data members
601 /// some members like enum or static members will be excluded
602 
604 {
605  if ((cl == 0) || (ptr == 0) || rec.Done()) return;
606 
607  // ensure that real class data (including parents) exists
608  if (!(cl->Property() & kIsAbstract)) cl->BuildRealData();
609 
610  // scan only real data
611  TObject *obj = 0;
612  TIter iter(cl->GetListOfRealData());
613  while ((obj = iter()) != 0) {
614  TRealData *rdata = dynamic_cast<TRealData *>(obj);
615  if ((rdata == 0) || strchr(rdata->GetName(),'.')) continue;
616 
617  TDataMember *member = rdata->GetDataMember();
618  // exclude enum or static variables
619  if ((member == 0) || (member->Property() & (kIsStatic | kIsEnum | kIsUnion))) continue;
620  char *member_ptr = ptr + rdata->GetThisOffset();
621 
622  if (member->IsaPointer()) member_ptr = *((char **) member_ptr);
623 
624  TRootSnifferScanRec chld;
625 
626  if (chld.GoInside(rec, member, 0, this)) {
627 
628  TClass *mcl = (member->IsBasic() || member->IsSTLContainer()) ? 0 :
629  gROOT->GetClass(member->GetTypeName());
630 
631  Int_t coll_offset = mcl ? mcl->GetBaseClassOffset(TCollection::Class()) : -1;
632  if (coll_offset >= 0) {
633  chld.SetField(item_prop_more, "true", kFALSE);
634  chld.fHasMore = kTRUE;
635  }
636 
637  if (chld.SetFoundResult(ptr, cl, member)) break;
638 
639  const char *title = member->GetTitle();
640  if ((title != 0) && (strlen(title) != 0))
641  chld.SetField(item_prop_title, title);
642 
643  if (member->GetTypeName())
644  chld.SetField(item_prop_typename, member->GetTypeName());
645 
646  if (member->GetArrayDim() > 0) {
647  // store array dimensions in form [N1,N2,N3,...]
648  TString dim("[");
649  for (Int_t n = 0; n < member->GetArrayDim(); n++) {
650  if (n > 0) dim.Append(",");
651  dim.Append(TString::Format("%d", member->GetMaxIndex(n)));
652  }
653  dim.Append("]");
654  chld.SetField(item_prop_arraydim, dim, kFALSE);
655  } else
656  if (member->GetArrayIndex()!=0) {
657  TRealData *idata = cl->GetRealData(member->GetArrayIndex());
658  TDataMember *imember = (idata!=0) ? idata->GetDataMember() : 0;
659  if ((imember!=0) && (strcmp(imember->GetTrueTypeName(),"int")==0)) {
660  Int_t arraylen = *((int *) (ptr + idata->GetThisOffset()));
661  chld.SetField(item_prop_arraydim, TString::Format("[%d]", arraylen), kFALSE);
662  }
663  }
664 
665  chld.SetRootClass(mcl);
666 
667  if (chld.CanExpandItem()) {
668  if (coll_offset >= 0) {
669  // chld.SetField("#members", "true", kFALSE);
670  ScanCollection(chld, (TCollection *)(member_ptr + coll_offset));
671  }
672  }
673 
674  if (chld.SetFoundResult(ptr, cl, member)) break;
675  }
676  }
677 }
678 
679 ////////////////////////////////////////////////////////////////////////////////
680 /// scans object properties
681 /// here such fields as _autoload or _icon properties depending on class or object name could be assigned
682 /// By default properties, coded in the Class title are scanned. Example:
683 /// ClassDef(UserClassName, 1) // class comments *SNIFF* _field1=value _field2="string value"
684 /// Here *SNIFF* mark is important. After it all expressions like field=value are parsed
685 /// One could use double quotes to code string values with spaces.
686 /// Fields separated from each other with spaces
687 
689 {
690  TClass* cl = obj ? obj->IsA() : 0;
691 
692  if (cl && cl->InheritsFrom(TLeaf::Class())) {
693  rec.SetField("_more", "false");
694  rec.SetField("_can_draw", "false");
695  return;
696  }
697 
698  const char* pos = strstr(cl ? cl->GetTitle() : "", "*SNIFF*");
699  if (pos==0) return;
700 
701  pos += 7;
702  while (*pos != 0) {
703  if (*pos == ' ') { pos++; continue; }
704  // first locate identifier
705  const char* pos0 = pos;
706  while ((*pos != 0) && (*pos != '=')) pos++;
707  if (*pos == 0) return;
708  TString name(pos0, pos-pos0);
709  pos++;
710  Bool_t quotes = (*pos == '\"');
711  if (quotes) pos++;
712  pos0 = pos;
713  // then value with or without quotes
714  while ((*pos != 0) && (*pos != (quotes ? '\"' : ' '))) pos++;
715  TString value(pos0, pos-pos0);
716  rec.SetField(name, value);
717  if (quotes) pos++;
718  pos++;
719  }
720 }
721 
722 ////////////////////////////////////////////////////////////////////////////////
723 /// scans object childs (if any)
724 /// here one scans collection, branches, trees and so on
725 
727 {
728  if (obj->InheritsFrom(TFolder::Class())) {
729  ScanCollection(rec, ((TFolder *) obj)->GetListOfFolders());
730  } else if (obj->InheritsFrom(TDirectory::Class())) {
731  TDirectory *dir = (TDirectory *) obj;
732  ScanCollection(rec, dir->GetList(), 0, dir->GetListOfKeys());
733  } else if (obj->InheritsFrom(TTree::Class())) {
734  if (!rec.IsReadOnly(fReadOnly)) {
735  rec.SetField("_player", "JSROOT.drawTreePlayer");
736  rec.SetField("_prereq", "jq2d");
737  }
738  ScanCollection(rec, ((TTree *) obj)->GetListOfLeaves());
739  } else if (obj->InheritsFrom(TBranch::Class())) {
740  ScanCollection(rec, ((TBranch *) obj)->GetListOfLeaves());
741  } else if (rec.CanExpandItem()) {
742  ScanObjectMembers(rec, obj->IsA(), (char *) obj);
743  }
744 }
745 
746 ////////////////////////////////////////////////////////////////////////////////
747 /// scan collection content
748 
750  const char *foldername, TCollection *keys_lst)
751 {
752  if (((lst == 0) || (lst->GetSize() == 0)) && ((keys_lst == 0) || (keys_lst->GetSize() == 0))) return;
753 
754  TRootSnifferScanRec folderrec;
755  if (foldername) {
756  if (!folderrec.GoInside(rec, 0, foldername, this)) return;
757  }
758 
759  TRootSnifferScanRec &master = foldername ? folderrec : rec;
760 
761  if (lst != 0) {
762  TIter iter(lst);
763  TObject *next = iter();
764  Bool_t isany = kFALSE;
765 
766  while (next!=0) {
767  if (IsItemField(next)) {
768  // special case - in the beginning one could have items for master folder
769  if (!isany && (next->GetName() != 0) && ((*(next->GetName()) == '_') || master.ScanOnlyFields()))
770  master.SetField(next->GetName(), next->GetTitle());
771  next = iter();
772  continue;
773  }
774 
775  isany = kTRUE;
776  TObject* obj = next;
777 
778  TRootSnifferScanRec chld;
779  if (!chld.GoInside(master, obj, 0, this)) { next = iter(); continue; }
780 
781  if (chld.SetResult(obj, obj->IsA())) return;
782 
783  Bool_t has_kind(kFALSE), has_title(kFALSE);
784 
785  ScanObjectProperties(chld, obj);
786  // now properties, coded as TNamed objects, placed after object in the hierarchy
787  while ((next = iter()) != 0) {
788  if (!IsItemField(next)) break;
789  if ((next->GetName() != 0) && ((*(next->GetName()) == '_') || chld.ScanOnlyFields())) {
790  // only fields starting with _ are stored
791  chld.SetField(next->GetName(), next->GetTitle());
792  if (strcmp(next->GetName(), item_prop_kind)==0) has_kind = kTRUE;
793  if (strcmp(next->GetName(), item_prop_title)==0) has_title = kTRUE;
794  }
795  }
796 
797  if (!has_kind) chld.SetRootClass(obj->IsA());
798  if (!has_title && (obj->GetTitle()!=0)) chld.SetField(item_prop_title, obj->GetTitle());
799 
800  ScanObjectChilds(chld, obj);
801 
802  if (chld.SetResult(obj, obj->IsA())) return;
803  }
804  }
805 
806  if (keys_lst != 0) {
807  TIter iter(keys_lst);
808  TObject *kobj(0);
809 
810  while ((kobj = iter()) != 0) {
811  TKey *key = dynamic_cast<TKey *>(kobj);
812  if (key == 0) continue;
813  TObject *obj = (lst == 0) ? 0 : lst->FindObject(key->GetName());
814 
815  // even object with the name exists, it should also match with class name
816  if ((obj!=0) && (strcmp(obj->ClassName(),key->GetClassName())!=0)) obj = 0;
817 
818  // if object of that name and of that class already in the list, ignore appropriate key
819  if ((obj != 0) && (master.fMask & TRootSnifferScanRec::kScan)) continue;
820 
821  Bool_t iskey = kFALSE;
822  // if object not exists, provide key itself for the scan
823  if (obj == 0) { obj = key; iskey = kTRUE; }
824 
825  TRootSnifferScanRec chld;
826  TString fullname = TString::Format("%s;%d", key->GetName(), key->GetCycle());
827 
828  if (chld.GoInside(master, obj, fullname.Data(), this)) {
829 
830  if (!chld.IsReadOnly(fReadOnly) && iskey && chld.IsReadyForResult()) {
831  TObject *keyobj = key->ReadObj();
832  if (keyobj != 0)
833  if (chld.SetResult(keyobj, keyobj->IsA())) return;
834  }
835 
836  if (chld.SetResult(obj, obj->IsA())) return;
837 
838  TClass *obj_class = obj->IsA();
839 
840  ScanObjectProperties(chld, obj);
841 
842  if (obj->GetTitle()!=0) chld.SetField(item_prop_title, obj->GetTitle());
843 
844  // special handling of TKey class - in non-readonly mode
845  // sniffer allowed to fetch objects
846  if (!chld.IsReadOnly(fReadOnly) && iskey) {
847  if (strcmp(key->GetClassName(), "TDirectoryFile") == 0) {
848  if (chld.fLevel == 0) {
849  TDirectory *dir = dynamic_cast<TDirectory *>(key->ReadObj());
850  if (dir != 0) {
851  obj = dir;
852  obj_class = dir->IsA();
853  }
854  } else {
855  chld.SetField(item_prop_more, "true", kFALSE);
856  chld.fHasMore = kTRUE;
857  }
858  } else {
859  obj_class = TClass::GetClass(key->GetClassName());
860  if (obj_class && obj_class->InheritsFrom(TTree::Class())) {
861  if (rec.CanExpandItem()) {
862  // it is requested to expand tree element - read it
863  obj = key->ReadObj();
864  if (obj) obj_class = obj->IsA();
865  } else {
866  rec.SetField("_player", "JSROOT.drawTreePlayerKey");
867  rec.SetField("_prereq", "jq2d");
868  // rec.SetField("_more", "true"); // one could allow to extend
869  }
870  }
871  }
872  }
873 
874  rec.SetRootClass(obj_class);
875 
876  ScanObjectChilds(chld, obj);
877 
878  // here we should know how many childs are accumulated
879  if (chld.SetResult(obj, obj_class)) return;
880  }
881  }
882  }
883 }
884 
885 ////////////////////////////////////////////////////////////////////////////////
886 /// scan complete ROOT objects hierarchy
887 /// For the moment it includes objects in gROOT directory
888 /// and list of canvases and files
889 /// Also all registered objects are included.
890 /// One could reimplement this method to provide alternative
891 /// scan methods or to extend some collection kinds
892 
894 {
895  rec.SetField(item_prop_kind, "ROOT.Session");
896  if (fCurrentArg && fCurrentArg->GetUserName())
897  rec.SetField(item_prop_user, fCurrentArg->GetUserName());
898 
899  // should be on the top while //root/http folder could have properties for itself
900  TFolder *topf = dynamic_cast<TFolder *>(gROOT->FindObject("//root/http"));
901  if (topf) {
902  rec.SetField(item_prop_title, topf->GetTitle());
903  ScanCollection(rec, topf->GetListOfFolders());
904  }
905 
906  {
907  TRootSnifferScanRec chld;
908  if (chld.GoInside(rec, 0, "StreamerInfo", this)) {
909  chld.SetField(item_prop_kind, "ROOT.TStreamerInfoList");
910  chld.SetField(item_prop_title, "List of streamer infos for binary I/O");
911  chld.SetField(item_prop_hidden, "true");
912  chld.SetField("_after_request", "JSROOT.MarkAsStreamerInfo");
913  }
914  }
915 
916  if (IsScanGlobalDir()) {
917  ScanCollection(rec, gROOT->GetList());
918 
919  ScanCollection(rec, gROOT->GetListOfCanvases(), "Canvases");
920 
921  ScanCollection(rec, gROOT->GetListOfFiles(), "Files");
922  }
923 }
924 
925 ////////////////////////////////////////////////////////////////////////////////
926 /// return true if object can be drawn
927 
929 {
930  if (cl == 0) return kFALSE;
931  if (cl->InheritsFrom(TH1::Class())) return kTRUE;
932  if (cl->InheritsFrom(TGraph::Class())) return kTRUE;
933  if (cl->InheritsFrom(TCanvas::Class())) return kTRUE;
934  if (cl->InheritsFrom(TProfile::Class())) return kTRUE;
935  return kFALSE;
936 }
937 
938 ////////////////////////////////////////////////////////////////////////////////
939 /// scan ROOT hierarchy with provided store object
940 
941 void TRootSniffer::ScanHierarchy(const char *topname, const char *path,
942  TRootSnifferStore *store, Bool_t only_fields)
943 {
945  rec.fSearchPath = path;
946  if (rec.fSearchPath) {
947  while(*rec.fSearchPath == '/') rec.fSearchPath++;
948  if (*rec.fSearchPath == 0) rec.fSearchPath = 0;
949  }
950 
951  // if path non-empty, we should find item first and than start scanning
953  if (only_fields) rec.fMask |= TRootSnifferScanRec::kOnlyFields;
954 
955  rec.fStore = store;
956 
957  rec.CreateNode(topname);
958 
959  if (rec.fSearchPath == 0)
961 
962  if ((rec.fSearchPath == 0) && (GetAutoLoad() != 0))
963  rec.SetField(item_prop_autoload, GetAutoLoad());
964 
965  ScanRoot(rec);
966 
967  rec.CloseNode();
968 }
969 
970 ////////////////////////////////////////////////////////////////////////////////
971 /// Search element with specified path
972 /// Returns pointer on element
973 /// Optionally one could obtain element class, member description
974 /// and number of childs. When chld!=0, not only element is searched,
975 /// but also number of childs are counted. When member!=0, any object
976 /// will be scanned for its data members (disregard of extra options)
977 
978 void *TRootSniffer::FindInHierarchy(const char *path, TClass **cl,
979  TDataMember **member, Int_t *chld)
980 {
981  if (IsStreamerInfoItem(path)) {
982  // special handling for streamer info
983  CreateMemFile();
984  if (cl && fSinfo) *cl = fSinfo->IsA();
985  return fSinfo;
986  }
987 
988  TRootSnifferStore store;
989 
991  rec.fSearchPath = path;
993  if (*rec.fSearchPath == '/') rec.fSearchPath++;
994  rec.fStore = &store;
995 
996  ScanRoot(rec);
997 
998  TDataMember *res_member = store.GetResMember();
999  TClass *res_cl = store.GetResClass();
1000  void *res = store.GetResPtr();
1001 
1002  if ((res_member!=0) && (res_cl!=0) && (member==0)) {
1003  res_cl = (res_member->IsBasic() || res_member->IsSTLContainer()) ? 0 :
1004  gROOT->GetClass(res_member->GetTypeName());
1005  TRealData *rdata = res_cl->GetRealData(res_member->GetName());
1006  if (rdata) {
1007  res = (char *) res + rdata->GetThisOffset();
1008  if (res_member->IsaPointer()) res = *((char **) res);
1009  } else {
1010  res = 0; // should never happen
1011  }
1012  }
1013 
1014  if (cl) *cl = res_cl;
1015  if (member) *member = res_member;
1016  if (chld) *chld = store.GetResNumChilds();
1017 
1018  // remember current restriction
1019  fCurrentRestrict = store.GetResRestrict();
1020 
1021  return res;
1022 }
1023 
1024 ////////////////////////////////////////////////////////////////////////////////
1025 /// Search element in hierarchy, derived from TObject
1026 
1028 {
1029  TClass *cl(0);
1030 
1031  void *obj = FindInHierarchy(path, &cl);
1032 
1033  return (cl != 0) && (cl->GetBaseClassOffset(TObject::Class()) == 0) ? (TObject *) obj : 0;
1034 }
1035 
1036 ////////////////////////////////////////////////////////////////////////////////
1037 /// Returns hash value for streamer infos
1038 /// At the moment - just number of items in streamer infos list.
1039 
1041 {
1042  return fSinfo ? fSinfo->GetSize() : 0;
1043 }
1044 
1045 ////////////////////////////////////////////////////////////////////////////////
1046 /// Get hash function for specified item
1047 /// used to detect any changes in the specified object
1048 
1049 ULong_t TRootSniffer::GetItemHash(const char *itemname)
1050 {
1051  if (IsStreamerInfoItem(itemname)) return GetStreamerInfoHash();
1052 
1053  TObject *obj = FindTObjectInHierarchy(itemname);
1054 
1055  return obj == 0 ? 0 : TString::Hash(obj, obj->IsA()->Size());
1056 }
1057 
1058 ////////////////////////////////////////////////////////////////////////////////
1059 /// Method verifies if object can be drawn
1060 
1062 {
1063  TClass *obj_cl(0);
1064  void *res = FindInHierarchy(path, &obj_cl);
1065  return (res != 0) && IsDrawableClass(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(0);
1075  Int_t obj_chld(-1);
1076  void *res = FindInHierarchy(path, &obj_cl, 0, &obj_chld);
1077  return (res != 0) && (obj_chld > 0);
1078 }
1079 
1080 ////////////////////////////////////////////////////////////////////////////////
1081 /// Creates TMemFile instance, which used for objects streaming
1082 /// One could not use TBufferFile directly,
1083 /// while one also require streamer infos list
1084 
1086 {
1087  if (fMemFile != 0) return;
1088 
1089  TDirectory *olddir = gDirectory;
1090  gDirectory = 0;
1091  TFile *oldfile = gFile;
1092  gFile = 0;
1093 
1094  fMemFile = new TMemFile("dummy.file", "RECREATE");
1095  gROOT->GetListOfFiles()->Remove(fMemFile);
1096 
1097  TH1F *d = new TH1F("d", "d", 10, 0, 10);
1098  fMemFile->WriteObject(d, "h1");
1099  delete d;
1100 
1101  TGraph *gr = new TGraph(10);
1102  gr->SetName("abc");
1103  // // gr->SetDrawOptions("AC*");
1104  fMemFile->WriteObject(gr, "gr1");
1105  delete gr;
1106 
1107  fMemFile->WriteStreamerInfo();
1108 
1109  // make primary list of streamer infos
1110  TList *l = new TList();
1111 
1112  l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TGraph"));
1113  l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TH1F"));
1114  l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TH1"));
1115  l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TNamed"));
1116  l->Add(gROOT->GetListOfStreamerInfo()->FindObject("TObject"));
1117 
1118  fMemFile->WriteObject(l, "ll");
1119  delete l;
1120 
1121  fMemFile->WriteStreamerInfo();
1122 
1123  fSinfo = fMemFile->GetStreamerInfoList();
1124 
1125  gDirectory = olddir;
1126  gFile = oldfile;
1127 }
1128 
1129 ////////////////////////////////////////////////////////////////////////////////
1130 /// produce JSON data for specified item
1131 /// For object conversion TBufferJSON is used
1132 
1133 Bool_t TRootSniffer::ProduceJson(const char *path, const char *options,
1134  TString &res)
1135 {
1136  if ((path == 0) || (*path == 0)) return kFALSE;
1137 
1138  if (*path == '/') path++;
1139 
1140  TUrl url;
1141  url.SetOptions(options);
1142  url.ParseOptions();
1143  Int_t compact = -1;
1144  if (url.GetValueFromOptions("compact"))
1145  compact = url.GetIntValueFromOptions("compact");
1146 
1147  TClass *obj_cl(0);
1148  TDataMember *member(0);
1149  void *obj_ptr = FindInHierarchy(path, &obj_cl, &member);
1150  if ((obj_ptr == 0) || ((obj_cl == 0) && (member == 0))) return kFALSE;
1151 
1152  res = TBufferJSON::ConvertToJSON(obj_ptr, obj_cl, compact >= 0 ? compact : 0, member ? member->GetName() : 0);
1153 
1154  return res.Length() > 0;
1155 }
1156 
1157 ////////////////////////////////////////////////////////////////////////////////
1158 /// execute command marked as _kind=='Command'
1159 
1160 Bool_t TRootSniffer::ExecuteCmd(const char *path, const char *options,
1161  TString &res)
1162 {
1163  TFolder *parent(0);
1164  TObject *obj = GetItem(path, parent, kFALSE, kFALSE);
1165 
1166  const char *kind = GetItemField(parent, obj, item_prop_kind);
1167  if ((kind == 0) || (strcmp(kind, "Command") != 0)) {
1168  if (gDebug > 0) Info("ExecuteCmd", "Entry %s is not a command", path);
1169  res = "false";
1170  return kTRUE;
1171  }
1172 
1173  const char *cmethod = GetItemField(parent, obj, "method");
1174  if ((cmethod==0) || (strlen(cmethod)==0)) {
1175  if (gDebug > 0) Info("ExecuteCmd", "Entry %s do not defines method for execution", path);
1176  res = "false";
1177  return kTRUE;
1178  }
1179 
1180  // if read-only specified for the command, it is not allowed for execution
1181  if (fRestrictions.GetLast()>=0) {
1182  FindInHierarchy(path); // one need to call method to check access rights
1183  if (fCurrentRestrict==1) {
1184  if (gDebug > 0) Info("ExecuteCmd", "Entry %s not allowed for specified user", path);
1185  res = "false";
1186  return kTRUE;
1187  }
1188  }
1189 
1190  TString method = cmethod;
1191 
1192  const char *cnumargs = GetItemField(parent, obj, "_numargs");
1193  Int_t numargs = cnumargs ? TString(cnumargs).Atoi() : 0;
1194  if (numargs > 0) {
1195  TUrl url;
1196  url.SetOptions(options);
1197  url.ParseOptions();
1198 
1199  for (Int_t n=0; n<numargs;n++) {
1200  TString argname = TString::Format("arg%d", n+1);
1201  const char* argvalue = url.GetValueFromOptions(argname);
1202  if (argvalue==0) {
1203  if (gDebug > 0) Info("ExecuteCmd", "For command %s argument %s not specified in options %s", path, argname.Data(), options);
1204  res = "false";
1205  return kTRUE;
1206  }
1207 
1208  TString svalue = DecodeUrlOptionValue(argvalue, kTRUE);
1209  argname = TString("%") + argname + TString("%");
1210  method.ReplaceAll(argname, svalue);
1211  }
1212  }
1213 
1214  if (gDebug > 0) Info("ExecuteCmd", "Executing command %s method:%s", path, method.Data());
1215 
1216  TObject *item_obj = 0;
1217  Ssiz_t separ = method.Index("/->");
1218 
1219  if (method.Index("this->") == 0) {
1220  // if command name started with this-> means method of sniffer will be executed
1221  item_obj = this;
1222  separ = 3;
1223  } else
1224  if (separ != kNPOS) {
1225  item_obj = FindTObjectInHierarchy(TString(method.Data(), separ).Data());
1226  }
1227 
1228  if (item_obj != 0) {
1229  method = TString::Format("((%s*)%lu)->%s", item_obj->ClassName(), (long unsigned) item_obj, method.Data() + separ + 3);
1230  if (gDebug > 2) Info("ExecuteCmd", "Executing %s", method.Data());
1231  }
1232 
1233  Long_t v = gROOT->ProcessLineSync(method.Data());
1234 
1235  res.Form("%ld", v);
1236 
1237  return kTRUE;
1238 }
1239 
1240 ////////////////////////////////////////////////////////////////////////////////
1241 /// produce JSON/XML for specified item
1242 /// contrary to h.json request, only fields for specified item are stored
1243 
1244 Bool_t TRootSniffer::ProduceItem(const char *path, const char *options, TString &res, Bool_t asjson)
1245 {
1246  if (asjson) {
1247  TRootSnifferStoreJson store(res, strstr(options, "compact")!=0);
1248  ScanHierarchy("top", path, &store, kTRUE);
1249  } else {
1250  TRootSnifferStoreXml store(res, strstr(options, "compact")!=0);
1251  ScanHierarchy("top", path, &store, kTRUE);
1252  }
1253  return res.Length() > 0;
1254 }
1255 
1256 
1257 ////////////////////////////////////////////////////////////////////////////////
1258 /// produce XML data for specified item
1259 /// For object conversion TBufferXML is used
1260 
1261 Bool_t TRootSniffer::ProduceXml(const char *path, const char * /*options*/,
1262  TString &res)
1263 {
1264  if ((path == 0) || (*path == 0)) return kFALSE;
1265 
1266  if (*path == '/') path++;
1267 
1268  TClass *obj_cl(0);
1269  void *obj_ptr = FindInHierarchy(path, &obj_cl);
1270  if ((obj_ptr == 0) || (obj_cl == 0)) return kFALSE;
1271 
1272  res = TBufferXML::ConvertToXML(obj_ptr, obj_cl);
1273 
1274  return res.Length() > 0;
1275 }
1276 
1277 ////////////////////////////////////////////////////////////////////////////////
1278 /// method replaces all kind of special symbols, which could appear in URL options
1279 
1280 TString TRootSniffer::DecodeUrlOptionValue(const char *value, Bool_t remove_quotes)
1281 {
1282  if ((value == 0) || (strlen(value) == 0)) return TString();
1283 
1284  TString res = value;
1285 
1286  res.ReplaceAll("%27", "\'");
1287  res.ReplaceAll("%22", "\"");
1288  res.ReplaceAll("%3E", ">");
1289  res.ReplaceAll("%3C", "<");
1290  res.ReplaceAll("%20", " ");
1291  res.ReplaceAll("%5B", "[");
1292  res.ReplaceAll("%5D", "]");
1293  res.ReplaceAll("%3D", "=");
1294 
1295  if (remove_quotes && (res.Length() > 1) &&
1296  ((res[0] == '\'') || (res[0] == '\"')) && (res[0] == res[res.Length() - 1])) {
1297  res.Remove(res.Length() - 1);
1298  res.Remove(0, 1);
1299  }
1300 
1301  return res;
1302 }
1303 
1304 ////////////////////////////////////////////////////////////////////////////////
1305 /// execute command for specified object
1306 /// options include method and extra list of parameters
1307 /// sniffer should be not-readonly to allow execution of the commands
1308 /// reskind defines kind of result 0 - debug, 1 - json, 2 - binary
1309 
1310 Bool_t TRootSniffer::ProduceExe(const char *path, const char *options, Int_t reskind, TString *res_str, void **res_ptr, Long_t *res_length)
1311 {
1312  TString *debug = (reskind == 0) ? res_str : 0;
1313 
1314  if ((path == 0) || (*path == 0)) {
1315  if (debug) debug->Append("Item name not specified\n");
1316  return debug != 0;
1317  }
1318 
1319  if (*path == '/') path++;
1320 
1321  TClass *obj_cl(0);
1322  void *obj_ptr = FindInHierarchy(path, &obj_cl);
1323  if (debug) debug->Append(TString::Format("Item:%s found:%s\n", path, obj_ptr ? "true" : "false"));
1324  if ((obj_ptr == 0) || (obj_cl == 0)) return debug != 0;
1325 
1326  TUrl url;
1327  url.SetOptions(options);
1328 
1329  const char *method_name = url.GetValueFromOptions("method");
1330  TString prototype = DecodeUrlOptionValue(url.GetValueFromOptions("prototype"), kTRUE);
1331  TString funcname = DecodeUrlOptionValue(url.GetValueFromOptions("func"), kTRUE);
1332  TMethod *method = 0;
1333  TFunction *func = 0;
1334  if (method_name != 0) {
1335  if (prototype.Length() == 0) {
1336  if (debug) debug->Append(TString::Format("Search for any method with name \'%s\'\n", method_name));
1337  method = obj_cl->GetMethodAllAny(method_name);
1338  } else {
1339  if (debug) debug->Append(TString::Format("Search for method \'%s\' with prototype \'%s\'\n", method_name, prototype.Data()));
1340  method = obj_cl->GetMethodWithPrototype(method_name, prototype);
1341  }
1342  }
1343 
1344  if (method != 0) {
1345  if (debug) debug->Append(TString::Format("Method: %s\n", method->GetPrototype()));
1346  } else {
1347  if (funcname.Length() > 0) {
1348  if (prototype.Length() == 0) {
1349  if (debug) debug->Append(TString::Format("Search for any function with name \'%s\'\n", funcname.Data()));
1350  func = gROOT->GetGlobalFunction(funcname);
1351  } else {
1352  if (debug) debug->Append(TString::Format("Search for function \'%s\' with prototype \'%s\'\n", funcname.Data(), prototype.Data()));
1353  func = gROOT->GetGlobalFunctionWithPrototype(funcname, prototype);
1354  }
1355  }
1356 
1357  if (func != 0) {
1358  if (debug) debug->Append(TString::Format("Function: %s\n", func->GetPrototype()));
1359  }
1360  }
1361 
1362  if ((method == 0) && (func==0)) {
1363  if (debug) debug->Append("Method not found\n");
1364  return debug != 0;
1365  }
1366 
1367  if ((fReadOnly && (fCurrentRestrict == 0)) || (fCurrentRestrict == 1)) {
1368  if ((method!=0) && (fCurrentAllowedMethods.Index(method_name) == kNPOS)) {
1369  if (debug) debug->Append("Server runs in read-only mode, method cannot be executed\n");
1370  return debug != 0;
1371  } else
1372  if ((func!=0) && (fCurrentAllowedMethods.Index(funcname) == kNPOS)) {
1373  if (debug) debug->Append("Server runs in read-only mode, function cannot be executed\n");
1374  return debug != 0;
1375  } else {
1376  if (debug) debug->Append("For that special method server allows access even read-only mode is specified\n");
1377  }
1378  }
1379 
1380  TList *args = method ? method->GetListOfMethodArgs() : func->GetListOfMethodArgs();
1381 
1382  TList garbage;
1383  garbage.SetOwner(kTRUE); // use as garbage collection
1384  TObject *post_obj = 0; // object reconstructed from post request
1385  TString call_args;
1386 
1387  TIter next(args);
1388  TMethodArg *arg = 0;
1389  while ((arg = (TMethodArg *) next()) != 0) {
1390 
1391  if ((strcmp(arg->GetName(), "rest_url_opt") == 0) &&
1392  (strcmp(arg->GetFullTypeName(), "const char*") == 0) && (args->GetSize() == 1)) {
1393  // very special case - function requires list of options after method=argument
1394 
1395  const char *pos = strstr(options, "method=");
1396  if ((pos == 0) || (strlen(pos) < strlen(method_name) + 8)) return debug != 0;
1397  call_args.Form("\"%s\"", pos + strlen(method_name) + 8);
1398  break;
1399  }
1400 
1401  TString sval;
1402  const char *val = url.GetValueFromOptions(arg->GetName());
1403  if (val) {
1404  sval = DecodeUrlOptionValue(val, kFALSE);
1405  val = sval.Data();
1406  }
1407 
1408  if ((val!=0) && (strcmp(val,"_this_")==0)) {
1409  // special case - object itself is used as argument
1410  sval.Form("(%s*)0x%lx", obj_cl->GetName(), (long unsigned) obj_ptr);
1411  val = sval.Data();
1412  } else
1413  if ((val!=0) && (fCurrentArg!=0) && (fCurrentArg->GetPostData()!=0)) {
1414  // process several arguments which are specific for post requests
1415  if (strcmp(val,"_post_object_xml_")==0) {
1416  // post data has extra 0 at the end and can be used as null-terminated string
1417  post_obj = TBufferXML::ConvertFromXML((const char*) fCurrentArg->GetPostData());
1418  if (post_obj == 0) {
1419  sval = "0";
1420  } else {
1421  sval.Form("(%s*)0x%lx", post_obj->ClassName(), (long unsigned) post_obj);
1422  if (url.HasOption("_destroy_post_")) garbage.Add(post_obj);
1423  }
1424  val = sval.Data();
1425  } else
1426  if ((strcmp(val,"_post_object_")==0) && url.HasOption("_post_class_")) {
1427  TString clname = url.GetValueFromOptions("_post_class_");
1428  TClass* arg_cl = gROOT->GetClass(clname, kTRUE, kTRUE);
1429  if ((arg_cl!=0) && (arg_cl->GetBaseClassOffset(TObject::Class()) == 0) && (post_obj==0)) {
1430  post_obj = (TObject*) arg_cl->New();
1431  if (post_obj==0) {
1432  if (debug) debug->Append(TString::Format("Fail to create object of class %s\n", clname.Data()));
1433  } else {
1434  if (debug) debug->Append(TString::Format("Reconstruct object of class %s from POST data\n", clname.Data()));
1435  TBufferFile buf(TBuffer::kRead, fCurrentArg->GetPostDataLength(), fCurrentArg->GetPostData(), kFALSE);
1436  buf.MapObject(post_obj, arg_cl);
1437  post_obj->Streamer(buf);
1438  if (url.HasOption("_destroy_post_")) garbage.Add(post_obj);
1439  }
1440  }
1441  sval.Form("(%s*)0x%lx", clname.Data(), (long unsigned) post_obj);
1442  val = sval.Data();
1443  } else
1444  if (strcmp(val,"_post_data_")==0) {
1445  sval.Form("(void*)0x%lx", (long unsigned) *res_ptr);
1446  val = sval.Data();
1447  } else
1448  if (strcmp(val,"_post_length_")==0) {
1449  sval.Form("%ld", (long) *res_length);
1450  val = sval.Data();
1451  }
1452  }
1453 
1454  if (val == 0) val = arg->GetDefault();
1455 
1456  if (debug) debug->Append(TString::Format(" Argument:%s Type:%s Value:%s \n", arg->GetName(), arg->GetFullTypeName(), val ? val : "<missed>"));
1457  if (val == 0) return debug != 0;
1458 
1459  if (call_args.Length() > 0) call_args += ", ";
1460 
1461  if ((strcmp(arg->GetFullTypeName(), "const char*") == 0) || (strcmp(arg->GetFullTypeName(), "Option_t*") == 0)) {
1462  int len = strlen(val);
1463  if ((strlen(val) < 2) || (*val != '\"') || (val[len - 1] != '\"'))
1464  call_args.Append(TString::Format("\"%s\"", val));
1465  else
1466  call_args.Append(val);
1467  } else {
1468  call_args.Append(val);
1469  }
1470  }
1471 
1472  TMethodCall *call = 0;
1473 
1474  if (method!=0) {
1475  call = new TMethodCall(obj_cl, method_name, call_args.Data());
1476  if (debug) debug->Append(TString::Format("Calling obj->%s(%s);\n", method_name, call_args.Data()));
1477 
1478  } else {
1479  call = new TMethodCall(funcname.Data(), call_args.Data());
1480  if (debug) debug->Append(TString::Format("Calling %s(%s);\n", funcname.Data(), call_args.Data()));
1481  }
1482 
1483  garbage.Add(call);
1484 
1485  if (!call->IsValid()) {
1486  if (debug) debug->Append("Fail: invalid TMethodCall\n");
1487  return debug != 0;
1488  }
1489 
1490  Int_t compact = 0;
1491  if (url.GetValueFromOptions("compact"))
1492  compact = url.GetIntValueFromOptions("compact");
1493 
1494  TString res = "null";
1495  void *ret_obj = 0;
1496  TClass *ret_cl = 0;
1497  TBufferFile *resbuf = 0;
1498  if (reskind==2) {
1499  resbuf = new TBufferFile(TBuffer::kWrite, 10000);
1500  garbage.Add(resbuf);
1501  }
1502 
1503  switch (call->ReturnType()) {
1504  case TMethodCall::kLong: {
1505  Long_t l(0);
1506  if (method)
1507  call->Execute(obj_ptr, l);
1508  else
1509  call->Execute(l);
1510  if (resbuf) resbuf->WriteLong(l);
1511  else res.Form("%ld", l);
1512  break;
1513  }
1514  case TMethodCall::kDouble : {
1515  Double_t d(0.);
1516  if (method)
1517  call->Execute(obj_ptr, d);
1518  else
1519  call->Execute(d);
1520  if (resbuf) resbuf->WriteDouble(d);
1521  else res.Form(TBufferJSON::GetFloatFormat(), d);
1522  break;
1523  }
1524  case TMethodCall::kString : {
1525  char *txt(0);
1526  if (method)
1527  call->Execute(obj_ptr, &txt);
1528  else
1529  call->Execute(0, &txt); // here 0 is artificial, there is no proper signature
1530  if (txt != 0) {
1531  if (resbuf) resbuf->WriteString(txt);
1532  else res.Form("\"%s\"", txt);
1533  }
1534  break;
1535  }
1536  case TMethodCall::kOther : {
1537  std::string ret_kind = func ? func->GetReturnTypeNormalizedName() : method->GetReturnTypeNormalizedName();
1538  if ((ret_kind.length() > 0) && (ret_kind[ret_kind.length() - 1] == '*')) {
1539  ret_kind.resize(ret_kind.length() - 1);
1540  ret_cl = gROOT->GetClass(ret_kind.c_str(), kTRUE, kTRUE);
1541  }
1542 
1543  if (ret_cl != 0) {
1544  Long_t l(0);
1545  if (method)
1546  call->Execute(obj_ptr, l);
1547  else
1548  call->Execute(l);
1549  if (l != 0) ret_obj = (void *) l;
1550  } else {
1551  if (method)
1552  call->Execute(obj_ptr);
1553  else
1554  call->Execute();
1555  }
1556 
1557  break;
1558  }
1559  case TMethodCall::kNone : {
1560  if (method)
1561  call->Execute(obj_ptr);
1562  else
1563  call->Execute();
1564  break;
1565  }
1566  }
1567 
1568  const char *_ret_object_ = url.GetValueFromOptions("_ret_object_");
1569  if (_ret_object_ != 0) {
1570  TObject *obj = 0;
1571  if (gDirectory != 0) obj = gDirectory->Get(_ret_object_);
1572  if (debug) debug->Append(TString::Format("Return object %s found %s\n", _ret_object_, obj ? "true" : "false"));
1573 
1574  if (obj == 0) {
1575  res = "null";
1576  } else {
1577  ret_obj = obj;
1578  ret_cl = obj->IsA();
1579  }
1580  }
1581 
1582  if ((ret_obj != 0) && (ret_cl != 0)) {
1583  if ((resbuf != 0) && (ret_cl->GetBaseClassOffset(TObject::Class()) == 0)) {
1584  TObject *obj = (TObject *) ret_obj;
1585  resbuf->MapObject(obj);
1586  obj->Streamer(*resbuf);
1587  if (fCurrentArg) fCurrentArg->SetExtraHeader("RootClassName", ret_cl->GetName());
1588  } else {
1589  res = TBufferJSON::ConvertToJSON(ret_obj, ret_cl, compact);
1590  }
1591  }
1592 
1593  if ((resbuf != 0) && (resbuf->Length() > 0) && (res_ptr != 0) && (res_length != 0)) {
1594  *res_ptr = malloc(resbuf->Length());
1595  memcpy(*res_ptr, resbuf->Buffer(), resbuf->Length());
1596  *res_length = resbuf->Length();
1597  }
1598 
1599  if (debug) debug->Append(TString::Format("Result = %s\n", res.Data()));
1600 
1601  if ((reskind == 1) && res_str) *res_str = res;
1602 
1603  if (url.HasOption("_destroy_result_") && (ret_obj != 0) && (ret_cl != 0)) {
1604  ret_cl->Destructor(ret_obj);
1605  if (debug) debug->Append("Destroy result object at the end\n");
1606  }
1607 
1608  // delete all garbage objects, but should be also done with any return
1609  garbage.Delete();
1610 
1611  return kTRUE;
1612 }
1613 
1614 ////////////////////////////////////////////////////////////////////////////////
1615 /// Process several requests, packing all results into binary or JSON buffer
1616 /// Input parameters should be coded in the POST block and has
1617 /// individual request relative to current path, separated with '\n' symbol like
1618 /// item1/root.bin\n
1619 /// item2/exe.bin?method=GetList\n
1620 /// item3/exe.bin?method=GetTitle\n
1621 /// Request requires 'number' URL option which contains number of requested items
1622 ///
1623 /// In case of binary request output buffer looks like:
1624 /// 4bytes length + payload, 4bytes length + payload, ...
1625 /// In case of JSON request output is array with results for each item
1626 /// multi.json request do not support binary requests for the items
1627 
1628 Bool_t TRootSniffer::ProduceMulti(const char *path, const char *options, void *&ptr, Long_t &length, TString &str, Bool_t asjson)
1629 {
1630  if ((fCurrentArg==0) || (fCurrentArg->GetPostDataLength()<=0) || (fCurrentArg->GetPostData()==0)) return kFALSE;
1631 
1632  const char* args = (const char*) fCurrentArg->GetPostData();
1633  const char* ends = args + fCurrentArg->GetPostDataLength();
1634 
1635  TUrl url;
1636  url.SetOptions(options);
1637 
1638  Int_t number = 0;
1639  if (url.GetValueFromOptions("number"))
1640  number = url.GetIntValueFromOptions("number");
1641 
1642  // binary buffers required only for binary requests, json output can be produced as is
1643  std::vector<void*> mem;
1644  std::vector<Long_t> memlen;
1645 
1646  if (asjson) str = "[";
1647 
1648  for (Int_t n=0;n<number;n++) {
1649  const char* next = args;
1650  while ((next < ends) && (*next != '\n')) next++;
1651  if (next==ends) {
1652  Error("ProduceMulti", "Not enough arguments in POST block");
1653  break;
1654  }
1655 
1656  TString file1(args, next - args);
1657  args = next + 1;
1658 
1659  TString path1, opt1;
1660 
1661  // extract options
1662  Int_t pos = file1.First('?');
1663  if (pos != kNPOS) {
1664  opt1 = file1(pos+1, file1.Length() - pos);
1665  file1.Resize(pos);
1666  }
1667 
1668  // extract extra path
1669  pos = file1.Last('/');
1670  if (pos != kNPOS) {
1671  path1 = file1(0, pos);
1672  file1.Remove(0, pos+1);
1673  }
1674 
1675  if ((path!=0) && (*path!=0)) path1 = TString(path) + "/" + path1;
1676 
1677  void* ptr1 = 0;
1678  Long_t len1 = 0;
1679  TString str1;
1680 
1681  // produce next item request
1682  Produce(path1, file1, opt1, ptr1, len1, str1);
1683 
1684  if (asjson) {
1685  if (n>0) str.Append(", ");
1686  if (ptr1!=0) { str.Append("\"<non-supported binary>\""); free(ptr1); } else
1687  if (str1.Length()>0) str.Append(str1); else str.Append("null");
1688  } else {
1689  if ((str1.Length()>0) && (ptr1==0)) {
1690  len1 = str1.Length();
1691  ptr1 = malloc(len1);
1692  memcpy(ptr1, str1.Data(), len1);
1693  }
1694  mem.push_back(ptr1);
1695  memlen.push_back(len1);
1696  }
1697  }
1698 
1699  if (asjson) {
1700  str.Append("]");
1701  } else {
1702  length = 0;
1703  for (unsigned n=0;n<mem.size();n++) {
1704  length += 4 + memlen[n];
1705  }
1706  ptr = malloc(length);
1707  char* curr = (char*) ptr;
1708  for (unsigned n=0;n<mem.size();n++) {
1709  Long_t l = memlen[n];
1710  *curr++ = (char) (l & 0xff); l = l >> 8;
1711  *curr++ = (char) (l & 0xff); l = l >> 8;
1712  *curr++ = (char) (l & 0xff); l = l >> 8;
1713  *curr++ = (char) (l & 0xff);
1714  if ((mem[n]!=0) && (memlen[n]>0)) memcpy(curr, mem[n], memlen[n]);
1715  curr+=memlen[n];
1716  }
1717  }
1718 
1719  for (unsigned n=0;n<mem.size();n++) free(mem[n]);
1720 
1721  return kTRUE;
1722 }
1723 
1724 
1725 ////////////////////////////////////////////////////////////////////////////////
1726 /// Return true if it is streamer info item name
1727 
1729 {
1730  if ((itemname == 0) || (*itemname == 0)) return kFALSE;
1731 
1732  return (strcmp(itemname, "StreamerInfo") == 0) || (strcmp(itemname, "StreamerInfo/") == 0);
1733 }
1734 
1735 ////////////////////////////////////////////////////////////////////////////////
1736 /// produce binary data for specified item
1737 /// if "zipped" option specified in query, buffer will be compressed
1738 
1739 Bool_t TRootSniffer::ProduceBinary(const char *path, const char * /*query*/, void *&ptr,
1740  Long_t &length)
1741 {
1742  if ((path == 0) || (*path == 0)) return kFALSE;
1743 
1744  if (*path == '/') path++;
1745 
1746  TClass *obj_cl(0);
1747  void *obj_ptr = FindInHierarchy(path, &obj_cl);
1748  if ((obj_ptr == 0) || (obj_cl == 0)) return kFALSE;
1749 
1750  if (obj_cl->GetBaseClassOffset(TObject::Class()) != 0) {
1751  Info("ProduceBinary", "Non-TObject class not supported");
1752  return kFALSE;
1753  }
1754 
1755  // ensure that memfile exists
1756  CreateMemFile();
1757 
1758  TDirectory *olddir = gDirectory;
1759  gDirectory = 0;
1760  TFile *oldfile = gFile;
1761  gFile = 0;
1762 
1763  TObject *obj = (TObject *) obj_ptr;
1764 
1765  TBufferFile *sbuf = new TBufferFile(TBuffer::kWrite, 100000);
1766  sbuf->SetParent(fMemFile);
1767  sbuf->MapObject(obj);
1768  obj->Streamer(*sbuf);
1769  if (fCurrentArg) fCurrentArg->SetExtraHeader("RootClassName", obj_cl->GetName());
1770 
1771  // produce actual version of streamer info
1772  delete fSinfo;
1773  fMemFile->WriteStreamerInfo();
1774  fSinfo = fMemFile->GetStreamerInfoList();
1775 
1776  gDirectory = olddir;
1777  gFile = oldfile;
1778 
1779  ptr = malloc(sbuf->Length());
1780  memcpy(ptr, sbuf->Buffer(), sbuf->Length());
1781  length = sbuf->Length();
1782 
1783  delete sbuf;
1784 
1785  return kTRUE;
1786 }
1787 
1788 ////////////////////////////////////////////////////////////////////////////////
1789 /// Method to produce image from specified object
1790 ///
1791 /// Parameters:
1792 /// kind - image kind TImage::kPng, TImage::kJpeg, TImage::kGif
1793 /// path - path to object
1794 /// options - extra options
1795 ///
1796 /// By default, image 300x200 is produced
1797 /// In options string one could provide following parameters:
1798 /// w - image width
1799 /// h - image height
1800 /// opt - draw options
1801 /// For instance:
1802 /// http://localhost:8080/Files/hsimple.root/hpx/get.png?w=500&h=500&opt=lego1
1803 ///
1804 /// Return is memory with produced image
1805 /// Memory must be released by user with free(ptr) call
1806 
1807 Bool_t TRootSniffer::ProduceImage(Int_t kind, const char *path,
1808  const char *options, void *&ptr,
1809  Long_t &length)
1810 {
1811  ptr = 0;
1812  length = 0;
1813 
1814  if ((path == 0) || (*path == 0)) return kFALSE;
1815  if (*path == '/') path++;
1816 
1817  TClass *obj_cl(0);
1818  void *obj_ptr = FindInHierarchy(path, &obj_cl);
1819  if ((obj_ptr == 0) || (obj_cl == 0)) return kFALSE;
1820 
1821  if (obj_cl->GetBaseClassOffset(TObject::Class()) != 0) {
1822  Error("TRootSniffer", "Only derived from TObject classes can be drawn");
1823  return kFALSE;
1824  }
1825 
1826  TObject *obj = (TObject *) obj_ptr;
1827 
1828  TImage *img = TImage::Create();
1829  if (img == 0) return kFALSE;
1830 
1831  if (obj->InheritsFrom(TPad::Class())) {
1832 
1833  if (gDebug > 1)
1834  Info("TRootSniffer", "Crate IMAGE directly from pad");
1835  img->FromPad((TPad *) obj);
1836  } else if (IsDrawableClass(obj->IsA())) {
1837 
1838  if (gDebug > 1)
1839  Info("TRootSniffer", "Crate IMAGE from object %s", obj->GetName());
1840 
1841  Int_t width(300), height(200);
1842  TString drawopt = "";
1843 
1844  if ((options != 0) && (*options != 0)) {
1845  TUrl url;
1846  url.SetOptions(options);
1847  url.ParseOptions();
1848  Int_t w = url.GetIntValueFromOptions("w");
1849  if (w > 10) width = w;
1850  Int_t h = url.GetIntValueFromOptions("h");
1851  if (h > 10) height = h;
1852  const char *opt = url.GetValueFromOptions("opt");
1853  if (opt != 0) drawopt = opt;
1854  }
1855 
1856  Bool_t isbatch = gROOT->IsBatch();
1857  TVirtualPad *save_gPad = gPad;
1858 
1859  if (!isbatch) gROOT->SetBatch(kTRUE);
1860 
1861  TCanvas *c1 = new TCanvas("__online_draw_canvas__", "title", width, height);
1862  obj->Draw(drawopt.Data());
1863  img->FromPad(c1);
1864  delete c1;
1865 
1866  if (!isbatch) gROOT->SetBatch(kFALSE);
1867  gPad = save_gPad;
1868 
1869  } else {
1870  delete img;
1871  return kFALSE;
1872  }
1873 
1874  TImage *im = TImage::Create();
1875  im->Append(img);
1876 
1877  char *png_buffer(0);
1878  int size(0);
1879 
1880  im->GetImageBuffer(&png_buffer, &size, (TImage::EImageFileTypes) kind);
1881 
1882  if ((png_buffer != 0) && (size > 0)) {
1883  ptr = malloc(size);
1884  length = size;
1885  memcpy(ptr, png_buffer, length);
1886  }
1887 
1888  delete [] png_buffer;
1889  delete im;
1890 
1891  return ptr != 0;
1892 }
1893 
1894 ////////////////////////////////////////////////////////////////////////////////
1895 /// Method produce different kind of data out of object
1896 /// Parameter 'path' specifies object or object member
1897 /// Supported 'file' (case sensitive):
1898 /// "root.bin" - binary data
1899 /// "root.png" - png image
1900 /// "root.jpeg" - jpeg image
1901 /// "root.gif" - gif image
1902 /// "root.xml" - xml representation
1903 /// "root.json" - json representation
1904 /// "exe.json" - method execution with json reply
1905 /// "exe.bin" - method execution with binary reply
1906 /// "exe.txt" - method execution with debug output
1907 /// "cmd.json" - execution of registered commands
1908 /// Result returned either as string or binary buffer,
1909 /// which should be released with free() call
1910 
1911 Bool_t TRootSniffer::Produce(const char *path, const char *file,
1912  const char *options, void *&ptr, Long_t &length, TString &str)
1913 {
1914  if ((file == 0) || (*file == 0)) return kFALSE;
1915 
1916  if (strcmp(file, "root.bin") == 0)
1917  return ProduceBinary(path, options, ptr, length);
1918 
1919  if (strcmp(file, "root.png") == 0)
1920  return ProduceImage(TImage::kPng, path, options, ptr, length);
1921 
1922  if (strcmp(file, "root.jpeg") == 0)
1923  return ProduceImage(TImage::kJpeg, path, options, ptr, length);
1924 
1925  if (strcmp(file, "root.gif") == 0)
1926  return ProduceImage(TImage::kGif, path, options, ptr, length);
1927 
1928  if (strcmp(file, "exe.bin") == 0)
1929  return ProduceExe(path, options, 2, 0, &ptr, &length);
1930 
1931  if (strcmp(file, "root.xml") == 0)
1932  return ProduceXml(path, options, str);
1933 
1934  if (strcmp(file, "root.json") == 0)
1935  return ProduceJson(path, options, str);
1936 
1937  // used for debugging
1938  if (strcmp(file, "exe.txt") == 0)
1939  return ProduceExe(path, options, 0, &str);
1940 
1941  if (strcmp(file, "exe.json") == 0)
1942  return ProduceExe(path, options, 1, &str);
1943 
1944  if (strcmp(file, "cmd.json") == 0)
1945  return ExecuteCmd(path, options, str);
1946 
1947  if (strcmp(file, "item.json") == 0)
1948  return ProduceItem(path, options, str, kTRUE);
1949 
1950  if (strcmp(file, "item.xml") == 0)
1951  return ProduceItem(path, options, str, kFALSE);
1952 
1953  if (strcmp(file, "multi.bin") == 0)
1954  return ProduceMulti(path, options, ptr, length, str, kFALSE);
1955 
1956  if (strcmp(file, "multi.json") == 0)
1957  return ProduceMulti(path, options, ptr, length, str, kTRUE);
1958 
1959  return kFALSE;
1960 }
1961 
1962 ////////////////////////////////////////////////////////////////////////////////
1963 /// return item from the subfolders structure
1964 
1965 TObject *TRootSniffer::GetItem(const char *fullname, TFolder *&parent, Bool_t force, Bool_t within_objects)
1966 {
1967  TFolder *topf = gROOT->GetRootFolder();
1968 
1969  if (topf == 0) {
1970  Error("RegisterObject", "Not found top ROOT folder!!!");
1971  return 0;
1972  }
1973 
1974  TFolder *httpfold = dynamic_cast<TFolder *>(topf->FindObject("http"));
1975  if (httpfold == 0) {
1976  if (!force) return 0;
1977  httpfold = topf->AddFolder("http", "ROOT http server");
1978  httpfold->SetBit(kCanDelete);
1979  // register top folder in list of cleanups
1980  gROOT->GetListOfCleanups()->Add(httpfold);
1981  }
1982 
1983  parent = httpfold;
1984  TObject *obj = httpfold;
1985 
1986  if (fullname==0) return httpfold;
1987 
1988  // when full path started not with slash, "Objects" subfolder is appended
1989  TString path = fullname;
1990  if (within_objects && ((path.Length()==0) || (path[0]!='/')))
1991  path = fObjectsPath + "/" + path;
1992 
1993  TString tok;
1994  Ssiz_t from(0);
1995 
1996  while (path.Tokenize(tok,from,"/")) {
1997  if (tok.Length()==0) continue;
1998 
1999  TFolder *fold = dynamic_cast<TFolder *> (obj);
2000  if (fold == 0) return 0;
2001 
2002  TIter iter(fold->GetListOfFolders());
2003  while ((obj = iter()) != 0) {
2004  if (IsItemField(obj)) continue;
2005  if (tok.CompareTo(obj->GetName())==0) break;
2006  }
2007 
2008  if (obj == 0) {
2009  if (!force) return 0;
2010  obj = fold->AddFolder(tok, "sub-folder");
2011  obj->SetBit(kCanDelete);
2012  }
2013 
2014  parent = fold;
2015  }
2016 
2017  return obj;
2018 }
2019 
2020 ////////////////////////////////////////////////////////////////////////////////
2021 /// creates subfolder where objects can be registered
2022 
2023 TFolder *TRootSniffer::GetSubFolder(const char *subfolder, Bool_t force)
2024 {
2025  TFolder *parent = 0;
2026 
2027  return dynamic_cast<TFolder *> (GetItem(subfolder, parent, force));
2028 }
2029 
2030 ////////////////////////////////////////////////////////////////////////////////
2031 /// Register object in subfolder structure
2032 /// subfolder parameter can have many levels like:
2033 ///
2034 /// TRootSniffer* sniff = new TRootSniffer("sniff");
2035 /// sniff->RegisterObject("my/sub/subfolder", h1);
2036 ///
2037 /// Such objects can be later found in "Objects" folder of sniffer like
2038 ///
2039 /// h1 = sniff->FindTObjectInHierarchy("/Objects/my/sub/subfolder/h1");
2040 ///
2041 /// If subfolder name starts with '/', object will be registered starting from top folder.
2042 ///
2043 /// One could provide additional fields for registered objects
2044 /// For instance, setting "_more" field to true let browser
2045 /// explore objects members. For instance:
2046 ///
2047 /// TEvent* ev = new TEvent("ev");
2048 /// sniff->RegisterObject("Events", ev);
2049 /// sniff->SetItemField("Events/ev", "_more", "true");
2050 
2051 Bool_t TRootSniffer::RegisterObject(const char *subfolder, TObject *obj)
2052 {
2053  TFolder *f = GetSubFolder(subfolder, kTRUE);
2054  if (f == 0) return kFALSE;
2055 
2056  // If object will be destroyed, it will be removed from the folders automatically
2057  obj->SetBit(kMustCleanup);
2058 
2059  f->Add(obj);
2060 
2061  return kTRUE;
2062 }
2063 
2064 ////////////////////////////////////////////////////////////////////////////////
2065 /// unregister (remove) object from folders structures
2066 /// folder itself will remain even when it will be empty
2067 
2069 {
2070  if (obj == 0) return kTRUE;
2071 
2072  TFolder *topf = dynamic_cast<TFolder *>(gROOT->FindObject("//root/http"));
2073 
2074  if (topf == 0) {
2075  Error("UnregisterObject", "Not found //root/http folder!!!");
2076  return kFALSE;
2077  }
2078 
2079  // TODO - probably we should remove all set properties as well
2080  if (topf) topf->RecursiveRemove(obj);
2081 
2082  return kTRUE;
2083 }
2084 
2085 ////////////////////////////////////////////////////////////////////////////////
2086 /// create item element
2087 
2088 Bool_t TRootSniffer::CreateItem(const char *fullname, const char *title)
2089 {
2090  TFolder *f = GetSubFolder(fullname, kTRUE);
2091  if (f == 0) return kFALSE;
2092 
2093  if (title) f->SetTitle(title);
2094 
2095  return kTRUE;
2096 }
2097 
2098 ////////////////////////////////////////////////////////////////////////////////
2099 /// return true when object is TNamed with kItemField bit set
2100 /// such objects used to keep field values for item
2101 
2103 {
2104  return (obj!=0) && (obj->IsA() == TNamed::Class()) && obj->TestBit(kItemField);
2105 }
2106 
2107 ////////////////////////////////////////////////////////////////////////////////
2108 /// set or get field for the child
2109 /// each field coded as TNamed object, placed after chld in the parent hierarchy
2110 
2112  const char *name, const char *value, TNamed **only_get)
2113 {
2114  if (parent==0) return kFALSE;
2115 
2116  if (chld==0) {
2117  Info("SetField", "Should be special case for top folder, support later");
2118  return kFALSE;
2119  }
2120 
2121  TIter iter(parent->GetListOfFolders());
2122 
2123  TObject* obj = 0;
2124  Bool_t find(kFALSE), last_find(kFALSE);
2125  // this is special case of top folder - fields are on very top
2126  if (parent == chld) { last_find = find = kTRUE; }
2127  TNamed* curr = 0;
2128  while ((obj = iter()) != 0) {
2129  if (IsItemField(obj)) {
2130  if (last_find && (obj->GetName()!=0) && !strcmp(name, obj->GetName())) curr = (TNamed*) obj;
2131  } else {
2132  last_find = (obj == chld);
2133  if (last_find) find = kTRUE;
2134  if (find && !last_find) break; // no need to continue
2135  }
2136  }
2137 
2138  // object must be in childs list
2139  if (!find) return kFALSE;
2140 
2141  if (only_get!=0) {
2142  *only_get = curr;
2143  return curr!=0;
2144  }
2145 
2146  if (curr!=0) {
2147  if (value!=0) { curr->SetTitle(value); }
2148  else { parent->Remove(curr); delete curr; }
2149  return kTRUE;
2150  }
2151 
2152  curr = new TNamed(name, value);
2153  curr->SetBit(kItemField);
2154 
2155  if (last_find) {
2156  // object is on last place, therefore just add property
2157  parent->Add(curr);
2158  return kTRUE;
2159  }
2160 
2161  // only here we do dynamic cast to the TList to use AddAfter
2162  TList *lst = dynamic_cast<TList *> (parent->GetListOfFolders());
2163  if (lst==0) {
2164  Error("SetField", "Fail cast to TList");
2165  return kFALSE;
2166  }
2167 
2168  if (parent==chld)
2169  lst->AddFirst(curr);
2170  else
2171  lst->AddAfter(chld, curr);
2172 
2173  return kTRUE;
2174 }
2175 
2176 ////////////////////////////////////////////////////////////////////////////////
2177 /// set field for specified item
2178 
2179 Bool_t TRootSniffer::SetItemField(const char *fullname, const char *name, const char *value)
2180 {
2181  if ((fullname==0) || (name==0)) return kFALSE;
2182 
2183  TFolder *parent(0);
2184  TObject *obj = GetItem(fullname, parent);
2185 
2186  if ((parent==0) || (obj==0)) return kFALSE;
2187 
2188  if (strcmp(name, item_prop_title)==0) {
2189  TNamed* n = dynamic_cast<TNamed*> (obj);
2190  if (n!=0) { n->SetTitle(value); return kTRUE; }
2191  }
2192 
2193  return AccessField(parent, obj, name, value);
2194 }
2195 
2196 ////////////////////////////////////////////////////////////////////////////////
2197 /// return field for specified item
2198 
2199 const char *TRootSniffer::GetItemField(TFolder *parent, TObject *obj, const char *name)
2200 {
2201  if ((parent==0) || (obj==0) || (name==0)) return 0;
2202 
2203  TNamed *field(0);
2204 
2205  if (!AccessField(parent, obj, name, 0, &field)) return 0;
2206 
2207  return field ? field->GetTitle() : 0;
2208 }
2209 
2210 
2211 ////////////////////////////////////////////////////////////////////////////////
2212 /// return field for specified item
2213 
2214 const char *TRootSniffer::GetItemField(const char *fullname, const char *name)
2215 {
2216  if (fullname==0) return 0;
2217 
2218  TFolder *parent(0);
2219  TObject *obj = GetItem(fullname, parent);
2220 
2221  return GetItemField(parent, obj, name);
2222 }
2223 
2224 
2225 ////////////////////////////////////////////////////////////////////////////////
2226 /// Register command which can be executed from web interface
2227 ///
2228 /// As method one typically specifies string, which is executed with
2229 /// gROOT->ProcessLine() method. For instance
2230 /// serv->RegisterCommand("Invoke","InvokeFunction()");
2231 ///
2232 /// Or one could specify any method of the object which is already registered
2233 /// to the server. For instance:
2234 /// serv->Register("/", hpx);
2235 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()");
2236 /// Here symbols '/->' separates item name from method to be executed
2237 ///
2238 /// One could specify additional arguments in the command with
2239 /// syntax like %arg1%, %arg2% and so on. For example:
2240 /// serv->RegisterCommand("/ResetHPX", "/hpx/->SetTitle(\"%arg1%\")");
2241 /// serv->RegisterCommand("/RebinHPXPY", "/hpxpy/->Rebin2D(%arg1%,%arg2%)");
2242 /// Such parameter(s) will be requested when command clicked in the browser.
2243 ///
2244 /// Once command is registered, one could specify icon which will appear in the browser:
2245 /// serv->SetIcon("/ResetHPX", "rootsys/icons/ed_execute.png");
2246 ///
2247 /// One also can set extra property '_fastcmd', that command appear as
2248 /// tool button on the top of the browser tree:
2249 /// serv->SetItemField("/ResetHPX", "_fastcmd", "true");
2250 /// Or it is equivalent to specifying extra argument when register command:
2251 /// serv->RegisterCommand("/ResetHPX", "/hpx/->Reset()", "button;rootsys/icons/ed_delete.png");
2252 
2253 Bool_t TRootSniffer::RegisterCommand(const char *cmdname, const char *method, const char *icon)
2254 {
2255  CreateItem(cmdname, Form("command %s", method));
2256  SetItemField(cmdname, "_kind", "Command");
2257  if (icon != 0) {
2258  if (strncmp(icon, "button;", 7) == 0) {
2259  SetItemField(cmdname, "_fastcmd", "true");
2260  icon += 7;
2261  }
2262  if (*icon != 0) SetItemField(cmdname, "_icon", icon);
2263  }
2264  SetItemField(cmdname, "method", method);
2265  Int_t numargs = 0;
2266  do {
2267  TString nextname = TString::Format("%sarg%d%s","%",numargs+1,"%");
2268  if (strstr(method,nextname.Data())==0) break;
2269  numargs++;
2270  } while (numargs<100);
2271  if (numargs>0)
2272  SetItemField(cmdname, "_numargs", TString::Format("%d", numargs));
2273 
2274  return kTRUE;
2275 }
Bool_t ProduceImage(Int_t kind, const char *path, const char *options, void *&ptr, Long_t &length)
Method to produce image from specified object.
virtual void Append(const TImage *, const char *="+", const char *="#00000000")
Definition: TImage.h:183
TString fItemName
current level of hierarchy
Definition: TRootSniffer.h:43
Bool_t RegisterObject(const char *subfolder, TObject *obj)
Register object in subfolder structure subfolder parameter can have many levels like: ...
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:52
const char * item_prop_user
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition: TString.cxx:865
Bool_t SetResult(void *obj, TClass *cl, TDataMember *member=0)
Obsolete, use SetFoundResult instead.
A TFolder object is a collection of objects and folders.
Definition: TFolder.h:32
virtual void WriteString(const char *s)
Write string to I/O buffer.
void * GetResPtr() const
An array of TObjects.
Definition: TObjArray.h:39
Bool_t HasOption(const char *key) const
Returns true if the given key appears in the URL options list.
Definition: TUrl.cxx:672
Bool_t CanExploreItem(const char *path)
Method returns true when object has childs or one could try to expand item.
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:405
EImageFileTypes
Definition: TImage.h:44
ULong_t GetItemHash(const char *itemname)
Get hash function for specified item used to detect any changes in the specified object.
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket...
Definition: TBufferFile.h:51
Bool_t Produce(const char *path, const char *file, const char *options, void *&ptr, Long_t &length, TString &str)
Method produce different kind of data out of object Parameter &#39;path&#39; specifies object or object membe...
Bool_t IsStreamerInfoItem(const char *itemname)
Return true if it is streamer info item name.
UInt_t fMask
pointer on parent record
Definition: TRootSniffer.h:40
Bool_t ProduceBinary(const char *path, const char *options, void *&ptr, Long_t &length)
produce binary data for specified item if "zipped" option specified in query, buffer will be compress...
Int_t Depth() const
Returns depth of hierarchy.
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:488
virtual TList * GetListOfKeys() const
Definition: TDirectory.h:158
void BeforeNextChild()
indicates that new child for current element will be started
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Ssiz_t Length() const
Definition: TString.h:390
Collectable string class.
Definition: TObjString.h:32
static const EReturnType kOther
Definition: TMethodCall.h:50
return c1
Definition: legend1.C:41
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:33
Storage of hierarchy scan in TRootSniffer in JSON format.
This class represents a WWW compatible URL.
Definition: TUrl.h:41
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:635
static byte * ptr1
Definition: gifdecode.c:16
search for specified item (only objects and collections)
Definition: TRootSniffer.h:32
TDataMember * GetResMember() const
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:131
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
THist< 1, float, THistStatContent, THistStatUncertainty > TH1F
Definition: THist.hxx:302
virtual TList * GetList() const
Definition: TDirectory.h:157
TH1 * h
Definition: legend2.C:5
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:50
virtual void * FindInHierarchy(const char *path, TClass **cl=0, TDataMember **member=0, Int_t *chld=0)
Search element with specified path Returns pointer on element Optionally one could obtain element cla...
Bool_t GoInside(TRootSnifferScanRec &super, TObject *obj, const char *obj_name=0, TRootSniffer *sniffer=0)
Method verifies if new level of hierarchy should be started with provided object. ...
virtual void Remove(TObject *obj)
Remove object from this folder. obj must be a TObject or a TFolder.
Definition: TFolder.cxx:466
Short_t GetCycle() const
Return cycle number associated to this key.
Definition: TKey.cxx:561
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
Definition: TList.cxx:93
Long_t Property() const
Set TObject::fBits and fStreamerType to cache information about the class.
Definition: TClass.cxx:5671
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 CanSetFields() const
return true when fields could be set to the hierarchy item
Definition: TRootSniffer.h:61
#define gROOT
Definition: TROOT.h:364
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.
static const EReturnType kLong
Definition: TMethodCall.h:47
Basic string class.
Definition: TString.h:137
tomato 1-D histogram with a float per channel (see TH1 documentation)}
Definition: TH1.h:575
Bool_t SetFoundResult(void *obj, TClass *cl, TDataMember *member=0)
Set found element with class and datamember (optional)
virtual const char * GetClassName() const
Definition: TKey.h:77
Bool_t Done() const
Method indicates that scanning can be interrupted while result is set.
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
Bool_t IsaPointer() const
Return true if data member is a pointer.
const Bool_t kFALSE
Definition: Rtypes.h:92
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition: TObject.cxx:255
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:497
void SetParent(TObject *parent)
Set parent owning this buffer.
Definition: TBuffer.cxx:239
void CreateMemFile()
Creates TMemFile instance, which used for objects streaming One could not use TBufferFile directly...
virtual void BeforeNextChild(Int_t, Int_t, Int_t)
void Restrict(const char *path, const char *options)
Restrict access to the specified location.
Each ROOT method (see TMethod) has a linked list of its arguments.
Definition: TMethodArg.h:33
An abstract interface to image processing library.
Definition: TImage.h:37
std::string GetReturnTypeNormalizedName() const
Get the normalized name of the return type.
Definition: TFunction.cxx:154
void MapObject(const TObject *obj, UInt_t offset=1)
Add object to the fMap container.
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
list of created items names, need to avoid duplication
Definition: TRootSniffer.h:45
const char * Class
Definition: TXMLSetup.cxx:64
Bool_t ProduceItem(const char *path, const char *options, TString &res, Bool_t asjson=kTRUE)
produce JSON/XML for specified item contrary to h.json request, only fields for specified item are st...
#define malloc
Definition: civetweb.c:818
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
Abstract interface for storage of hierarchy scan in TRootSniffer.
normal scan of hierarchy
Definition: TRootSniffer.h:30
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition: TClass.cxx:4137
Bool_t CreateItem(const char *fullname, const char *title)
create item element
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:739
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
void CloseNode()
close started node
Bool_t ProduceXml(const char *path, const char *options, TString &res)
produce XML data for specified item For object conversion TBufferXML is used
A TMemFile is like a normal TFile except that it reads and writes only from memory.
Definition: TMemFile.h:19
Bool_t CanExpandItem()
Returns true when item can be expanded.
TList * GetListOfRealData() const
Definition: TClass.h:405
if set, only fields for specified item will be set (but all fields)
Definition: TRootSniffer.h:34
#define gFile
Definition: TFile.h:316
static const EReturnType kString
Definition: TMethodCall.h:49
mask for actions, only actions copied to child rec
Definition: TRootSniffer.h:35
const char * Data() const
Definition: TString.h:349
const char * item_prop_rootversion
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:396
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2706
expand of specified item - allowed to scan object members
Definition: TRootSniffer.h:31
const char * GetAutoLoad() const
return name of configured autoload scripts (or 0)
Bool_t IsReadOnly(Bool_t dflt=kTRUE)
Returns read-only flag for current item.
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
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:2335
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
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
Bool_t ExecuteCmd(const char *path, const char *options, TString &res)
execute command marked as _kind==&#39;Command&#39;
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4702
const char * item_prop_kind
Bool_t ScanOnlyFields() const
Definition: TRootSniffer.h:66
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
Int_t GetResRestrict() const
void Info(const char *location, const char *msgfmt,...)
TString & Append(const char *cs)
Definition: TString.h:492
std::vector< std::vector< double > > Data
virtual void Add(TObject *obj)
Add object to this folder. obj must be a TObject or a TFolder.
Definition: TFolder.cxx:170
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
const char * fSearchPath
defines operation kind
Definition: TRootSniffer.h:41
const char * GetDefault() const
Get default value of method argument.
Definition: TMethodArg.cxx:58
static const EReturnType kDouble
Definition: TMethodCall.h:48
Int_t Atoi() const
Return integer value of string.
Definition: TString.cxx:1965
virtual void RecursiveRemove(TObject *obj)
Recursively remove object from a folder.
Definition: TFolder.cxx:458
char * Buffer() const
Definition: TBuffer.h:93
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:30
Method or function calling interface.
Definition: TMethodCall.h:41
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
void SetRootClass(TClass *cl)
Mark item with ROOT class and correspondent streamer info.
check if there childs, very similar to search
Definition: TRootSniffer.h:33
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 fields
Definition: TRootSniffer.h:51
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition: TVirtualPad.h:59
virtual ~TRootSniffer()
destructor
void Error(const char *location, const char *msgfmt,...)
Storage of hierarchy scan in TRootSniffer in XML format.
A doubly linked list.
Definition: TList.h:47
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...
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3276
void BuildRealData(void *pointer=0, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition: TClass.cxx:1940
const char * item_prop_arraydim
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
const char * GetValueFromOptions(const char *key) const
Return a value for a given key from the URL options.
Definition: TUrl.cxx:649
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
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:188
Int_t fLevel
current path searched
Definition: TRootSniffer.h:42
const char * item_prop_realname
Collection abstract base class.
Definition: TCollection.h:48
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5059
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2322
const char * item_prop_title
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:159
The most important graphics class in the ROOT system.
Definition: TPad.h:37
Bool_t RegisterCommand(const char *cmdname, const char *method, const char *icon)
Register command which can be executed from web interface.
char * Form(const char *fmt,...)
Int_t fNumFields
indicate if node was started
Definition: TRootSniffer.h:50
TLine * l
Definition: textangle.C:4
The TRealData class manages the effective list of all data members for a given class.
Definition: TRealData.h:34
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
virtual void ScanRoot(TRootSnifferScanRec &rec)
scan complete ROOT objects hierarchy For the moment it includes objects in gROOT directory and list o...
static TString ConvertToXML(const TObject *obj, Bool_t GenericLayout=kFALSE, Bool_t UseNamespaces=kFALSE)
Converts object, inherited from TObject class, to XML string GenericLayout defines layout choice for ...
Definition: TBufferXML.cxx:168
virtual ~TRootSnifferScanRec()
destructor
Bool_t AccessField(TFolder *parent, TObject *item, const char *name, const char *value, TNamed **only_get=0)
set or get field for the child each field coded as TNamed object, placed after chld in the parent hie...
void ScanHierarchy(const char *topname, const char *path, TRootSnifferStore *store, Bool_t only_fields=kFALSE)
Method scans normal objects, registered in ROOT.
void ScanObjectMembers(TRootSnifferScanRec &rec, TClass *cl, char *ptr)
scripts names, which are add as _autoload parameter to h.json request
TGraphErrors * gr
Definition: legend1.C:25
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2241
TRootSnifferScanRec()
number of childs
Bool_t IsReadyForResult() const
Checks if result will be accepted.
TString & Remove(Ssiz_t pos)
Definition: TString.h:616
long Long_t
Definition: RtypesCore.h:50
int Ssiz_t
Definition: RtypesCore.h:63
The Canvas class.
Definition: TCanvas.h:41
TList fItemsNames
name of current item
Definition: TRootSniffer.h:44
static TObject * ConvertFromXML(const char *str, Bool_t GenericLayout=kFALSE, Bool_t UseNamespaces=kFALSE)
Read object from XML, produced by ConvertToXML() method.
Definition: TBufferXML.cxx:215
virtual Int_t GetSize() const
Definition: TCollection.h:95
static const char * GetFloatFormat()
return current printf format for float/double members, default "%e"
virtual const char * GetPrototype() const
Returns the prototype of a function as defined by CINT, or 0 in case of error.
Definition: TFunction.cxx:245
#define ClassImp(name)
Definition: Rtypes.h:279
double f(double x)
Bool_t ProduceExe(const char *path, const char *options, Int_t reskind, TString *ret_str, void **ret_ptr=0, Long_t *ret_length=0)
execute command for specified object options include method and extra list of parameters sniffer shou...
TCollection * GetListOfFolders() const
Definition: TFolder.h:57
virtual void WriteLong(Long_t l)
Definition: TBufferFile.h:378
TList * GetListOfMethodArgs()
Return list containing the TMethodArgs of a TFunction.
Definition: TFunction.cxx:126
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:416
double Double_t
Definition: RtypesCore.h:55
Bool_t ProduceMulti(const char *path, const char *options, void *&ptr, Long_t &length, TString &str, Bool_t asjson=kTRUE)
Process several requests, packing all results into binary or JSON buffer Input parameters should be c...
TRootSnifferStore * fStore
restriction 0 - default, 1 - read-only, 2 - full access
Definition: TRootSniffer.h:47
Describe directory structure in memory.
Definition: TDirectory.h:44
virtual void FromPad(TVirtualPad *, Int_t=0, Int_t=0, UInt_t=0, UInt_t=0)
Definition: TImage.h:130
virtual void GetImageBuffer(char **, int *, EImageFileTypes=TImage::kPng)
Definition: TImage.h:249
#define free
Definition: civetweb.c:821
unsigned long ULong_t
Definition: RtypesCore.h:51
double func(double *x, double *p)
Definition: stressTF1.cxx:213
virtual void WriteDouble(Double_t d)
Definition: TBufferFile.h:413
static TString ConvertToJSON(const TObject *obj, Int_t compact=0, const char *member_name=0)
converts object, inherited from TObject class, to JSON string
TRootSnifferScanRec * fParent
Definition: TRootSniffer.h:39
virtual void CreateNode(Int_t, const char *)
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2882
TCanvas * slash()
Definition: slash.C:1
virtual void AddAfter(const TObject *after, TObject *obj)
Insert object after object after in the list.
Definition: TList.cxx:221
Bool_t IsItemField(TObject *obj) const
return true when object is TNamed with kItemField bit set such objects used to keep field values for ...
Bool_t ProduceJson(const char *path, const char *options, TString &res)
produce JSON data for specified item For object conversion TBufferJSON is used
Mother of all ROOT objects.
Definition: TObject.h:44
Global functions class (global functions are obtained from CINT).
Definition: TFunction.h:30
Int_t GetArrayDim() const
Return number of array dimensions.
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 TObject * ReadObj()
To read a TObject* from the file.
Definition: TKey.cxx:727
const char * GetFullTypeName() const
Get full type description of method argument, e.g.: "class TDirectory*".
Definition: TMethodArg.cxx:75
virtual void Add(TObject *obj)
Definition: TList.h:81
const Ssiz_t kNPOS
Definition: Rtypes.h:115
void ScanCollection(TRootSnifferScanRec &rec, TCollection *lst, const char *foldername=0, TCollection *keys_lst=0)
scan collection content
Int_t Length() const
Definition: TBuffer.h:96
void Execute(const char *, const char *, int *=0)
Execute method on this object with the given parameter string, e.g.
Definition: TMethodCall.h:68
Definition: file.py:1
Each ROOT class (see TClass) has a linked list of methods.
Definition: TMethod.h:40
virtual void CloseNode(Int_t, Int_t)
A Graph is a graphics object made of two arrays X and Y with npoints each.
Definition: TGraph.h:53
void SetOptions(const char *opt)
Definition: TUrl.h:96
void ParseOptions() const
Parse URL options into a key/value map.
Definition: TUrl.cxx:618
Bool_t fHasMore
object to store results
Definition: TRootSniffer.h:48
const char * item_prop_more
#define gPad
Definition: TVirtualPad.h:289
R__EXTERN Int_t gDebug
Definition: Rtypes.h:128
bool debug
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
Long_t Property() const
Get property description word. For meaning of bits see EProperty.
Bool_t fNodeStarted
indicates that potentially there are more items can be found
Definition: TRootSniffer.h:49
virtual TObject * FindObject(const char *name) const
Search object identified by name in the tree of folders inside this folder.
Definition: TFolder.cxx:310
A TTree object has a header with a name and a title.
Definition: TTree.h:98
#define gDirectory
Definition: TDirectory.h:221
const char * item_prop_autoload
TDataMember * GetDataMember() const
Definition: TRealData.h:57
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4598
static TImage * Create()
Create an image.
Definition: TImage.cxx:36
static const EReturnType kNone
Definition: TMethodCall.h:53
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:582
virtual void ScanObjectProperties(TRootSnifferScanRec &rec, TObject *obj)
scans object properties here such fields as _autoload or _icon properties depending on class or objec...
A TTree is a list of TBranches.
Definition: TBranch.h:58
void MakeItemName(const char *objname, TString &itemname)
Construct item name, using object name as basis.
const Bool_t kTRUE
Definition: Rtypes.h:91
Int_t GetResNumChilds() const
Long_t GetThisOffset() const
Definition: TRealData.h:59
virtual const char * GetName() const
Returns name of object.
Definition: TRealData.h:56
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
TMethod * GetMethodWithPrototype(const char *method, const char *proto, Bool_t objectIsConst=kFALSE, ROOT::EFunctionMatchMode mode=ROOT::kConversionMatch)
Find the method with a given prototype.
Definition: TClass.cxx:4213
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:460
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:155
void BuildFullName(TString &buf, TRootSnifferScanRec *prnt=0)
Produces full name for the current item.
const Int_t n
Definition: legend1.C:16
const char * GetItemField(TFolder *parent, TObject *item, const char *name)
return field for specified item
Bool_t IsValid() const
Return true if the method call has been properly initialized and is usable.
char name[80]
Definition: TGX11.cxx:109
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:467
const char * cnt
Definition: TXMLSetup.cxx:75
EReturnType ReturnType()
Returns the return type of the method.
int CompareTo(const char *cs, ECaseCompare cmp=kExact) const
Compare a string to char *cs2.
Definition: TString.cxx:386
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
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1059
ULong_t GetStreamerInfoHash()
Returns hash value for streamer infos At the moment - just number of items in streamer infos list...
TObject * FindTObjectInHierarchy(const char *path)
Search element in hierarchy, derived from TObject.
TClass * GetResClass() const
static Bool_t IsDrawableClass(TClass *cl)
return true if object can be drawn
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition: TString.cxx:606