Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
XMLReader.cxx
Go to the documentation of this file.
1// @(#)root/core/utils:$Id: XMLReader.cxx 35213 2010-09-08 16:39:04Z axel $
2// Author: Velislava Spasova, 2010-09-16
3
4/*************************************************************************
5 * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//////////////////////////////////////////////////////////////////////////
13// //
14// This class reads selection.xml files. //
15// //
16//////////////////////////////////////////////////////////////////////////
17
18
19
20#include "XMLReader.h"
22#include "SelectionRules.h"
23#include "TClingUtils.h"
24
25std::map<std::string, XMLReader::ETagNames> XMLReader::fgMapTagNames;
26
27/*
28 This is a static function - which in our context means it is populated only ones
29 */
31 if (!(fgMapTagNames.empty())) return; // if the map has already been populated, return, else populate it
32
37 XMLReader::fgMapTagNames["namespace"] = kClass;
38 XMLReader::fgMapTagNames["/namespace"] = kEndClass;
46 XMLReader::fgMapTagNames["member"] = kField; // field and member treated identically
47 XMLReader::fgMapTagNames["/member"] = kEndField; // field and member treated identically
65}
66
67/*
68 This function Gets the next tag from teh input file stream
69 file - the open input stream
70 out - we return the tag through that parameter
71 lineCount - we are counting the line numbers here in order to print error messages in case of an error
72 */
73bool XMLReader::GetNextTag(std::ifstream& file, std::string& out, int& lineCount)
74{
75 int c;
76 std::string str;
77 bool angleBraceLevel = false;
78 bool quotes = false;
79 bool comment = false;
80 bool tagIsComment = false;
81 bool xmlDecl = false;
82 bool tagIsXMLDecl = false; // like <?xml version="1.0" encoding="ISO-8859-1"?>
83 bool isCR=false;
84 bool isInlineComment = false ; // Support comments like in c++ "// Mycomment"
85 int charMinus1= '@';
86 int charMinus2= '@';
87 int charMinus3= '@';
88 while(file.good())
89 {
90 c = file.get();
91 // Temp fix: the stream should become a string
92 if (c=='&'){
93 std::string pattern;
94 int i=0;
95 for (;i<3 && file.good();++i){
96 pattern+=file.get();
97 }
98 if (pattern == "lt;"){
99 c = '<';
100 }
101 else if (pattern == "gt;"){
102 c = '>';
103 }
104 else {
105 for (;i!=0 && file.good();--i){
106 file.unget();
107 }
108 }
109 }
110
111 if (file.good()){
112 bool br = false; // break - we Set it when we have found the end of the tag
113
114 //count quotes - we don't want to count < and > inside quotes as opening/closing brackets
115 switch (c) {
116 case '\r': // skip these
117 isCR=true;
118 break;
119 case '\n': ++lineCount; // if new line increment lineCount
120 break;
121 case '"': quotes = !quotes; // we are allowed to have only pair number of quotes per tag - for the attr. values
122 break;
123 case '<':
124 if (!quotes) angleBraceLevel = !angleBraceLevel; // we count < only outside quotes (i.e. quotes = false)
125 if (!angleBraceLevel && !comment) return false; // if angleBraceLevel = true, we have < outside quotes - this is error
126 break;
127 case '>':
128 if (!quotes && !comment) angleBraceLevel = !angleBraceLevel; // we count > only outside quotes (i.e. quotes = false)
129 if (!angleBraceLevel && !comment) br = true; // if angleBraceLevel = true, we have > outside quotes - this is end of tag => break
130 if (!angleBraceLevel && comment && charMinus2=='-' && charMinus1=='-') br = true;
131 if (charMinus2=='-' && charMinus1=='-'){
132 if (comment) { tagIsComment=true; br=true; } // comment ended!
133 else { return false; } // a comment ends w/o starting
134 }
135 if (charMinus1=='?'){
136 if (xmlDecl) {tagIsXMLDecl=true;br=true;} // xmlDecl ended
137 else {return false;} // an xmlDecl ends w/o starting
138 }
139 break;
140 case '-':
141 if (charMinus3=='<' && charMinus2=='!' && charMinus1=='-') comment = !comment; // We are in a comment
142 break;
143 case '?': // treat the xml standard declaration
144 if (charMinus1=='<') xmlDecl=!xmlDecl;
145 break;
146 case '/': // if char is /, preceeding is / and we are not between a < > pair or an xml comment:
147 if (charMinus1=='/' && !angleBraceLevel && !comment){
148 isInlineComment=true;
149 }
150 break;
151 }
152 if (isCR){
153 isCR=false;
154 continue;
155 }
156 if (isInlineComment){
157 out.erase(out.size()-1,1);
158 while (file.good() && c!='\n'){ // continue up to the end of the line or the file
159 c = file.get();
160 }
161 break;
162 }
166 // check if the comment ended
167 if (comment && !(charMinus3=='-' && charMinus2=='-' && charMinus1=='>')){
168 continue;
169 }
170 out += c; // if c != {<,>,"}, add it to the tag
171 if (br) break; // if br = true, we have reached the end of the tag and we stop reading from the input stream
172
173 }
174 }
175
176
177 // Trim Both leading and trailing spaces
178 int startpos = out.find_first_not_of(" \t\n"); // Find the first character position after excluding leading blank spaces
179 int endpos = out.find_last_not_of(" \t\n"); // Find the first character position from reverse af
180
181 // if all spaces or empty return an empty string
182 if (((int) std::string::npos == startpos ) || ((int) std::string::npos == endpos))
183 {
184 out = "";
185 }
186 else
187 out = out.substr( startpos, endpos-startpos+1 );
188
189 // if tag isn't empty, check if everything is OK with the tag format
190 if (!out.empty()){
191 bool isTagOk = CheckIsTagOK(out);
193 out="";
194 return GetNextTag(file,out,lineCount);
195 }
196 else{
197 return isTagOk;
198 }
199 }
200 else
201 return true;
202}
203
204//////////////////////////////////////////////////////////////////////////////////////////
205
206/*
207 Checks if the tag is OK with respect to the opening and closing <>
208 */
209
210bool XMLReader::CheckIsTagOK(const std::string& tag)
211{
212 if (tag.length()<3){
213 ROOT::TMetaUtils::Error(nullptr,"This is not a tag!\n");
214 return false;
215 }
216
217 // if tag doesn't begin with <, this is not a tag
218 if (tag.at(0) != '<'){
219 ROOT::TMetaUtils::Error(nullptr,"Malformed tag %s (tag doesn't begin with <)!\n", tag.c_str());
220 return false;
221 }
222
223 // if the second symbol is space - this is malformed tag - name of the tag should go directly after the <
224 if (isspace(tag.at(1))){
225 ROOT::TMetaUtils::Error(nullptr,"Malformed tag %s (there should be no white-spaces between < and name-of-tag)!\n", tag.c_str());
226 return false;
227 }
228
229 // this for checks if there are spaces between / and the closing >
230 int countWSp = 0;
231 for (std::string::size_type i = tag.length()-2; true /*see break below*/; --i) {
232 char c = tag[i];
233
234 if (isspace(c)) {
235 ++countWSp;
236 }
237 else {
238 if (c == '/' && countWSp>0) {
239 ROOT::TMetaUtils::Error(nullptr,"Malformed tag %s (there should be no white-spaces between / and >)!\n", tag.c_str());
240 return false;
241 }
242 break;
243 }
244 if (i == 0) break;
245 }
246
247
248 // here we are checking for a situation in which we have forgotten to close quotes and the next tag has entered in an
249 // attribute value of the current tag (example: <class name="a > <fild name="b" />).
250 // NOTE: this will only work if tags like <class pattern = "something><" /> arent valid because in any case they will
251 // be processed as invalid tags
252 int pos1 = tag.find(">");
253 if (pos1>-1) {
254 for (std::string::size_type i = pos1+1, e = tag.length(); i < e; ++i) {
255 char c = tag[i];
256
257 if (isspace(c)){
258 continue;
259 }
260 if (c == '<'){
261 return false;
262 }
263 else{
264 break;
265 }
266 }
267 }
268
269 return true;
270}
271
272//////////////////////////////////////////////////////////////////////////////////////////
273/*
274 Returns true if the tag is standalone. By standlone I mean <something />
275 */
276bool XMLReader::IsStandaloneTag(const std::string& tag)
277{
278 std::string tagEnd = tag.substr(tag.length()-2, 2);
279 return (tagEnd == "/>");
280}
281
282//////////////////////////////////////////////////////////////////////////////////////////
283/*
284 Returns true if the tag is closing tag, t.e. </class>
285 */
286bool XMLReader::IsClosingTag(const std::string& tag)
287{
288 std::string tagBegin = tag.substr(0, 2);
289 return (tagBegin == "</");
290}
291
292//////////////////////////////////////////////////////////////////////////////////////////
293/*
294 Returns name of the tag (class, function, method, selection, ...). If the name is not amongst the names populated in the
295 map, return kInvalid
296 */
297XMLReader::ETagNames XMLReader::GetNameOfTag(const std::string& tag, std::string& name)
298{
299 for (std::string::size_type i = 0, e = tag.length(); i < e; ++i) {
300 char c = tag[i];
301 if (isspace(c)) break;
302 if ((c != '<') && (c != '>'))
303 name += c;
304 }
305
306 std::map<std::string, ETagNames>::iterator it;
308 if (it != XMLReader::fgMapTagNames.end())
310 else
311 return kInvalid;
312}
313
314
315/////////////////////////////////////////////////////////////////////////////////////////
316/*
317 We Get the attributes (if any) of the tag as {attribute_name, attribute_value} couples
318 If there are no attributes, I don't fill the out vector and after that in the Parse()
319 method check if out is empty. All the error handling conserning attributes is done here
320 and this is the reason why the logic is somtimes a bit obscure.
321 */
322bool XMLReader::GetAttributes(const std::string& tag, std::vector<Attributes>& out, const char* lineNum)
323{
324 // Get position of first symbol of the name of the tag
325 std::string name;
326 GetNameOfTag(tag,name);
327
328 bool standalone = IsStandaloneTag(tag);
329
330 // cut off the name of the tag and the trailing /> or >
331 std::string::size_type cutend = tag.length() - 1 - name.length();
332 if (standalone) --cutend;
333 std::string attrstr = tag.substr(1 /*for '<'*/ + name.length(), cutend);
334
335 if (attrstr.length() > 4) { //ELSE ERROR HANDLING; - no need for it - I check in Parse()
336 //cut off any last spaces, tabs or end of lines
337 int pos = attrstr.find_last_not_of(" \t\n");
338 attrstr = attrstr.substr(1, pos+1);
339
340 /*
341 The logic here is the following - we have bool name - it shows if we have read (or are reading) an attribute name
342 bool equalfound - shows if we have found the = symbol after the name
343 bool value - shows if we have found or are reading the attribute value
344 bool newattr - do we have other attributes to read
345 char lastsymbol - I use it to detect a situation like name = xx"value"
346 */
347 std::string attrtemp;
348 bool namefound = false;
349 bool equalfound = false;
350 bool value = false;
351 bool newattr = true;
352 bool inString = false;
353 std::string attr_name;
354 std::string attr_value;
355 char lastsymbol = '\0';
356
357 for (std::string::size_type i = 0, e = attrstr.length()-1; i < e; ++i) {
358 char c = attrstr[i];
359
360 if (c == '=') {
361 if (!namefound){ // if no name was read, report error (i.e. <class ="x">)
362 ROOT::TMetaUtils::Error(nullptr,"At line %s. No name of attribute\n", lineNum);
363 return false;
364 }
365 else {
366 equalfound = true;
367 if (!value) // do not do that if we are reading a value. There can be an = in it
368 lastsymbol = '=';
369 else
370 attr_value += c; // in case we are in a value, we save also the =
371
372 }
373 }
374 else if (isspace(c) && !inString) continue;
375 else if (c == '"') {
377 lastsymbol = '"';
378 if (namefound && equalfound){ //if name was read and = was found
379 if (!value){ // in this case we are starting to read the value of the attribute
380 value = true;
381 }
382 else { // if !value is false, then value is true which means that these are the closing quotes for the
383 // attribute value
384 if (attr_name.length() == 0) { // checks if attribute name is empty
385 ROOT::TMetaUtils::Error(nullptr,"At line %s. Attribute - missing attribute name!\n", lineNum);
386 return false;
387 }
388 // Lift this: one may had an empty attribute value
389// if (attr_value.length() == 0) { // checks if the attribute value is empty
390// ROOT::TMetaUtils::Error(0,"Attribute - missing attibute value!\n");
391// return false;
392// }
393
394 // creates new Attributes object and pushes it back in the vector
395 // then Sets the variables in the initial state - if there are other attributes to be read
396
397 // For the moment the proto pattern is not implemented. The current ROOT6 architecture
398 // relies on ABI compatibility for calling functions, no stub functions are present.
399 // The concept of selecting/excluding functions is not defined.
400// if (attr_name == "proto_pattern") {
401// printf("XMLReader::GetAttributes(): proto_pattern selection not implemented yet!\n");
402// }
403 ROOT::TMetaUtils::Info(nullptr, "*** Attribute: %s = \"%s\"\n", attr_name.c_str(), attr_value.c_str());
404 if (attr_name=="pattern" && attr_value.find("*") == std::string::npos){
405 ROOT::TMetaUtils::Warning(nullptr,"At line %s. A pattern, \"%s\", without wildcards is being used. This selection rule would not have any effect. Transforming it to a rule based on name.\n", lineNum, attr_value.c_str());
406 attr_name="name";
407 }
408 out.emplace_back(attr_name, attr_value);
409 attr_name = "";
410 attr_value = "";
411 namefound = false;
412 value = false;
413 equalfound = false;
414 newattr = true;
415 }
416 }
417 else { // this is the case in which (name && equalfound) is false i.e. we miss either the attribute name or the
418 // = symbol
419 ROOT::TMetaUtils::Error(nullptr,"At line %s. Attribute - missing attribute name or =\n", lineNum);
420 return false;
421 }
422 }
423 else if (lastsymbol == '=') { // this is the case in which the symbol is not ", space or = and the last symbol read
424 // (diferent than space) is =. This is a situation which is represented by for example <class name = x"value">
425 // this is an error
426 ROOT::TMetaUtils::Error(nullptr,"At line %s. Wrong quotes placement or lack of quotes\n", lineNum);
427 return false;
428 }
429 else if ((newattr || namefound) && !value){ // else - if name or newattr is Set, we should write in the attr_name variable
430 newattr = false;
431 namefound = true;
432 attr_name += c;
433 lastsymbol = c;
434 }
435 else if (value) {
436 attr_value += c; // if not, we should write in the attr_value variable
437 }
438 }
439
440 if (namefound && (!equalfound || !value)) { // this catches the situation <class name = "value" something >
441 ROOT::TMetaUtils::Error(nullptr,"At line %s. Attribute - missing attribute value\n", lineNum);
442 return false;
443 }
444 }
445 return true;
446}
447
448//////////////////////////////////////////////////////////////////////////////////////////
449/*
450 This is where the actual work is done - this method parses the XML file tag by tag
451 and for every tag extracts the atrributes. Here is done some error checking as well -
452 mostly conserning missing or excessive closing tags, nesting problems, etc.
453 */
454bool XMLReader::Parse(const std::string &fileName, SelectionRules& out)
455{
456
457 std::ifstream file(fileName);
458
459 PopulateMap();
460
461 int lineNum = 1;
462 bool exclusion = false;
463 bool selection = false;
464 bool sel = false;
465 bool selEnd = false;
466 bool exclEnd = false;
467 bool excl = false;
468 bool inIoread = false;
469 bool inClass = false;
470 bool inMethod = false;
471 bool inField = false;
472
473 BaseSelectionRule *bsr = nullptr; // Pointer to the base class, in it is written information about the current sel. rule
474 BaseSelectionRule *bsrChild = nullptr; // The same but keeps information for method or field children of a class
475 std::unique_ptr<ClassSelectionRule> csr;
476 std::unique_ptr<FunctionSelectionRule> fsr;
477 std::unique_ptr<VariableSelectionRule> vsr;
478 std::unique_ptr<EnumSelectionRule> esr;
479
480 while(file.good()){
481 std::string tagStr;
482
483 bool tagOK = GetNextTag(file, tagStr, lineNum);
484
485 const char* tagStrCharp = tagStr.c_str();
486 // convert number to string
487 std::ostringstream buf;
488 buf << lineNum;
489 std::string lineNumStr = buf.str();
490 const char* lineNumCharp = lineNumStr.c_str();
491 if (!tagOK){
492 ROOT::TMetaUtils::Error(nullptr,"At line %s. Bad tag: %s\n", lineNumCharp, tagStrCharp);
493 out.ClearSelectionRules();
494 return false;
495 }
496
497 if (!tagStr.empty()){
498 std::vector<Attributes> attrs;
499 std::string name;
502 if (!attrError) {
503 ROOT::TMetaUtils::Error(nullptr,"Attribute at line %s. Bad tag: %s\n", lineNumCharp, tagStrCharp);
504 out.ClearSelectionRules();
505 return false;
506 }
507
508 // after we have the name of the tag, we react according to the type of the tag
509 switch (tagKind){
510 case kInvalid:
511 {
512 ROOT::TMetaUtils::Error(nullptr,"At line %s. Unrecognized name of tag %s\n", lineNumCharp, tagStrCharp);
513 out.ClearSelectionRules(); //Clear the selection rules up to now
514 return false;
515 }
516 case kClass:
517 {
518 if (inClass){
519 //this is an error
520 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
521 out.ClearSelectionRules();
522 return false;
523 }
524 if (!IsStandaloneTag(tagStr)){ // if the class tag is not standalone, then it has (probably) some child nodes
525 inClass = true;
526 }
527 csr.reset(new ClassSelectionRule(fCount++, fInterp, fileName.c_str(), lineNum)); // create new class selection rule
528 csr->SetRequestStreamerInfo(true);
529 bsr = csr.get(); // we could access it through the base class pointer
530 break;
531 }
532 case kEndClass:
533 {
534 if (inClass) { // if this is closing a parent class element, clear the parent information
535 inClass = false;
536 out.AddClassSelectionRule(*csr); // if we have a closing tag - we should write the class selection rule to the
537 // SelectionRules object; for standalone class tags we write the class sel rule at the end of the tag processing
538 }
539 else { // if we don't have parent information, it means that this closing tag doesn't have opening tag
540 ROOT::TMetaUtils::Error(nullptr,"Single </class> tag at line %s",lineNumCharp);
541 out.ClearSelectionRules();
542 return false;
543 }
544 break;
545 }
546 case kVersion:
547 {
548 if (!inClass){
549 ROOT::TMetaUtils::Error(nullptr,"Version tag not within class element at line %s",lineNumCharp);
550 out.ClearSelectionRules();
551 return false;
552 }
553 break;
554 }
555 case kBeginIoread:
556 case kBeginIoreadRaw:
557 {
558 inIoread = true;
559 // Try to see if we have CDATA to be put into the attributes
560 std::streampos initialPos(file.tellg());
561 const unsigned int lineCharsSize=1000;
563 file.getline(lineChars,lineCharsSize);
564 std::string lineStr(lineChars);
565 // skip potential empty lines
566 while (lineStr == "" ||
567 std::count(lineStr.begin(),lineStr.end(),' ') == (int)lineStr.size()){
568 file.getline(lineChars,lineCharsSize);
570 }
571 // look for the start of the data section
572 size_t dataBeginPos = lineStr.find("<![CDATA[");
573 if (dataBeginPos==std::string::npos){ // no data
574 file.seekg(initialPos);
575 break;
576 }
577
578 // we put ourselves after the <![CDATA[
579 lineStr = lineStr.substr(dataBeginPos+9);
580
581 // if we are here, we have data. Let's put it in a string which
582 // will become the code attribute
583 std::string codeAttrVal;
584 while(true){
585 // while loop done to read the data
586 // if we find ]]>, it means we are at the end of the data,
587 // we need to stop
588 size_t dataEndPos = lineStr.find("]]>");
589 if (dataEndPos!=std::string::npos) {
590 // add code that may be before the ]]>
591 codeAttrVal+=lineStr.substr(0,dataEndPos);
592 break;
593 }
594 codeAttrVal+=lineStr; // here because data can be on one line!
595 codeAttrVal+="\n";
596 file.getline(lineChars,lineCharsSize);
598 }
599 attrs.emplace_back("code", codeAttrVal);
600 break;
601 }
602 case kEndIoread:
603 case kEndIoreadRaw:
604 {
605 if (!inIoread){
606 ROOT::TMetaUtils::Error(nullptr,"Single </ioread> at line %s",lineNumCharp);
607 out.ClearSelectionRules();
608 return false;
609 }
610 inIoread = false;
611 break;
612 }
613 case kSelection:
614 {
615 if (inClass){
616 //this is an error
617 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
618 out.ClearSelectionRules();
619 return false;
620 }
621 sel = true; // we need both selection (indicates that we are in the selection section) and sel (indicates that
622 // we had an opening <selection> tag)
623 selection = true;
624 exclusion = false;
625 break;
626 }
627 case kEndSelection:
628 {
629 if (inClass){
630 //this is an error
631 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
632 out.ClearSelectionRules();
633 return false;
634 }
635 if (selection) { // if we had opening selection tag, everything is OK
636 selection = false;
637 selEnd = true;
638 }
639 else { // if not, this is a closing tag without an opening such
640 ROOT::TMetaUtils::Error(nullptr,"At line %s. Missing <selection> tag", lineNumCharp);
641 out.ClearSelectionRules();
642 return false;
643 }
644 break;
645 }
646 case kExclusion:
647 {
648 if (inClass){
649 //this is an error
650 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
651 out.ClearSelectionRules();
652 return false;
653 }
654 excl = true; // we need both exclusion (indicates that we are in the exclusion section) and excl (indicates we had
655 // at a certain time an opening <exclusion> tag)
656 if (selection) { // if selection is true, we didn't have fEndSelection type of tag
657 ROOT::TMetaUtils::Error(nullptr,"At line %s. Missing </selection> tag", lineNumCharp);
658 out.ClearSelectionRules();
659 return false;
660 }
661 exclusion=true;
662 break;
663 }
664 case kEndExclusion:
665 {
666 if (inClass){
667 //this is an error
668 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
669 out.ClearSelectionRules();
670 return false;
671 }
672 if (exclusion) { // if exclusion is Set, everything is OK
673 exclusion=false;
674 exclEnd = true;
675 }
676 else { // if not we have a closing </exclusion> tag without an opening <exclusion> tag
677 ROOT::TMetaUtils::Error(nullptr,"At line %s. Missing <exclusion> tag", lineNumCharp);
678 out.ClearSelectionRules();
679 return false;
680 }
681 break;
682 }
683 case kField:
684 {
685 if (!inClass){ // if we have a <field>, <method> or <properties> tag outside a parent <clas>s tag,
686 //this is an error
687 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s not inside a <class> element\n", lineNumCharp,tagStrCharp);
688 out.ClearSelectionRules();
689 return false;
690 }
691 if (!IsStandaloneTag(tagStr)){
692 inField=true;
693 }
694 vsr.reset(new VariableSelectionRule(fCount++, fInterp,fileName.c_str(), lineNum)); // the field is variable selection rule object
695 bsrChild = vsr.get();
696 break;
697 }
698 case kEndField:
699 {
700 if (!inField){
701 ROOT::TMetaUtils::Error(nullptr,"At line %s. Closing field tag which was not opened\n", lineNumCharp);
702 out.ClearSelectionRules();
703 return false;
704 }
705 inField=false;
706 ROOT::TMetaUtils::Info(nullptr,"At line %s. A field is not supposed to have an end-tag (this message will become a warning).\n", lineNumCharp);
707 break;
708 }
709 case kMethod:
710 {
711 if (!inClass){ // if we have a <field>, <method> or <properties> tag outside a parent <clas>s tag,
712 //this is an error
713 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s not inside a <class> element\n", lineNumCharp,tagStrCharp);
714 out.ClearSelectionRules();
715 return false;
716 }
717 if (!IsStandaloneTag(tagStr)){
718 inMethod=true;
719 }
720 fsr.reset(new FunctionSelectionRule(fCount++, fInterp,fileName.c_str(), lineNum)); // the method is function selection rule object
721 bsrChild = fsr.get();
722 break;
723 }
724 case kEndMethod:
725 {
726 if (!inMethod){
727 ROOT::TMetaUtils::Error(nullptr,"At line %s. Closing method tag which was not opened\n", lineNumCharp);
728 out.ClearSelectionRules();
729 return false;
730 }
731 inMethod=false;
732 ROOT::TMetaUtils::Info(nullptr,"At line %s. A method is not supposed to have an end-tag (this message will become a warning).\n", lineNumCharp);
733 break;
734 }
735 case kProperties:
736 {
737 if (!inClass){ // if we have a <field>, <method> or <properties> tag outside a parent <clas>s tag,
738 //this is an error
739 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s not inside a <class> element\n", lineNumCharp,tagStrCharp);
740 out.ClearSelectionRules();
741 return false;
742 }
743 if (!IsStandaloneTag(tagStr)) {
744 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag should be standalone\n", lineNumCharp);
745 out.ClearSelectionRules();
746 return false;
747 }
748 // we don't create separate selection object for properties - we include them as attribute-value pairs for the class
749 break;
750 }
751 case kFunction:
752 {
753 if (inClass){
754 //this is an error
755 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
756 out.ClearSelectionRules();
757 return false;
758 }
759 fsr.reset(new FunctionSelectionRule(fCount++, fInterp,fileName.c_str(), lineNum));
760 bsr = fsr.get();
761 break;
762 }
763 case kVariable:
764 {
765 if (inClass){
766 //this is an error
767 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
768 out.ClearSelectionRules();
769 return false;
770 }
771 vsr.reset(new VariableSelectionRule(fCount++, fInterp,fileName.c_str(), lineNum));
772 bsr = vsr.get();
773 break;
774 }
775 case kTypedef:
776 {
777 if (inClass){
778 //this is an error
779 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
780 out.ClearSelectionRules();
781 return false;
782 }
783 csr.reset(new ClassSelectionRule(fCount++, fInterp));
784 attrs.emplace_back("fromTypedef", "true");
785 bsr = csr.get();
786 break;
787 }
788 case kEnum:
789 {
790 if (inClass){
791 //this is an error
792 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
793 out.ClearSelectionRules();
794 return false;
795 }
796 esr.reset(new EnumSelectionRule(fCount++, fInterp,fileName.c_str(), lineNum));
797 bsr = esr.get();
798 break;
799 }
800 case kLcgdict:
801 {}
802 case kEndLcgdict:
803 {
804 if (inClass){
805 //this is an error
806 ROOT::TMetaUtils::Error(nullptr,"At line %s. Tag %s inside a <class> element\n", lineNumCharp,tagStrCharp);
807 out.ClearSelectionRules();
808 return false;
809 }
810 break;
811 }
812 default: ROOT::TMetaUtils::Error(nullptr,"Unknown tag name: %s \n",tagStrCharp);
813 }
814
815
816 // Take care of ioread rules
818 // A first sanity check
819 if (attrs.empty()){
820 ROOT::TMetaUtils::Error(nullptr,"At line %s. ioread element has no attributes.\n",lineNumCharp);
821 return false;
822 }
823 // Loop over the attrs to get the info to build the linkdef-like string
824 // Cache the name and the value
825 std::string iAttrName;
826 std::string iAttrValue;
827 // save attributes in a map to then format the new line which is of the form
828 // #pragma read sourceClass="class1" targetClass="class2" version="[1-]" source="" target="transient_" code="{ newObj->initializeTransientss(); }";
829 // where "#pragma read" should not appear
830 // The check for the sanity of the pragma is delegated to the ProcessReadPragma routine
831
832 std::map<std::string,std::string> pragmaArgs;
833 for (int i = 0, n = attrs.size(); i < n; ++i) {
834 pragmaArgs[attrs[i].fName]=attrs[i].fValue;
835 }
836
837 std::stringstream pragmaLineStream;
838 const std::string attrs[11] ={"sourceClass",
839 "version",
840 "targetClass",
841 "target",
842 "targetType",
843 "source",
844 "code",
845 "checksum",
846 "embed",
847 "include",
848 "attributes"};
849 std::string value;
850 for (unsigned int i=0;i<11;++i) {
851 const std::string& attr = attrs[i];
852 if ( pragmaArgs.count(attr) == 1){
854 if (attr == "code") value= "{"+value+"}";
855 pragmaLineStream << " " << attr << "=\""<< value << "\"";
856 }
857 }
858
859 // Now send them to the pragma processor. The info will be put
860 // in a global then read by the TMetaUtils
861 ROOT::TMetaUtils::Info(nullptr,"Pragma generated for ioread rule: %s\n", pragmaLineStream.str().c_str());
862 std::string error_string;
863 if (tagKind == kBeginIoread)
865 else // this is a raw rule
867 if (!error_string.empty())
868 ROOT::TMetaUtils::Error(nullptr, "%s", error_string.c_str());
869 continue; // no need to go further
870 } // end of ioread rules
871
872
873 // We do not want to propagate in the meta the values in the
874 // version tag
875 if (!tagStr.empty() && tagKind != kVersion) {
876
877 if (!exclusion && !IsClosingTag(tagStr)) { // exclusion should be false, we are not interested in closing tags
878 // as well as in key-tags such as <selection> and <lcgdict>
879 if (tagKind == kLcgdict || tagKind == kSelection) {
880 ;// DEBUG std::cout<<"Don't care (don't create sel rule)"<<std::endl;
881 } else {
882 // DEBUG std::cout<<"Yes"<<std::endl;
883 if (tagKind == kField || tagKind == kMethod)
884 bsrChild->SetSelected(BaseSelectionRule::kYes); // if kMethod or kField - add to child
885 else if (bsr)
886 bsr->SetSelected(BaseSelectionRule::kYes);
887 }
888 }
889 else { // if exclusion = true
890 if (IsStandaloneTag(tagStr)) {
891 // DEBUG std::cout<<"No"<<std::endl;
892 if (tagKind == kField || tagKind == kMethod)
893 bsrChild->SetSelected(BaseSelectionRule::kNo);
894 else if (bsr)
895 bsr->SetSelected(BaseSelectionRule::kNo);
896 }
897 else if (tagKind == kClass) {
898 // DEBUG std::cout<<"Don't care (create sel rule)"<<std::endl; // if it is not a standalone tag,
899 //this means it is a parent class tag
900 // In that case we don't care about the class, but we do care about the children, for which the selection
901 // rule should be No. So for the parent class it is - Don't care; for the children it is No
902 bsr->SetSelected(BaseSelectionRule::kDontCare); // this is for the parent
903 }
904 // DEBUG else std::cout<<"Don't care (don't create sel rule)"<<std::endl;
905 }
906
907// // DEBUG std::cout<<"Is child: ";
908// if (inClass){
909// if (((tagKind == kClass)) || tagKind == kEndClass) // if this is the same tag as the parent
910// // or it is a closing tag, the tag is not a child
911// ;// DEBUG std::cout<<"No"<<std::endl;
912// // else if tagKind is one of the following, it means that we have a missing </class> tag
913// // because these tag kinds cannot be children for a parent <class> tag
914// else if (tagKind == kClass || tagKind == kEnum || tagKind == kVariable || tagKind == kFunction ||
915// tagKind == kEndSelection || tagKind == kExclusion || tagKind == kEndExclusion){
916// ROOT::TMetaUtils::Error(0,"XML at line %s. Missing </class> tag\n",lineNumCharp);
917// out.ClearSelectionRules();
918// return false;
919// }
920// // DEBUG else std::cout<<"Yes"<<std::endl;
921// }
922// // DEBUG else std::cout<<"No"<<std::endl;
923
924
925 if (!attrs.empty()){
926 // Cache the name and the value
927 std::string iAttrName;
928 std::string iAttrValue;
929 for (int i = 0, n = attrs.size(); i < n; ++i) {
930 iAttrName=attrs[i].fName;
931 iAttrValue=attrs[i].fValue;
932
933 // request no streamer
934 if (tagKind == kClass && csr && "noStreamer" == iAttrName){
935 if (iAttrValue == "true") {
936 csr->SetRequestNoStreamer(true);
937 } else if (iAttrValue != "false") {
939 "XML at line %s: class attribute 'noStreamer' must be 'true' or 'false' (it was %s)\n",
940 lineNumCharp, iAttrValue.c_str());
941 }
942 }
943
944 // request RNTuple serialization mode
945 if (tagKind == kClass && csr && "rntupleStreamerMode" == iAttrName) {
946 if (iAttrValue == "false") {
947 if (csr->RequestedRNTupleSerializationMode() == -1) {
949 nullptr,
950 "XML at line %s: class attribute 'rntupleStreamerMode' must be either 'true' or 'false', "
951 "not both\n",
952 lineNumCharp, iAttrValue.c_str());
953 } else {
954 csr->SetRequestedRNTupleSerializationMode(1);
955 }
956 } else if (iAttrValue == "true") {
957 if (csr->RequestedRNTupleSerializationMode() == 1) {
959 nullptr,
960 "XML at line %s: class attribute 'rntupleStreamerMode' must be either 'true' or 'false', "
961 "not both\n",
962 lineNumCharp, iAttrValue.c_str());
963 } else {
964 csr->SetRequestedRNTupleSerializationMode(-1);
965 }
966 } else {
968 nullptr,
969 "XML at line %s: class attribute 'rntupleStreamerMode' must be 'true' or 'false' "
970 "(it was %s)\n",
971 lineNumCharp, iAttrValue.c_str());
972 }
973 }
974
975 // request no input operator
976 if (tagKind == kClass && csr && "noInputOperator" == iAttrName){
977 if (iAttrValue == "true") {
978 csr->SetRequestNoInputOperator(true);
979 } else if (iAttrValue != "false") {
981 "XML at line %s: class attribute 'noInputOperator' must be 'true' or 'false' (it was %s)\n",
982 lineNumCharp, iAttrValue.c_str());
983 }
984 }
985
986 // Set the class version
987 if (tagKind == kClass &&
988 csr &&
989 "ClassVersion" == iAttrName){
990 csr->SetRequestedVersionNumber(atoi(iAttrValue.c_str()));
991 continue;
992 }
993
994 if (tagKind == kClass ||
995 tagKind == kTypedef ||
996 tagKind == kProperties ||
997 tagKind == kEnum ||
998 tagKind == kFunction ||
999 tagKind == kVariable) {
1000 if (bsr->HasAttributeWithName(iAttrName)) {
1001 std::string preExistingValue;
1002 bsr->GetAttributeValue(iAttrName,preExistingValue);
1003 if (preExistingValue!=iAttrValue){ // If different from before
1005 "Line %s: assigning new value %s to attribue %s (it was %s)\n",
1006 lineNumCharp,iAttrValue.c_str(),iAttrName.c_str(),preExistingValue.c_str());
1007 out.ClearSelectionRules();
1008 return false;
1009 }
1010 }
1011 bsr->SetAttributeValue(iAttrName, iAttrValue);
1012 if ((iAttrName == "file_name" || iAttrName == "file_pattern") && tagKind == kClass){
1013 bsr->SetAttributeValue("pattern","*");
1014 out.SetHasFileNameRule(true);
1015 }
1016 }
1017 else if (bsrChild) {
1018 if (bsrChild->HasAttributeWithName(iAttrName)) {
1019 std::string preExistingValue;
1020 bsrChild->GetAttributeValue(iAttrName,preExistingValue);
1021 if (preExistingValue!=iAttrValue){ // If different from before
1023 "Line %s: assigning new value %s to attribue %s (it was %s)\n",
1024 lineNumCharp,iAttrValue.c_str(),iAttrName.c_str(),preExistingValue.c_str());
1025 out.ClearSelectionRules();
1026 return false;
1027 }
1028 }
1029 bsrChild->SetAttributeValue(iAttrName, iAttrValue);
1030 }
1031 }
1032 }
1033 }
1034
1035 // add selection rule to the SelectionRules object
1036 // if field or method - add to the class selection rule object
1037 // if parent class, don't add here, add when kEndClass is reached
1038 switch(tagKind) {
1039 case kClass:
1040 if (!inClass) out.AddClassSelectionRule(*csr);
1041 break;
1042 case kTypedef:
1043 out.AddClassSelectionRule(*csr);
1044 break;
1045 case kFunction:
1046 out.AddFunctionSelectionRule(*fsr);
1047 break;
1048 case kVariable:
1049 out.AddVariableSelectionRule(*vsr);
1050 break;
1051 case kEnum:
1052 out.AddEnumSelectionRule(*esr);
1053 break;
1054 case kField:
1055 csr->AddFieldSelectionRule(*vsr);
1056 break;
1057 case kMethod:
1058 csr->AddMethodSelectionRule(*fsr);
1059 break;
1060 default:
1061 break;
1062 }
1063 }
1064 }
1065 // we are outside of the while cycle which means that we have read the whole XML document
1066
1067 if (sel && !selEnd) { // if selEnd is true, it menas that we never had a closing </selection> tag
1068 ROOT::TMetaUtils::Error(nullptr,"Error - missing </selection> tag\n");
1069 out.ClearSelectionRules();
1070 return false;
1071 }
1072 if (excl && !exclEnd ) { // if excl is true and exclEnd is false, it means that we had an opening <exclusion> tag but we
1073 // never had the closing </exclusion> tag
1074 ROOT::TMetaUtils::Error(nullptr,"Error - missing </selection> tag\n");
1075 out.ClearSelectionRules();
1076 return false;
1077 }
1078 return true;
1079
1080}
#define c(i)
Definition RSha256.hxx:101
#define e(i)
Definition RSha256.hxx:103
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t sel
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
char name[80]
Definition TGX11.cxx:110
VariableSelectionRule EnumSelectionRule
VariableSelectionRule FunctionSelectionRule
const_iterator begin() const
const_iterator end() const
The class representing the collection of selection rules.
cling::Interpreter & fInterp
Definition XMLReader.h:48
static bool IsClosingTag(const std::string &tag)
@ kBeginIoreadRaw
Definition XMLReader.h:77
@ kEndIoreadRaw
Definition XMLReader.h:78
@ kEndSelection
Definition XMLReader.h:72
@ kEndLcgdict
Definition XMLReader.h:74
@ kBeginIoread
Definition XMLReader.h:75
@ kEndExclusion
Definition XMLReader.h:73
@ kProperties
Definition XMLReader.h:64
static void PopulateMap()
Definition XMLReader.cxx:30
long fCount
Definition XMLReader.h:47
static std::map< std::string, ETagNames > fgMapTagNames
Definition XMLReader.h:85
static bool CheckIsTagOK(const std::string &tag)
bool Parse(const std::string &fileName, SelectionRules &out)
static bool GetNextTag(std::ifstream &file, std::string &out, int &lineCount)
Definition XMLReader.cxx:73
static bool GetAttributes(const std::string &tag, std::vector< Attributes > &out, const char *lineNum)
static ETagNames GetNameOfTag(const std::string &tag, std::string &name)
static bool IsStandaloneTag(const std::string &tag)
const Int_t n
Definition legend1.C:16
void Error(const char *location, const char *fmt,...)
void Info(const char *location, const char *fmt,...)
void Warning(const char *location, const char *fmt,...)
void ProcessReadPragma(const char *args, std::string &error_string)
I am being called when a read pragma is encountered.
void ProcessReadRawPragma(const char *args, std::string &error_string)
I am being called then a readraw pragma is encountered.