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