Coverage Report

Created: 2023-06-07 06:17

/src/CMake/Source/cmXMLParser.cxx
Line
Count
Source (jump to first uncovered line)
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file Copyright.txt or https://cmake.org/licensing for details.  */
3
#include "cmXMLParser.h"
4
5
#include <cctype>
6
#include <cstring>
7
#include <iostream>
8
#include <sstream>
9
10
#include <cm3p/expat.h>
11
12
#include "cmsys/FStream.hxx"
13
14
cmXMLParser::cmXMLParser()
15
7.48k
{
16
7.48k
  this->Parser = nullptr;
17
7.48k
  this->ParseError = 0;
18
7.48k
  this->ReportCallback = nullptr;
19
7.48k
  this->ReportCallbackData = nullptr;
20
7.48k
}
21
22
cmXMLParser::~cmXMLParser()
23
7.48k
{
24
7.48k
  if (this->Parser) {
25
3.65k
    this->CleanupParser();
26
3.65k
  }
27
7.48k
}
28
29
int cmXMLParser::Parse(const char* string)
30
7.48k
{
31
7.48k
  return this->InitializeParser() &&
32
7.48k
    this->ParseChunk(string, strlen(string)) && this->CleanupParser();
33
7.48k
}
34
35
int cmXMLParser::ParseFile(const char* file)
36
7.48k
{
37
7.48k
  if (!file) {
38
0
    return 0;
39
0
  }
40
41
7.48k
  cmsys::ifstream ifs(file);
42
7.48k
  if (!ifs) {
43
0
    return 0;
44
0
  }
45
46
7.48k
  std::ostringstream str;
47
7.48k
  str << ifs.rdbuf();
48
7.48k
  return this->Parse(str.str().c_str());
49
7.48k
}
50
51
int cmXMLParser::InitializeParser()
52
7.48k
{
53
7.48k
  if (this->Parser) {
54
0
    std::cerr << "Parser already initialized" << std::endl;
55
0
    this->ParseError = 1;
56
0
    return 0;
57
0
  }
58
59
  // Create the expat XML parser.
60
7.48k
  this->Parser = XML_ParserCreate(nullptr);
61
7.48k
  XML_SetElementHandler(static_cast<XML_Parser>(this->Parser),
62
7.48k
                        &cmXMLParserStartElement, &cmXMLParserEndElement);
63
7.48k
  XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser),
64
7.48k
                              &cmXMLParserCharacterDataHandler);
65
7.48k
  XML_SetUserData(static_cast<XML_Parser>(this->Parser), this);
66
7.48k
  this->ParseError = 0;
67
7.48k
  return 1;
68
7.48k
}
69
70
int cmXMLParser::ParseChunk(const char* inputString,
71
                            std::string::size_type length)
