summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/xmlfile.h
blob: ba3a1176e2581d9d82aa93716ff1b28400417fae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    xmlfile.h

    XML file parsing code.

***************************************************************************/
#ifndef MAME_LIB_UTIL_XMLFILE_H
#define MAME_LIB_UTIL_XMLFILE_H

#pragma once

#include "corefile.h"

#include <list>
#include <string>
#include <utility>


// forward type declarations
struct XML_ParserStruct;


namespace util::xml {

/***************************************************************************
    CONSTANTS
***************************************************************************/

enum
{
	PARSE_FLAG_WHITESPACE_SIGNIFICANT = 1
};



/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

/* extended error information from parsing */
struct parse_error
{
	parse_error() = default;

	const char *            error_message = nullptr;
	int                     error_line = 0;
	int                     error_column = 0;
};


// parsing options
struct parse_options
{
	parse_options() = default;

	parse_error *       error = nullptr;
	void                (*init_parser)(XML_ParserStruct *parser) = nullptr;
	uint32_t            flags = 0;
};


// a node representing a data item and its relationships
class data_node
{
public:
	enum class int_format
	{
		DECIMAL,
		DECIMAL_HASH,
		HEX_DOLLAR,
		HEX_C
	};


	/* ----- XML node management ----- */

	char const *get_name() const { return m_name.empty() ? nullptr : m_name.c_str(); }

	char const *get_value() const { return m_value.empty() ? nullptr : m_value.c_str(); }
	void set_value(char const *value);
	void append_value(char const *value, int length);
	void trim_whitespace();

	data_node *get_parent() { return m_parent; }
	data_node const *get_parent() const { return m_parent; }

	// count the number of children
	std::size_t count_children() const;
	std::size_t count_attributes() const;

	// get the first child
	data_node *get_first_child() { return m_first_child; }
	data_node const *get_first_child() const { return m_first_child; }

	// find the first child with the given tag
	data_node *get_child(const char *name);
	data_node const *get_child(const char *name) const;

	// find the first child with the given tag and/or attribute/value pair
	data_node *find_first_matching_child(const char *name, const char *attribute, const char *matchval);
	data_node const *find_first_matching_child(const char *name, const char *attribute, const char *matchval) const;

	// get the next sibling
	data_node *get_next_sibling() { return m_next; }
	data_node const *get_next_sibling() const { return m_next; }

	// find the next sibling with the given tag
	data_node *get_next_sibling(const char *name);
	data_node const *get_next_sibling(const char *name) const;

	// find the next sibling with the given tag and/or attribute/value pair
	data_node *find_next_matching_sibling(const char *name, const char *attribute, const char *matchval);
	data_node const *find_next_matching_sibling(const char *name, const char *attribute, const char *matchval) const;

	// add a new child node
	data_node *add_child(const char *name, const char *value);

	// either return an existing child node or create one if it doesn't exist
	data_node *get_or_add_child(const char *name, const char *value);

	// recursively copy as child of another node
	data_node *copy_into(data_node &parent) const;

	// delete a node and its children
	void delete_node();


	/* ----- XML attribute management ----- */

	// return whether a node has the specified attribute
	bool has_attribute(const char *attribute) const;

	// return a pointer to the string value of an attribute, or nullptr if not present
	std::string const *get_attribute_string_ptr(const char *attribute) const;

	// return the string value of an attribute, or the specified default if not present
	const char *get_attribute_string(const char *attribute, const char *defvalue) const;

	// return the integer value of an attribute, or the specified default if not present
	long long get_attribute_int(const char *attribute, long long defvalue) const;

	// return the format of the given integer attribute
	int_format get_attribute_int_format(const char *attribute) const;

	// return the float value of an attribute, or the specified default if not present
	float get_attribute_float(const char *attribute, float defvalue) const;

	// set the string value of an attribute
	void set_attribute(const char *name, const char *value);

	// set the integer value of an attribute
	void set_attribute_int(const char *name, long long value);

	// set the float value of an attribute
	void set_attribute_float(const char *name, float value);

	// add an attribute even if an attribute with the same name already exists
	void add_attribute(const char *name, const char *value);



	int                     line;           /* line number for this node's start */


protected:
	data_node();
	~data_node();

	void write_recursive(int indent, util::core_file &file) const;


private:
	// a node representing an attribute
	struct attribute_node
	{
		template <typename T, typename U> attribute_node(T &&name, U &&value) : name(std::forward<T>(name)), value(std::forward<U>(value)) { }

		std::string name;
		std::string value;
	};


	data_node(data_node *parent, const char *name, const char *value);

	data_node(data_node const &) = delete;
	data_node(data_node &&) = delete;
	data_node &operator=(data_node &&) = delete;
	data_node &operator=(data_node const &) = delete;

	data_node *get_sibling(const char *name);
	data_node const *get_sibling(const char *name) const;
	data_node *find_matching_sibling(const char *name, const char *attribute, const char *matchval);
	data_node const *find_matching_sibling(const char *name, const char *attribute, const char *matchval) const;

	attribute_node *get_attribute(const char *attribute);
	attribute_node const *get_attribute(const char *attribute) const;

	void free_children();


	data_node *                 m_next;
	data_node *                 m_first_child;
	std::string                 m_name;
	std::string                 m_value;
	data_node *                 m_parent;
	std::list<attribute_node>   m_attributes;
};


// a node representing the root of a document
class file : public data_node
{
public:
	using ptr = std::unique_ptr<file>;


	~file();

	// create a new, empty XML file
	static ptr create();

	// parse an XML file into its nodes
	static ptr read(util::core_file &file, parse_options const *opts);

	// parse an XML string into its nodes
	static ptr string_read(const char *string, parse_options const *opts);

	// write an XML tree to a file
	void write(util::core_file &file) const;


private:
	file();
};



/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/

/* ----- miscellaneous interfaces ----- */

/* normalize a string into something that can be written to an XML file */
const char *normalize_string(const char *string);

} // namespace util::xml

#endif // MAME_LIB_UTIL_XMLFILE_H