Coverage Report

Created: 2026-10-28 06:38

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