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