1 /*
2    mkvmerge -- utility for splicing together matroska files
3    from component media subtypes
4 
5    Distributed under the GPL v2
6    see the file COPYING for details
7    or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8 
9    XML helper functions
10 
11    Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13 
14 #pragma once
15 
16 #include "common/common_pch.h"
17 
18 #include "pugixml.hpp"
19 
20 namespace mtx::xml {
21 
22 class exception: public mtx::exception {
23 public:
what()24   virtual const char *what() const throw() {
25     return "generic XML error";
26   }
27 };
28 
29 class conversion_x: public exception {
30 protected:
31   std::string m_message;
32 public:
conversion_x(std::string const & message)33   conversion_x(std::string const &message) : m_message{message} { }
~conversion_x()34   virtual ~conversion_x() throw() { }
35 
what()36   virtual char const *what() const throw() {
37     return m_message.c_str();
38   }
39 };
40 
41 class invalid_attribute_x: public exception {
42 protected:
43   std::string m_message, m_node, m_attribute;
44   ptrdiff_t m_position;
45 public:
invalid_attribute_x(std::string const & node,std::string const & attribute,ptrdiff_t position)46   invalid_attribute_x(std::string const &node, std::string const &attribute, ptrdiff_t position)
47     : m_node(node)
48     , m_attribute(attribute)
49     , m_position(position)
50   {
51     m_message = fmt::format(Y("Invalid attribute '{0}' in node '{1}' at position {2}"), m_attribute, m_node, m_position);
52   }
~invalid_attribute_x()53   virtual ~invalid_attribute_x() throw() { }
54 
what()55   virtual char const *what() const throw() {
56     return m_message.c_str();
57   }
58 };
59 
60 class invalid_child_node_x: public exception {
61 protected:
62   std::string m_message, m_node, m_parent;
63   ptrdiff_t m_position;
64 public:
invalid_child_node_x(std::string const & node,std::string const & parent,ptrdiff_t position)65   invalid_child_node_x(std::string const &node, std::string const &parent, ptrdiff_t position)
66     : m_node(node)
67     , m_parent(parent)
68     , m_position(position)
69   {
70     m_message = fmt::format(Y("<{0}> is not a valid child element of <{1}> at position {2}."), m_node, m_parent, m_position);
71   }
~invalid_child_node_x()72   virtual ~invalid_child_node_x() throw() { }
73 
what()74   virtual char const *what() const throw() {
75     return m_message.c_str();
76   }
77 };
78 
79 class duplicate_child_node_x: public exception {
80 protected:
81   std::string m_message, m_node, m_parent;
82   ptrdiff_t m_position;
83 public:
duplicate_child_node_x(std::string const & node,std::string const & parent,ptrdiff_t position)84   duplicate_child_node_x(std::string const &node, std::string const &parent, ptrdiff_t position)
85     : m_node(node)
86     , m_parent(parent)
87     , m_position(position)
88   {
89     m_message = fmt::format(Y("Only one instance of <{0}> is allowed beneath <{1}> at position {2}."), m_node, m_parent, m_position);
90   }
~duplicate_child_node_x()91   virtual ~duplicate_child_node_x() throw() { }
92 
what()93   virtual char const *what() const throw() {
94     return m_message.c_str();
95   }
96 };
97 
98 class malformed_data_x: public exception {
99 protected:
100   std::string m_message, m_node;
101   ptrdiff_t m_position;
102 public:
103   malformed_data_x(std::string const &node, ptrdiff_t position, std::string const &details = std::string{})
m_node(node)104     : m_node(node)
105     , m_position(position)
106   {
107     m_message = fmt::format(Y("The tag or attribute '{0}' at position {1} contains invalid or mal-formed data."), m_node, m_position);
108     if (!details.empty())
109       m_message += " " + details;
110   }
~malformed_data_x()111   virtual ~malformed_data_x() throw() { }
112 
what()113   virtual char const *what() const throw() {
114     return m_message.c_str();
115   }
116 };
117 
118 class out_of_range_x: public exception {
119 protected:
120   std::string m_message, m_node;
121   ptrdiff_t m_position;
122 public:
123   out_of_range_x(std::string const &node, ptrdiff_t position, std::string const &details = std::string{})
m_node(node)124     : m_node(node)
125     , m_position(position)
126   {
127     m_message = fmt::format(Y("The tag or attribute '{0}' at position {1} contains data that is outside its allowed range."), m_node, m_position);
128     if (!details.empty())
129       m_message += " " + details;
130   }
~out_of_range_x()131   virtual ~out_of_range_x() throw() { }
132 
what()133   virtual char const *what() const throw() {
134     return m_message.c_str();
135   }
136 };
137 
138 class xml_parser_x: public exception {
139 protected:
140   pugi::xml_parse_result m_result;
141 public:
xml_parser_x(pugi::xml_parse_result const & result)142   xml_parser_x(pugi::xml_parse_result const &result) : m_result(result) { }
what()143   virtual const char *what() const throw() {
144     return "XML parser error";
145   }
result()146   pugi::xml_parse_result const &result() {
147     return m_result;
148   }
149 };
150 
151 std::string escape(const std::string &src);
152 std::string create_node_name(const char *name, const char **atts);
153 
154 using document_cptr = std::shared_ptr<pugi::xml_document>;
155 
156 document_cptr load_file(std::string const &file_name, unsigned int options = pugi::parse_default, std::optional<int64_t> max_read_size = std::optional<int64_t>{});
157 
158 }
159