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