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