72
7.48k
{
73
7.48k
  if (!this->Parser) {
74
0
    std::cerr << "Parser not initialized" << std::endl;
75
0
    this->ParseError = 1;
76
0
    return 0;
77
0
  }
78
7.48k
  int res;
79
7.48k
  res = this->ParseBuffer(inputString, length);
80
7.48k
  if (res == 0) {
81
3.65k
    this->ParseError = 1;
82
3.65k
  }
83
7.48k
  return res;
84
7.48k
}
85
86
int cmXMLParser::CleanupParser()
87
7.48k
{
88
7.48k
  if (!this->Parser) {
89
0
    std::cerr << "Parser not initialized" << std::endl;
90
0
    this->ParseError = 1;
91
0
    return 0;
92
0
  }
93
7.48k
  int result = !this->ParseError;
94
7.48k
  if (result) {
95
    // Tell the expat XML parser about the end-of-input.
96
3.82k
    if (!XML_Parse(static_cast<XML_Parser>(this->Parser), "", 0, 1)) {
97
3.77k
      this->ReportXmlParseError();
98
3.77k
      result = 0;
99
3.77k
    }
100
3.82k
  }
101
102
  // Clean up the parser.
103
7.48k
  XML_ParserFree(static_cast<XML_Parser>(this->Parser));
104
7.48k
  this->Parser = nullptr;
105
106
7.48k
  return result;
107
7.48k
}
108
109
int cmXMLParser::ParseBuffer(const char* buffer, std::string::size_type count)
110
7.48k
{
111
  // Pass the buffer to the expat XML parser.
112
7.48k
  if (!XML_Parse(static_cast<XML_Parser>(this->Parser), buffer,
113
7.48k
                 static_cast<int>(count), 0)) {
114
3.65k
    this->ReportXmlParseError();
115
3.65k
    return 0;
116
3.65k
  }
117
3.82k
  return 1;
118
7.48k
}
119
120
int cmXMLParser::ParseBuffer(const char* buffer)
121
0
{
122
0
  return this->ParseBuffer(buffer, static_cast<int>(strlen(buffer)));
123
0
}
124
125
int cmXMLParser::ParsingComplete()
126
0
{
127
  // Default behavior is to parse to end of stream.
128
0
  return 0;
129
0
}
130
131
void cmXMLParser::StartElement(const std::string& name, const char** /*atts*/)
132
1.35M
{
133
1.35M
  std::cout << "Start element: " << name << std::endl;
134
1.35M
}
135
136
void cmXMLParser::EndElement(const std::string& name)
137
149k
{
138
149k
  std::cout << "End element: " << name << std::endl;
139
149k
}
140
141
void cmXMLParser::CharacterDataHandler(const char* /*inData*/,
142
                                       int /*inLength*/)
143
1.87M
{
144
1.87M
}
145
146
int cmXMLParser::IsSpace(char c)
147
0
{
148
0
  return isspace(c);
149
0
}
150
151
const char* cmXMLParser::FindAttribute(const char** atts,
152
                                       const char* attribute)
153
0
{
154
0
  if (atts && attribute) {
155
0
    for (const char** a = atts; *a && *(a + 1); a += 2) {
156
0
      if (strcmp(*a, attribute) == 0) {
157
0
        return *(a + 1);
158
0
      }
159
0
    }
160
0
  }
161
0
  return nullptr;
162
0
}
163
164
void cmXMLParserStartElement(void* parser, const char* name, const char** atts)
165
1.35M
{
166
  // Begin element handler that is registered with the XML_Parser.
167
  // This just casts the user data to a cmXMLParser and calls
168
  // StartElement.
169
1.35M
  static_cast<cmXMLParser*>(parser)->StartElement(name, atts);
170
1.35M
}
171
172
void cmXMLParserEndElement(void* parser, const char* name)
173
149k
{
174
  // End element handler that is registered with the XML_Parser.  This
175
  // just casts the user data to a cmXMLParser and calls EndElement.
176
149k
  static_cast<cmXMLParser*>(parser)->EndElement(name);
177
149k
}
178
179
void cmXMLParserCharacterDataHandler(void* parser, const char* data,
180
                                     int length)
181
1.87M
{
182
  // Character data handler that is registered with the XML_Parser.
183
  // This just casts the user data to a cmXMLParser and calls
184
  // CharacterDataHandler.
185
1.87M
  static_cast<cmXMLParser*>(parser)->CharacterDataHandler(data, length);
186
1.87M
}
187
188
void cmXMLParser::ReportXmlParseError()
189
7.43k
{
190
7.43k
  XML_Parser parser = static_cast<XML_Parser>(this->Parser);
191
7.43k
  this->ReportError(static_cast<int>(XML_GetCurrentLineNumber(parser)),
192
7.43k
                    static_cast<int>(XML_GetCurrentColumnNumber(parser)),
193
7.43k
                    XML_ErrorString(XML_GetErrorCode(parser)));
194
7.43k
}
195
196
void cmXMLParser::ReportError(int line, int /*unused*/, const char* msg)
197
7.43k
{
198
7.43k
  if (this->ReportCallback) {
199
0
    this->ReportCallback(line, msg, this->ReportCallbackData);
200
7.43k
  } else {
201
7.43k
    std::cerr << "Error parsing XML in stream at line " << line << ": " << msg
202
7.43k
              << std::endl;
203
7.43k
  }
204
7.43k
}