Coverage Report

Created: 2025-07-11 07:20

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