openMSX
XMLLoader.cc
Go to the documentation of this file.
1 #include "XMLLoader.hh"
2 #include "XMLElement.hh"
3 #include "XMLException.hh"
4 #include "File.hh"
5 #include "FileException.hh"
6 #include "MemBuffer.hh"
7 #include "rapidsax.hh"
8 
9 using std::string;
10 using std::string_view;
11 
12 namespace openmsx::XMLLoader {
13 
15 {
16 public:
17  // rapidsax handler interface
18  void start(string_view name);
19  void attribute(string_view name, string_view value);
20  void text(string_view txt);
21  void stop();
22  void doctype(string_view txt);
23 
24  string_view getSystemID() const { return systemID; }
25  XMLElement& getRoot() { return root; }
26 
27 private:
28  XMLElement root;
29  std::vector<XMLElement*> current;
30  string_view systemID;
31 };
32 
33 XMLElement load(string_view filename, string_view systemID)
34 {
35  MemBuffer<char> buf;
36  try {
37  File file(filename);
38  auto size = file.getSize();
40  file.read(buf.data(), size);
41  buf[size] = 0;
42  } catch (FileException& e) {
43  throw XMLException(filename, ": failed to read: ", e.getMessage());
44  }
45 
46  XMLElementParser handler;
47  try {
48  rapidsax::parse<rapidsax::trimWhitespace>(handler, buf.data());
49  } catch (rapidsax::ParseError& e) {
50  throw XMLException(filename, ": Document parsing failed: ", e.what());
51  }
52  auto& root = handler.getRoot();
53  if (root.getName().empty()) {
54  throw XMLException(filename,
55  ": Document doesn't contain mandatory root Element");
56  }
57  if (handler.getSystemID().empty()) {
58  throw XMLException(filename, ": Missing systemID.\n"
59  "You're probably using an old incompatible file format.");
60  }
61  if (handler.getSystemID() != systemID) {
62  throw XMLException(filename, ": systemID doesn't match "
63  "(expected ", systemID, ", got ", handler.getSystemID(), ")\n"
64  "You're probably using an old incompatible file format.");
65  }
66  return std::move(root);
67 }
68 
69 void XMLElementParser::start(string_view name)
70 {
71  XMLElement* newElem;
72  if (!current.empty()) {
73  newElem = &current.back()->addChild(string(name));
74  } else {
75  root.setName(string(name));
76  newElem = &root;
77  }
78  current.push_back(newElem);
79 }
80 
81 void XMLElementParser::attribute(string_view name, string_view value)
82 {
83  if (current.back()->hasAttribute(name)) {
84  throw XMLException(
85  "Found duplicate attribute \"", name, "\" in <",
86  current.back()->getName(), ">.");
87  }
88  current.back()->addAttribute(string(name), string(value));
89 }
90 
91 void XMLElementParser::text(string_view txt)
92 {
93  if (current.back()->hasChildren()) {
94  // no mixed-content elements
95  throw XMLException(
96  "Mixed text+subtags in <", current.back()->getName(),
97  ">: \"", txt, "\".");
98  }
99  current.back()->setData(string(txt));
100 }
101 
103 {
104  current.pop_back();
105 }
106 
107 void XMLElementParser::doctype(string_view txt)
108 {
109  auto pos1 = txt.find(" SYSTEM ");
110  if (pos1 == string_view::npos) return;
111  if ((pos1 + 8) >= txt.size()) return;
112  char q = txt[pos1 + 8];
113  if ((q != '"') && (q != '\'')) return;
114  auto t = txt.substr(pos1 + 9);
115  auto pos2 = t.find(q);
116  if (pos2 == string_view::npos) return;
117 
118  systemID = t.substr(0, pos2);
119 }
120 
121 } // namespace openmsx::XMLLoader
void doctype(string_view txt)
Definition: XMLLoader.cc:107
size_t getSize()
Returns the size of this file.
Definition: File.cc:103
const std::string & getMessage() const &
Definition: MSXException.hh:23
void setName(std::string name_)
Definition: XMLElement.hh:32
void start(string_view name)
Definition: XMLLoader.cc:69
void text(string_view txt)
Definition: XMLLoader.cc:91
string_view getSystemID() const
Definition: XMLLoader.cc:24
size_t size(std::string_view utf8)
constexpr const char *const filename
void resize(size_t size)
Grow or shrink the memory block.
Definition: MemBuffer.hh:120
const T * data() const
Returns pointer to the start of the memory buffer.
Definition: MemBuffer.hh:90
XMLElement load(string_view filename, string_view systemID)
Definition: XMLLoader.cc:33
void attribute(string_view name, string_view value)
Definition: XMLLoader.cc:81
void read(void *buffer, size_t num)
Read from file.
Definition: File.cc:83
const char * what() const
Definition: rapidsax.hh:110
constexpr size_t EXTRA_BUFFER_SPACE
Definition: rapidsax.hh:40
TclObject t