Coverage Report

Created: 2023-12-08 06:53

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