ATLAS Offline Software
Loading...
Searching...
No Matches
ExpatCoreParser.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include "ExpatCoreParser.h"
9#include <expat.h>
10#include <fstream>
11#include <cstdlib>
12#include <sstream>
13#include <array>
14#include <iostream>
15#include <filesystem>
16
17namespace {
18 constexpr std::size_t BUFFSIZE = 1000;
19 //empty string to use in returns
20 const std::string emptyString;
21 constexpr int errorValue{0};
22 constexpr int ok{1};
23}
24
25using namespace XmlParser;
26
28ExpatCoreParser::ExternalEntityMap ExpatCoreParser::s_entities;
29ExpatCoreParser::ExternalEntityMap ExpatCoreParser::s_text_entities;
30
31
32void
33ExpatCoreParser::start (void* user_data, const char* el, const char** attr){
34 auto& me = *static_cast<ExpatCoreParser*> (user_data);
35 me.do_start (el, attr);
36}
37
38void
39ExpatCoreParser::end (void* user_data, const char* el){
40 auto& me = *static_cast<ExpatCoreParser*> (user_data);
41 me.do_end (el);
42}
43
44void
45ExpatCoreParser::char_data (void* user_data, const XML_Char* s, int len){
46 auto& me = *static_cast<ExpatCoreParser*> (user_data);
47 me.do_char_data (s, len);
48}
49
50void
51ExpatCoreParser::default_handler (void* user_data, const XML_Char* s, int len){
52 auto& me = *static_cast<ExpatCoreParser*> (user_data);
53 me.do_default_handler (s, len);
54}
55
56void
57ExpatCoreParser::comment (void* user_data, const XML_Char* s){
58 auto& me = *static_cast<ExpatCoreParser*> (user_data);
59 me.do_comment (s);
60}
61
62int
63ExpatCoreParser::external_entity (XML_Parser parser, const XML_Char* context,
64 const XML_Char* /*base*/,const XML_Char* systemId, const XML_Char* /*publicId*/){
65 void* user_data = XML_GetUserData (parser);
66 auto& me = *static_cast<ExpatCoreParser*> (user_data);
67 return (me.do_external_entity (parser, context, systemId));
68}
69
70void
71ExpatCoreParser::register_external_entity (const std::string& name, const std::string& file_name) {
72 if (debug_enabled()){
73 std::cout << label()<<"> name=" << name << " file_name=" << file_name << "\n";
74 }
76 s_entities[name] = file_name;
77}
78
79void
80ExpatCoreParser::register_text_entity (const std::string& name, const std::string& text) {
81 if (debug_enabled()) {
82 std::cout << label()<<"> name=" << name<< "\n";
83 }
85 s_text_entities[name] = text;
86}
87
88
89std::unique_ptr<XMLCoreNode>
91 return std::move(m_top);
92}
93
94ExpatCoreParser::ExpatCoreParser (const std::string& prefix)
95 : m_top (nullptr),
96 m_last (nullptr),
97 m_prefix (prefix){
98}
99
100void
102 XML_SetParamEntityParsing(p, XML_PARAM_ENTITY_PARSING_ALWAYS);
103 XML_SetElementHandler(p, start, end);
104 XML_SetCharacterDataHandler(p, char_data);
105 XML_SetExternalEntityRefHandler(p, external_entity);
106 XML_SetCommentHandler(p, comment);
107 XML_SetUserData(p, this);
108}
109
111ExpatCoreParser::add_node (std::unique_ptr<XMLCoreNode> node){
112 if (!m_top){
113 m_top = std::make_unique<XMLCoreNode> (XMLCoreNode::DOCUMENT_NODE);
114 m_last = m_top.get();
115 }
116
117 return m_last->add_child (std::move(node));
118}
119
120void
121ExpatCoreParser::do_start (const char* el, const char** attr){
122 auto node = std::make_unique<XMLCoreNode> (XMLCoreNode::ELEMENT_NODE, el);
123 if (debug_enabled()) {
124 std::cout << label()<< "> el=" << el << " top=" << m_top.get() << " last=" << m_last << " node=" << node << "\n";
125 }
126 for (int i = 0; attr[i]; i += 2) {
127 const char* name = attr[i];
128 const char* value = attr[i+1];
129 node->set_attrib (name, value);
130 }
131 m_last = add_node (std::move(node));
132}
133
134void
135ExpatCoreParser::do_end (const char* el){
136 if (debug_enabled()){
137 std::cout <<label()<<"> el=" << el << "\n";
138 }
139 m_last = m_last->get_parent();
140}
141
142void
143ExpatCoreParser::do_char_data (const XML_Char* s, int len){
144 std::string text = rtrim(s, len);
145 if (text.empty()) return;
146 if (debug_enabled()) {
147 std::cout << label()<<"> [" << text << "]\n";
148 }
149 add_node (std::make_unique<XMLCoreNode>(XMLCoreNode::TEXT_NODE, "", text));
150}
151
152void
153ExpatCoreParser::do_default_handler (const XML_Char* s, int len){
154 std::string text = rtrim(s, len);
155 if (text.empty()) return;
156 if (debug_enabled()) {
157 std::cout << label()<<"> [" << text << "]\n";
158 }
159}
160
161void
162ExpatCoreParser::do_comment (const XML_Char* s){
163 auto node = std::make_unique<XMLCoreNode> (XMLCoreNode::COMMENT_NODE, "", s);
164 if (debug_enabled()) {
165 std::cout << label()<<"> s=" << s << " top=" << m_top.get() << " last=" << m_last << " node=" << node << "\n";
166 }
167 add_node (std::move(node));
168}
169
170int
171ExpatCoreParser::stream_parse(XML_Parser p, std::istream& is, const std::string & source_name){
172 int result = ok;
174 if (debug_enabled()) {
175 std::cout << label() << "> starting\n";
176 }
177 std::array<char, BUFFSIZE> buff{};
178 for (;;) {
179 is.read(buff.data(), buff.size());
180 const auto nbytes = is.gcount();
181 const bool done = is.eof();
182 if (is.bad()) {
183 std::cout << "Read error";
184 if (!source_name.empty()) {
185 std::cout << " in " << source_name;
186 }
187 std::cout << "\n";
188 result = errorValue;
189 break;
190 }
191 if (XML_Parse(p, buff.data(), static_cast<int>(nbytes), done) == XML_STATUS_ERROR) {
192 std::cout << "ExpatCoreParser::Parse error at line "
193 << XML_GetCurrentLineNumber(p);
194 if (!source_name.empty()) {
195 std::cout << " of " << source_name;
196 }
197 std::cout << ":\n" << XML_ErrorString(XML_GetErrorCode(p)) << "\n";
198 result = errorValue;
199 break;
200 }
201 if (done) {
202 break;
203 }
204 }
205 return result;
206}
207
208
209int
210ExpatCoreParser::generic_parse(XML_Parser p, const std::string& file_name){
211 const std::string& path = xmlFileName(file_name, m_prefix);
212 if (path.empty()) return errorValue;
213 if (debug_enabled()) {
214 std::cout << label() << "> file_name=" << file_name
215 << " prefix=" << m_prefix << "\n";
216 }
217 std::ifstream fs{path, std::ios::binary};
218 if (!fs) {
219 std::cout << "Could not open file " << path << "\n";
220 return errorValue;
221 }
222 return stream_parse(p, fs, file_name);
223}
224
225int
226ExpatCoreParser::generic_text_parse(XML_Parser p, const std::string& text){
227 if (debug_enabled()) {
228 std::cout << label() << ">\n";
229 }
230 std::istringstream is(text);
231 return stream_parse(p, is, {});
232}
233
234int
235ExpatCoreParser::do_external_entity(XML_Parser parser, const XML_Char* context, const XML_Char* systemId){
236 const std::string context_str = context ? context : "none";
237 if (context != nullptr) {
238 const std::string replacement = find_text_entity(context_str);
239 if (!replacement.empty()) {
240 if (debug_enabled()) {
241 std::cout << label() << "> context=[" << context_str
242 << "] replacement=[" << replacement << "]\n";
243 }
244 XMLParserPtr p{XML_ExternalEntityParserCreate(parser, context, nullptr)};
245 if (!p) return errorValue;
246 return generic_text_parse(p.get(), replacement);
247 }
248 }
249 std::string replacement = find_external_entity(context_str);
250 if (replacement == "NULL") {
251 return ok;
252 }
253 std::string originalSystemId = systemId ? systemId : "";
254 std::string effectiveSystemId = originalSystemId;
255 if (!replacement.empty()) {
256 effectiveSystemId = replacement;
257 }
258 if (debug_enabled()) {
259 std::cout << label() << "> context=[" << context_str
260 << "] systemId=[" << originalSystemId
261 << "] replacement=[" << replacement << "]\n";
262 }
263 XMLParserPtr p{XML_ExternalEntityParserCreate(parser, context, nullptr)};
264 if (!p) return errorValue;
265 return generic_parse(p.get(), effectiveSystemId);
266}
267
268std::string
269ExpatCoreParser::find_entity (const std::string& name, const ExternalEntityMap& mapChoice){
270 //lock is held here, doesn't need to be held by caller
272 ExternalEntityMap::const_iterator it = mapChoice.find(name);
273 return (it == mapChoice.end()) ? emptyString : it->second;
274}
275std::string
277 //coverity[MISSING_LOCK:FALSE]
278 return find_entity(name, s_entities);
279}
280
281std::string
282ExpatCoreParser::find_text_entity (const std::string& name){
283 //coverity[MISSING_LOCK:FALSE]
284 return find_entity(name, s_text_entities);
285}
286
287std::unique_ptr<XMLCoreNode>
288ExpatCoreParser::parse (std::string_view file_name){
289 const std::filesystem::path path{file_name};
290 ExpatCoreParser me{path.parent_path().string()};
291 auto p = make_parser();
292 int result = me.generic_parse (p.get(), path.filename().string());
293 if (result == errorValue) return nullptr;
294 return me.get_document ();
295}
296
297
298std::unique_ptr<XMLCoreNode>
299ExpatCoreParser::parse_string (const std::string& text){
300 ExpatCoreParser me ("");
301 auto p = make_parser();
302 int result = me.generic_text_parse (p.get(), text);
303 if (result == errorValue) return nullptr;
304 return me.get_document ();
305}
306
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
static Double_t fs
Various text/ptr utilities to use in the ExpatCoreParser.
int generic_text_parse(XML_Parser p, const std::string &text)
std::string find_text_entity(const std::string &name)
void do_start(const char *el, const char **attr)
static void register_text_entity(const std::string &name, const std::string &text)
void do_default_handler(const XML_Char *s, int len)
std::string find_external_entity(const std::string &name)
std::string m_prefix
XMLCoreNode * add_node(std::unique_ptr< XMLCoreNode > node)
static void char_data(void *, const XML_Char *s, int len)
static int external_entity(XML_Parser parser, const XML_Char *context, const XML_Char *, const XML_Char *systemId, const XML_Char *)
void configure_parser(XML_Parser p)
std::lock_guard< std::mutex > lock_t
int generic_parse(XML_Parser p, const std::string &file_name)
static void start(void *, const char *el, const char **attr)
std::string find_entity(const std::string &name, const ExternalEntityMap &mapChoice)
void do_end(const char *el)
static void default_handler(void *, const XML_Char *s, int len)
std::unique_ptr< XMLCoreNode > get_document()
void do_comment(const XML_Char *s)
static std::unique_ptr< XMLCoreNode > parse(std::string_view file_name)
void do_char_data(const XML_Char *s, int len)
XMLCoreNode * m_last
static std::unique_ptr< XMLCoreNode > parse_string(const std::string &text)
static void register_external_entity(const std::string &name, const std::string &file_name)
int stream_parse(XML_Parser p, std::istream &is, const std::string &source_name={})
std::unique_ptr< XMLCoreNode > m_top
static void comment(void *, const XML_Char *s)
std::map< std::string, std::string > ExternalEntityMap
int do_external_entity(XML_Parser parser, const XML_Char *context, const XML_Char *systemId)
static void end(void *, const char *el)
ExpatCoreParser(const std::string &prefix)
static std::mutex s_mutex
Simple DOM-like node structure to hold the result of XML parsing.
Definition XMLCoreNode.h:45
Definition node.h:24
std::string xmlFileName(const std::string &fname, const std::string &prefix)
find the xml file locally or on the datapath, return the full filename
bool debug_enabled()
true if XML debug mode is enabled in the environment
XMLParserPtr make_parser()
Create an RAII XMLParser pointer.
std::unique_ptr< std::remove_pointer_t< XML_Parser >, XMLParserDeleter > XMLParserPtr
RAII XMLParser pointer.
std::string label(const std::source_location loc=std::source_location::current())
report function name in a string, for debugging
std::string rtrim(const XML_Char *s, int len)
Trim newline from end of a XML_Char * , return the trimmed string as std::string.