The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
simple_wml.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 2025
3 by David White <dave@whitevine.net>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#pragma once
17
18#include <cstring>
19
20#include <cstddef>
21#include <iosfwd>
22#include <memory>
23#include <string>
24#include <vector>
25
26#include "exceptions.hpp"
27
28namespace simple_wml {
29
30struct error : public game::error {
31 error(const char* msg);
32};
33
35{
36public:
37 string_span() : str_(nullptr), size_(0)
38 {}
39 string_span(const char* str, int size) : str_(str), size_(size)
40 {}
41 string_span(const char* str) : str_(str), size_(strlen(str))
42 {}
43 string_span(const char* begin, const char* end) : str_(begin), size_(end - begin)
44 {}
45 string_span(std::string str) : str_(str.c_str()), size_(str.size())
46 {}
47
48 typedef const char* const_iterator;
49 typedef const char* iterator;
50 typedef const char value_type;
51
52 operator std::string_view() const { return std::string_view(str_, size_); }
53
54 bool operator==(const char* o) const {
55 const char* i1 = str_;
56 const char* i2 = str_ + size_;
57 while(i1 != i2 && *o && *i1 == *o) {
58 ++i1;
59 ++o;
60 }
61
62 return i1 == i2 && *o == 0;
63 }
64 bool operator!=(const char* o) const {
65 return !operator==(o);
66 }
67 bool operator==(const std::string& o) const {
68 return size_ == o.size() && memcmp(str_, o.data(), size_) == 0;
69 }
70 bool operator!=(const std::string& o) const {
71 return !operator==(o);
72 }
73 bool operator==(const string_span& o) const {
74 return size_ == o.size_ && memcmp(str_, o.str_, size_) == 0;
75 }
76 bool operator!=(const string_span& o) const {
77 return !operator==(o);
78 }
79 bool operator<(const string_span& o) const {
80 const int len = size_ < o.size_ ? size_ : o.size_;
81 for(int n = 0; n < len; ++n) {
82 if(str_[n] != o.str_[n]) {
83 if(str_[n] < o.str_[n]) {
84 return true;
85 } else {
86 return false;
87 }
88 }
89 }
90
91 return size_ < o.size_;
92 }
93
94 const char* begin() const { return str_; }
95 const char* end() const { return str_ + size_; }
96
97 int size() const { return size_; }
98 bool empty() const { return size_ == 0; }
99 bool is_null() const { return str_ == nullptr; }
100
101 bool to_bool(bool default_value=false) const;
102 int to_int() const;
103 std::string to_string() const;
104
105 //returns a duplicate of the string span in a new[] allocated buffer
106 char* duplicate() const;
107
108private:
109 const char* str_;
110 unsigned int size_;
111};
112
113std::ostream& operator<<(std::ostream& o, const string_span& s);
114
115class document;
116
117class node
118{
119public:
120 node(document& doc, node* parent);
121 node(document& doc, node* parent, const char** str, int depth=0);
122 ~node();
124 {
125 attribute(const string_span& k, const string_span& v) : key(k), value(v) {}
128 };
129 typedef std::vector<node*> child_list;
130
131 const string_span& operator[](const char* key) const;
132 const string_span& attr(const char* key) const {
133 return (*this)[key];
134 }
135
136 bool has_attr(const char* key) const;
137
138 //sets an attribute in the WML node. The node will keep a direct reference
139 //to key and value which it will maintain for its lifetime. The caller
140 //MUST guarantee that the key and value buffers remain valid for the
141 //lifetime of the node.
142 node& set_attr(const char* key, const char* value);
143
144 //functions which are identical to set_attr() except that the buffer
145 //referred to by 'value' will be duplicated and the new buffer managed by
146 //the node. The caller may destroy the value buffer as soon as the function
147 //returns. The key buffer must remain valid for the lifetime of the node.
148 node& set_attr_dup(const char* key, const char* value);
149 node& set_attr_dup(const char* key, const string_span& value);
150 /** As above but convert @a value to a WML value */
151 node& set_attr_esc(const char* key, string_span value);
152
153 node& set_attr_int(const char* key, int value);
154
155 node& add_child(const char* name);
156 node& add_child_at(const char* name, std::size_t index);
157 void remove_child(const char* name, std::size_t index);
158 void remove_child(const string_span& name, std::size_t index);
159
160 node* child(const char* name);
161 const node* child(const char* name) const;
162
163 node& child_or_add(const char* name);
164
165 const child_list& children(const char* name) const;
166
167 const string_span& first_child() const;
168
169 bool is_dirty() const { return output_cache_.is_null(); }
170
172
173 int output_size() const;
174 void output(char*& buf, CACHE_STATUS status=DO_NOT_MODIFY_CACHE);
175
176 void copy_into(node& n) const;
177
178 bool no_children() const { return children_.empty(); }
179 bool one_child() const { return children_.size() == 1 && children_.begin()->second.size() == 1; }
180
181 void apply_diff(const node& diff);
182
183 void set_doc(document* doc);
184
185 int nchildren() const;
186 int nattributes_recursive() const;
187
188private:
189 node(const node&) = delete;
190 node& operator=(const node&) = delete;
191
192 int get_children(const string_span& name);
193 int get_children(const char* name);
194
195 void set_dirty();
196 void shift_buffers(ptrdiff_t offset);
197
199
200 typedef std::vector<attribute> attribute_list;
202
204
205 typedef std::pair<string_span, child_list> child_pair;
206 typedef std::vector<child_pair> child_map;
207
208 static child_map::const_iterator find_in_map(const child_map& m, const string_span& attr);
209 static child_map::iterator find_in_map(child_map& m, const string_span& attr);
211
212 //a node position indicates the index into the child map where the node
213 //is, and then the index into the child list within where the node is.
214 struct node_pos {
216 : child_map_index(static_cast<unsigned short>(child_map_index)),
217 child_list_index(static_cast<unsigned short>(child_list_index))
218 {}
219 unsigned short child_map_index;
220 unsigned short child_list_index;
221 };
222
223 //a list of all the children in order.
224 std::vector<node_pos> ordered_children_;
225
226 void insert_ordered_child(int child_map_index, int child_list_index);
227 void remove_ordered_child(int child_map_index, int child_list_index);
228 void remove_ordered_child_list(int child_map_index);
229
230 void check_ordered_children() const;
231
233};
234
235std::string node_to_string(const node& n);
236
238
240
242{
243public:
244 document();
245 explicit document(char* buf, INIT_BUFFER_CONTROL control=INIT_TAKE_OWNERSHIP);
246 document(const char* buf, INIT_STATE state);
247 explicit document(string_span compressed_buf);
248 ~document();
249 const char* dup_string(const char* str);
250 const char* esc_string(string_span str);
251 node& root() { if(!root_) { generate_root(); } return *root_; }
252 const node& root() const { if(!root_) { const_cast<document*>(this)->generate_root(); } return *root_; }
253
254 const char* output();
255 string_span output_compressed(bool bzip2 = false);
256
257 void compress();
258
259 std::unique_ptr<document> clone();
260
261 const string_span& operator[](const char* key) const {
262 return root()[key];
263 }
264
265 const string_span& attr(const char* key) const {
266 return root()[key];
267 }
268
269 node* child(const char* name) {
270 return root().child(name);
271 }
272
273 const node* child(const char* name) const {
274 return root().child(name);
275 }
276
277 const node::child_list& children(const char* name) const {
278 return root().children(name);
279 }
280
281 node& set_attr(const char* key, const char* value) {
282 return root().set_attr(key, value);
283 }
284
285 node& set_attr_dup(const char* key, const char* value) {
286 return root().set_attr_dup(key, value);
287 }
288
289 void take_ownership_of_buffer(char* buffer) {
290 buffers_.push_back(buffer);
291 }
292
293 void swap(document& o) noexcept;
294 void clear();
295
296 static std::string stats();
297
298 static std::size_t document_size_limit;
299private:
300 void generate_root();
301 document(const document&) = delete;
302 document& operator=(const document&) = delete;
303
305 const char* output_;
306 std::vector<char*> buffers_;
308
309 //linked list of documents for accounting purposes
310 void attach_list();
311 void detach_list();
314};
315
316/** Implement non-member swap function for std::swap (calls @ref document::swap). */
317void swap(document& lhs, document& rhs) noexcept;
318
319}
void take_ownership_of_buffer(char *buffer)
const char * output()
std::unique_ptr< document > clone()
static std::string stats()
const string_span & operator[](const char *key) const
const node::child_list & children(const char *name) const
const node & root() const
document(const document &)=delete
static std::size_t document_size_limit
void swap(document &o) noexcept
node & set_attr(const char *key, const char *value)
const char * esc_string(string_span str)
std::vector< char * > buffers_
string_span output_compressed(bool bzip2=false)
const char * dup_string(const char *str)
string_span compressed_buf_
node & set_attr_dup(const char *key, const char *value)
document & operator=(const document &)=delete
const node * child(const char *name) const
const string_span & attr(const char *key) const
node * child(const char *name)
const string_span & attr(const char *key) const
int output_size() const
void set_doc(document *doc)
void insert_ordered_child(int child_map_index, int child_list_index)
void check_ordered_children() const
void remove_child(const char *name, std::size_t index)
int nchildren() const
node(const node &)=delete
bool no_children() const
bool is_dirty() const
int get_children(const string_span &name)
const string_span & operator[](const char *key) const
node & operator=(const node &)=delete
const child_list & children(const char *name) const
void apply_diff(const node &diff)
attribute_list attr_
bool has_attr(const char *key) const
node & set_attr_int(const char *key, int value)
std::vector< child_pair > child_map
node * child(const char *name)
std::vector< node * > child_list
void remove_ordered_child_list(int child_map_index)
int nattributes_recursive() const
std::vector< node_pos > ordered_children_
std::vector< attribute > attribute_list
const string_span & first_child() const
child_map children_
node & add_child(const char *name)
node & child_or_add(const char *name)
node & set_attr_esc(const char *key, string_span value)
As above but convert value to a WML value
node & set_attr(const char *key, const char *value)
string_span output_cache_
node & add_child_at(const char *name, std::size_t index)
void copy_into(node &n) const
node & set_attr_dup(const char *key, const char *value)
void remove_ordered_child(int child_map_index, int child_list_index)
void shift_buffers(ptrdiff_t offset)
std::pair< string_span, child_list > child_pair
bool one_child() const
static child_map::const_iterator find_in_map(const child_map &m, const string_span &attr)
bool to_bool(bool default_value=false) const
std::string to_string() const
string_span(const char *begin, const char *end)
bool operator<(const string_span &o) const
bool operator==(const std::string &o) const
char * duplicate() const
const char * end() const
const char * begin() const
bool operator!=(const string_span &o) const
string_span(const char *str)
string_span(const char *str, int size)
string_span(std::string str)
bool operator==(const char *o) const
const char * const_iterator
bool operator==(const string_span &o) const
bool operator!=(const char *o) const
bool operator!=(const std::string &o) const
static std::ostream & output()
Definition log.cpp:103
void swap(document &lhs, document &rhs) noexcept
Implement non-member swap function for std::swap (calls document::swap).
std::ostream & operator<<(std::ostream &o, const string_span &s)
std::string node_to_string(const node &n)
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
Base class for all the errors encountered by the engine.
attribute(const string_span &k, const string_span &v)
node_pos(int child_map_index, int child_list_index)
unsigned short child_map_index
unsigned short child_list_index
static map_location::direction n
static map_location::direction s