/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 | } |