Coverage Report

Created: 2025-06-20 06:51

/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
9.37k
{
15
9.37k
  this->Parser = nullptr;
16
9.37k
  this->ParseError = 0;
17
9.37k
  this->ReportCallback = nullptr;
18
9.37k
  this->ReportCallbackData = nullptr;
19
9.37k
}
20
21
cmXMLParser::~cmXMLParser()
22
9.37k
{
23
9.37k
  if (this->Parser) {
24
2.56k
    this->CleanupParser();
25
2.56k
  }
26
9.37k
}
27
28
int cmXMLParser::Parse(char const* string)
29
9.37k
{
30
9.37k
  return this->InitializeParser() &&
31
9.37k
    this->ParseChunk(string, strlen(string)) && this->CleanupParser();
32
9.37k
}
33
34
int cmXMLParser::ParseFile(char const* file)
35
9.37k
{
36
9.37k
  if (!file) {
37
0
    return 0;
38
0
  }
39
40
9.37k
  cmsys::ifstream ifs(file);
41
9.37k
  if (!ifs) {
42
0
    return 0;
43
0
  }
44
45
9.37k
  std::ostringstream str;
46
9.37k
  str << ifs.rdbuf();
47
9.37k
  return this->Parse(str.str().c_str());
48
9.37k
}
49
50
int cmXMLParser::InitializeParser()
51
9.37k
{
52
9.37k
  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
9.37k
  this->Parser = XML_ParserCreate(nullptr);
60
9.37k
  XML_SetElementHandler(static_cast<XML_Parser>(this->Parser),
61
9.37k
                        &cmXMLParserStartElement, &cmXMLParserEndElement);
62
9.37k
  XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser),
63
9.37k
                              &cmXMLParserCharacterDataHandler);
64
9.37k
  XML_SetUserData(static_cast<XML_Parser>(this->Parser), this);
65
9.37k
  this->ParseError = 0;
66
9.37k
  return 1;
67
9.37k
}
68
69
int cmXMLParser::ParseChunk(char const* inputString,
70
                            std::string::size_type length)
71
9.37k
{
72
9.37k
  if (!this->Parser) {
73
0
    std::cerr << "Parser not initialized" << std::endl;
74
0
    this->ParseError = 1;
75
0
    return 0;
76
0
  }
77
9.37k
  int res;
78
9.37k
  res = this->ParseBuffer(inputString, length);
79
9.37k
  if (res == 0) {
80
2.56k
    this->ParseError = 1;
81
2.56k
  }
82
9.37k
  return res;
83
9.37k
}
84
85
int cmXMLParser::CleanupParser()
86
9.37k
{
87
9.37k
  if (!this->Parser) {
88
0
    std::cerr << "Parser not initialized" << std::endl;
89
0
    this->ParseError = 1;
90
0
    return 0;
91
0
  }
92
9.37k
  int result = !this->ParseError;
93
9.37k
  if (result) {
94
    // Tell the expat XML parser about the end-of-input.
95
6.81k
    if (!XML_Parse(static_cast<XML_Parser>(this->Parser), "", 0, 1)) {
96
4.04k
      this->ReportXmlParseError();
97
4.04k
      result = 0;
98
4.04k
    }
99
6.81k
  }
100
101
  // Clean up the parser.
102
9.37k
  XML_ParserFree(static_cast<XML_Parser>(this->Parser));
103
9.37k
  this->Parser = nullptr;
104
105
9.37k
  return result;
106
9.37k
}
107
108
int cmXMLParser::ParseBuffer(char const* buffer, std::string::size_type count)
109
9.37k
{
110
  // Pass the buffer to the expat XML parser.
111
9.37k
  if (!XML_Parse(static_cast<XML_Parser>(this->Parser), buffer,
112
9.37k
                 static_cast<int>(count), 0)) {
113
2.56k
    this->ReportXmlParseError();
114
2.56k
    return 0;
115
2.56k
  }
116
6.81k
  return 1;
117
9.37k
}
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
286k
{
132
286k
  std::cout << "Start element: " << name << std::endl;
133
286k
}
134
135
void cmXMLParser::EndElement(std::string const& name)
136
175k
{
137
175k
  std::cout << "End element: " << name << std::endl;
138
175k
}
139
140
void cmXMLParser::CharacterDataHandler(char const* /*inData*/,
141
                                       int /*inLength*/)
142
7.60M
{
143
7.60M
}
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
286k
{
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
286k
  static_cast<cmXMLParser*>(parser)->StartElement(name, atts);
164
286k
}
165
166
void cmXMLParserEndElement(void* parser, char const* name)
167
175k
{
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
175k
  static_cast<cmXMLParser*>(parser)->EndElement(name);
171
175k
}
172
173
void cmXMLParserCharacterDataHandler(void* parser, char const* data,
174
                                     int length)
175
7.60M
{
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
7.60M
  static_cast<cmXMLParser*>(parser)->CharacterDataHandler(data, length);
180
7.60M
}
181
182
void cmXMLParser::ReportXmlParseError()
183
6.60k
{
184
6.60k
  XML_Parser parser = static_cast<XML_Parser>(this->Parser);
185
6.60k
  this->ReportError(static_cast<int>(XML_GetCurrentLineNumber(parser)),
186
6.60k
                    static_cast<int>(XML_GetCurrentColumnNumber(parser)),
187
6.60k
                    XML_ErrorString(XML_GetErrorCode(parser)));
188
6.60k
}
189
190
void cmXMLParser::ReportError(int line, int /*unused*/, char const* msg)
191
6.60k
{
192
6.60k
  if (this->ReportCallback) {
193
0
    this->ReportCallback(line, msg, this->ReportCallbackData);
194
6.60k
  } else {
195
6.60k
    std::cerr << "Error parsing XML in stream at line " << line << ": " << msg
196
6.60k
              << std::endl;
197
6.60k
  }
198
6.60k
}