The Battle for Wesnoth  1.19.10+dev
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 insert_ordered_child_list(int child_map_index);
229  void remove_ordered_child_list(int child_map_index);
230 
231  void check_ordered_children() const;
232 
234 };
235 
236 std::string node_to_string(const node& n);
237 
239 
241 
242 class document
243 {
244 public:
245  document();
246  explicit document(char* buf, INIT_BUFFER_CONTROL control=INIT_TAKE_OWNERSHIP);
247  document(const char* buf, INIT_STATE state);
248  explicit document(string_span compressed_buf);
249  ~document();
250  const char* dup_string(const char* str);
251  const char* esc_string(string_span str);
252  node& root() { if(!root_) { generate_root(); } return *root_; }
253  const node& root() const { if(!root_) { const_cast<document*>(this)->generate_root(); } return *root_; }
254 
255  const char* output();
256  string_span output_compressed(bool bzip2 = false);
257 
258  void compress();
259 
260  std::unique_ptr<document> clone();
261 
262  const string_span& operator[](const char* key) const {
263  return root()[key];
264  }
265 
266  const string_span& attr(const char* key) const {
267  return root()[key];
268  }
269 
270  node* child(const char* name) {
271  return root().child(name);
272  }
273 
274  const node* child(const char* name) const {
275  return root().child(name);
276  }
277 
278  const node::child_list& children(const char* name) const {
279  return root().children(name);
280  }
281 
282  node& set_attr(const char* key, const char* value) {
283  return root().set_attr(key, value);
284  }
285 
286  node& set_attr_dup(const char* key, const char* value) {
287  return root().set_attr_dup(key, value);
288  }
289 
290  void take_ownership_of_buffer(char* buffer) {
291  buffers_.push_back(buffer);
292  }
293 
294  void swap(document& o);
295  void clear();
296 
297  static std::string stats();
298 
299  static std::size_t document_size_limit;
300 private:
301  void generate_root();
302  document(const document&) = delete;
303  document& operator=(const document&) = delete;
304 
306  const char* output_;
307  std::vector<char*> buffers_;
309 
310  //linked list of documents for accounting purposes
311  void attach_list();
312  void detach_list();
315 };
316 
317 /** Implement non-member swap function for std::swap (calls @ref document::swap). */
318 void swap(document& lhs, document& rhs);
319 
320 }
void take_ownership_of_buffer(char *buffer)
Definition: simple_wml.hpp:290
const char * output()
const node & root() const
Definition: simple_wml.hpp:253
node & set_attr_dup(const char *key, const char *value)
Definition: simple_wml.hpp:286
std::unique_ptr< document > clone()
static std::string stats()
const node * child(const char *name) const
Definition: simple_wml.hpp:274
document & operator=(const document &)=delete
document(const document &)=delete
static std::size_t document_size_limit
Definition: simple_wml.hpp:299
const string_span & operator[](const char *key) const
Definition: simple_wml.hpp:262
const char * esc_string(string_span str)
node * child(const char *name)
Definition: simple_wml.hpp:270
const char * output_
Definition: simple_wml.hpp:306
const node::child_list & children(const char *name) const
Definition: simple_wml.hpp:278
void swap(document &o)
std::vector< char * > buffers_
Definition: simple_wml.hpp:307
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:266
string_span compressed_buf_
Definition: simple_wml.hpp:305
node & set_attr(const char *key, const char *value)
Definition: simple_wml.hpp:282
const string_span & attr(const char *key) const
Definition: simple_wml.hpp:132
int output_size() const
Definition: simple_wml.cpp:712
void set_doc(document *doc)
Definition: simple_wml.cpp:916
void insert_ordered_child(int child_map_index, int child_list_index)
Definition: simple_wml.cpp:511
void insert_ordered_child_list(int child_map_index)
Definition: simple_wml.cpp:552
void check_ordered_children() const
Definition: simple_wml.cpp:579
void remove_child(const char *name, std::size_t index)
Definition: simple_wml.cpp:609
int nchildren() const
Definition: simple_wml.cpp:927
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:666
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:649
void apply_diff(const node &diff)
Definition: simple_wml.cpp:848
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:614
std::vector< node * > child_list
Definition: simple_wml.hpp:129
void remove_ordered_child_list(int child_map_index)
Definition: simple_wml.cpp:562
int nattributes_recursive() const
Definition: simple_wml.cpp:940
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:702
child_map children_
Definition: simple_wml.hpp:210
void output(char *&buf, CACHE_STATUS status=DO_NOT_MODIFY_CACHE)
Definition: simple_wml.cpp:758
node & add_child(const char *name)
Definition: simple_wml.cpp:472
node & child_or_add(const char *name)
Definition: simple_wml.cpp:641
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:233
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:827
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:738
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:678
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:815
@ INIT_TAKE_OWNERSHIP
Definition: simple_wml.hpp:238
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