The Battle for Wesnoth  1.19.11+dev
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 
28 namespace simple_wml {
29 
30 struct error : public game::error {
31  error(const char* msg);
32 };
33 
35 {
36 public:
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 
108 private:
109  const char* str_;
110  unsigned int size_;
111 };
112 
113 std::ostream& operator<<(std::ostream& o, const string_span& s);
114 
115 class document;
116 
117 class node
118 {
119 public:
120  node(document& doc, node* parent);
121  node(document& doc, node* parent, const char** str, int depth=0);
122  ~node();
123  struct attribute
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 
188 private:
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);
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 
235 std::string node_to_string(const node& n);
236 
238 
240 
241 class document
242 {
243 public:
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);
294  void clear();
295 
296  static std::string stats();
297 
298  static std::size_t document_size_limit;
299 private:
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). */
317 void swap(document& lhs, document& rhs);
318 
319 }
void take_ownership_of_buffer(char *buffer)
Definition: simple_wml.hpp:289
const char * output()
const node & root() const
Definition: simple_wml.hpp:252
node & set_attr_dup(const char *key, const char *value)
Definition: simple_wml.hpp:285
std::unique_ptr< document > clone()
static std::string stats()
const node * child(const char *name) const
Definition: simple_wml.hpp:273
document & operator=(const document &)=delete
document(const document &)=delete
static std::size_t document_size_limit
Definition: simple_wml.hpp:298
const string_span & operator[](const char *key) const
Definition: simple_wml.hpp:261
const char * esc_string(string_span str)
node * child(const char *name)
Definition: simple_wml.hpp:269
const char * output_
Definition: simple_wml.hpp:305
const node::child_list & children(const char *name) const
Definition: simple_wml.hpp:277
void swap(document &o)
std::vector< char * > buffers_
Definition: simple_wml.hpp:306
string_span output_compressed(bool bzip2=false)
const char * dup_string(const char *str)
const string_span & attr(const char *key) const
Definition: simple_wml.hpp:265
string_span compressed_buf_
Definition: simple_wml.hpp:304
node & set_attr(const char *key, const char *value)
Definition: simple_wml.hpp:281
const string_span & attr(const char *key) const
Definition: simple_wml.hpp:132
int output_size() const
Definition: simple_wml.cpp:702
void set_doc(document *doc)
Definition: simple_wml.cpp:906
void insert_ordered_child(int child_map_index, int child_list_index)
Definition: simple_wml.cpp:511
void check_ordered_children() const
Definition: simple_wml.cpp:569
void remove_child(const char *name, std::size_t index)
Definition: simple_wml.cpp:599
int nchildren() const
Definition: simple_wml.cpp:917
node(const node &)=delete
bool no_children() const
Definition: simple_wml.hpp:178
bool is_dirty() const
Definition: simple_wml.hpp:169
node(document &doc, node *parent)
Definition: simple_wml.cpp:209
int get_children(const string_span &name)
Definition: simple_wml.cpp:656
document * doc_
Definition: simple_wml.hpp:198
const string_span & operator[](const char *key) const
Definition: simple_wml.cpp:393
const child_list & children(const char *name) const
Definition: simple_wml.cpp:639
void apply_diff(const node &diff)
Definition: simple_wml.cpp:838
attribute_list attr_
Definition: simple_wml.hpp:201
bool has_attr(const char *key) const
Definition: simple_wml.cpp:406
node & set_attr_int(const char *key, int value)
Definition: simple_wml.cpp:447
std::vector< child_pair > child_map
Definition: simple_wml.hpp:206
node * child(const char *name)
Definition: simple_wml.cpp:604
std::vector< node * > child_list
Definition: simple_wml.hpp:129
void remove_ordered_child_list(int child_map_index)
Definition: simple_wml.cpp:552
int nattributes_recursive() const
Definition: simple_wml.cpp:930
std::vector< node_pos > ordered_children_
Definition: simple_wml.hpp:224
std::vector< attribute > attribute_list
Definition: simple_wml.hpp:200
const string_span & first_child() const
Definition: simple_wml.cpp:692
child_map children_
Definition: simple_wml.hpp:210
void output(char *&buf, CACHE_STATUS status=DO_NOT_MODIFY_CACHE)
Definition: simple_wml.cpp:748
node & add_child(const char *name)
Definition: simple_wml.cpp:472
node & child_or_add(const char *name)
Definition: simple_wml.cpp:631
node & set_attr_esc(const char *key, string_span value)
As above but convert value to a WML value
Definition: simple_wml.cpp:442
node & operator=(const node &)=delete
node & set_attr(const char *key, const char *value)
Definition: simple_wml.cpp:414
string_span output_cache_
Definition: simple_wml.hpp:232
node & add_child_at(const char *name, std::size_t index)
Definition: simple_wml.cpp:453
void copy_into(node &n) const
Definition: simple_wml.cpp:817
node & set_attr_dup(const char *key, const char *value)
Definition: simple_wml.cpp:430
void remove_ordered_child(int child_map_index, int child_list_index)
Definition: simple_wml.cpp:533
void shift_buffers(ptrdiff_t offset)
Definition: simple_wml.cpp:728
std::pair< string_span, child_list > child_pair
Definition: simple_wml.hpp:205
bool one_child() const
Definition: simple_wml.hpp:179
static child_map::const_iterator find_in_map(const child_map &m, const string_span &attr)
Definition: simple_wml.cpp:668
bool to_bool(bool default_value=false) const
Definition: simple_wml.cpp:160
std::string to_string() const
Definition: simple_wml.cpp:184
string_span(const char *begin, const char *end)
Definition: simple_wml.hpp:43
bool operator<(const string_span &o) const
Definition: simple_wml.hpp:79
bool operator==(const std::string &o) const
Definition: simple_wml.hpp:67
const char * begin() const
Definition: simple_wml.hpp:94
char * duplicate() const
Definition: simple_wml.cpp:189
const char * end() const
Definition: simple_wml.hpp:95
bool operator!=(const string_span &o) const
Definition: simple_wml.hpp:76
string_span(const char *str)
Definition: simple_wml.hpp:41
string_span(const char *str, int size)
Definition: simple_wml.hpp:39
string_span(std::string str)
Definition: simple_wml.hpp:45
bool operator==(const char *o) const
Definition: simple_wml.hpp:54
const char * const_iterator
Definition: simple_wml.hpp:48
bool operator==(const string_span &o) const
Definition: simple_wml.hpp:73
bool operator!=(const char *o) const
Definition: simple_wml.hpp:64
bool operator!=(const std::string &o) const
Definition: simple_wml.hpp:70
void swap(document &lhs, document &rhs)
Implement non-member swap function for std::swap (calls document::swap).
std::ostream & operator<<(std::ostream &o, const string_span &s)
Definition: simple_wml.cpp:203
std::string node_to_string(const node &n)
Definition: simple_wml.cpp:805
@ INIT_TAKE_OWNERSHIP
Definition: simple_wml.hpp:237
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:29
attribute(const string_span &k, const string_span &v)
Definition: simple_wml.hpp:125
node_pos(int child_map_index, int child_list_index)
Definition: simple_wml.hpp:215
unsigned short child_map_index
Definition: simple_wml.hpp:219
unsigned short child_list_index
Definition: simple_wml.hpp:220
static map_location::direction n
static map_location::direction s