00001 #include <iostream>
00002 #include <sstream>
00003
00004 #include "global.hpp"
00005
00006 #include <boost/iostreams/filtering_stream.hpp>
00007 #include <boost/iostreams/filter/gzip.hpp>
00008
00009 #include "simple_wml.hpp"
00010
00011 #include "../log.hpp"
00012
00013 static lg::log_domain log_config("config");
00014 #define ERR_SWML LOG_STREAM(err, log_config)
00015
00016 namespace simple_wml {
00017
00018 namespace {
00019
00020 void debug_delete(node* n) {
00021 delete n;
00022 }
00023
00024 char* uncompress_buffer(const string_span& input, string_span* span)
00025 {
00026 int nalloc = input.size();
00027 int state = 0;
00028 try {
00029 std::istringstream stream(std::string(input.begin(), input.end()));
00030 state = 1;
00031 boost::iostreams::filtering_stream<boost::iostreams::input> filter;
00032 state = 2;
00033 filter.push(boost::iostreams::gzip_decompressor());
00034 filter.push(stream);
00035 state = 3;
00036
00037 const size_t chunk_size = input.size() * 10;
00038 nalloc = chunk_size;
00039 std::vector<char> buf(chunk_size);
00040 state = 4;
00041 size_t len = 0;
00042 size_t pos = 0;
00043 while(filter.good() && (len = filter.read(&buf[pos], chunk_size).gcount()) == chunk_size) {
00044 if(pos + chunk_size > 40000000) {
00045 throw error("WML document exceeds 40MB limit");
00046 }
00047
00048 pos += len;
00049 buf.resize(pos + chunk_size);
00050 len = 0;
00051 }
00052
00053 if(!filter.eof() && !filter.good()) {
00054 throw error("failed to uncompress");
00055 }
00056
00057 pos += len;
00058 state = 5;
00059 nalloc = pos;
00060
00061 buf.resize(pos);
00062 state = 6;
00063
00064 char* small_out = new char[pos+1];
00065 memcpy(small_out, &buf[0], pos);
00066 state = 7;
00067
00068 small_out[pos] = 0;
00069
00070 *span = string_span(small_out, pos);
00071 state = 8;
00072 return small_out;
00073 } catch (std::bad_alloc& e) {
00074 ERR_SWML << "ERROR: bad_alloc caught in uncompress_buffer() state "
00075 << state << " alloc bytes " << nalloc << " with input: '"
00076 << input << "' " << e.what() << std::endl;
00077 throw error("Bad allocation request in uncompress_buffer().");
00078 }
00079 }
00080
00081 char* compress_buffer(const char* input, string_span* span)
00082 {
00083 int nalloc = strlen(input);
00084 int state = 0;
00085 try {
00086 std::string in(input);
00087 state = 1;
00088 std::istringstream stream(in);
00089 state = 2;
00090 boost::iostreams::filtering_stream<boost::iostreams::input> filter;
00091 state = 3;
00092 filter.push(boost::iostreams::gzip_compressor());
00093 filter.push(stream);
00094 state = 4;
00095 nalloc = in.size()*2 + 80;
00096
00097 std::vector<char> buf(in.size()*2 + 80);
00098 state = 5;
00099 const int len = filter.read(&buf[0], buf.size()).gcount();
00100 assert(len < 128*1024*1024);
00101 if((!filter.eof() && !filter.good()) || len == static_cast<int>(buf.size())) {
00102 throw error("failed to compress");
00103 }
00104 state = 6;
00105 nalloc = len;
00106
00107 buf.resize(len);
00108 state = 7;
00109
00110 char* small_out = new char[len];
00111 memcpy(small_out, &buf[0], len);
00112 state = 8;
00113
00114 *span = string_span(small_out, len);
00115 assert(*small_out == 31);
00116 state = 9;
00117 return small_out;
00118 } catch (std::bad_alloc& e) {
00119 ERR_SWML << "ERROR: bad_alloc caught in compress_buffer() state "
00120 << state << " alloc bytes " << nalloc << " with input: '"
00121 << input << "' " << e.what() << std::endl;
00122 throw error("Bad allocation request in compress_buffer().");
00123 }
00124 }
00125
00126 }
00127
00128 bool string_span::to_bool(bool default_value) const
00129 {
00130 if(empty()) {
00131 return default_value;
00132 }
00133
00134 if (operator==("no") || operator==("off") || operator==("false") || operator==("0") || operator==("0.0"))
00135 return false;
00136
00137 return true;
00138 }
00139
00140 int string_span::to_int() const
00141 {
00142 const int buf_size = 64;
00143 if(size() >= buf_size) {
00144 return 0;
00145 }
00146 char buf[64];
00147 memcpy(buf, begin(), size());
00148 buf[size()] = 0;
00149 return atoi(buf);
00150 }
00151
00152 std::string string_span::to_string() const
00153 {
00154 return std::string(begin(), end());
00155 }
00156
00157 char* string_span::duplicate() const
00158 {
00159 char* buf = new char[size() + 1];
00160 memcpy(buf, begin(), size());
00161 buf[size()] = 0;
00162 return buf;
00163 }
00164
00165 error::error(const char* msg)
00166 : game::error(msg)
00167 {
00168 ERR_SWML << "ERROR: '" << msg << "'\n";
00169 }
00170
00171 std::ostream& operator<<(std::ostream& o, const string_span& s)
00172 {
00173 o << std::string(s.begin(), s.end());
00174 return o;
00175 }
00176
00177 node::node(document& doc, node* parent) :
00178 doc_(&doc),
00179 attr_(),
00180 parent_(parent),
00181 children_(),
00182 ordered_children_(),
00183 output_cache_()
00184 {
00185 }
00186
00187 #ifdef _MSC_VER
00188 #pragma warning (push)
00189 #pragma warning (disable: 4706)
00190 #endif
00191 node::node(document& doc, node* parent, const char** str, int depth) :
00192 doc_(&doc),
00193 attr_(),
00194 parent_(parent),
00195 children_(),
00196 ordered_children_(),
00197 output_cache_()
00198 {
00199 if(depth >= 1000) {
00200 throw error("elements nested too deep");
00201 }
00202
00203 const char*& s = *str;
00204
00205 const char* const begin = s;
00206 while(*s) {
00207 switch(*s) {
00208 case '[': {
00209 if(s[1] == '/') {
00210 output_cache_ = string_span(begin, s - begin);
00211 s = strchr(s, ']');
00212 if(s == NULL) {
00213 throw error("end element unterminated");
00214 }
00215
00216 ++s;
00217 return;
00218 }
00219
00220 ++s;
00221 const char* end = strchr(s, ']');
00222 if(end == NULL) {
00223 throw error("unterminated element");
00224 }
00225
00226 const int list_index = get_children(string_span(s, end - s));
00227 check_ordered_children();
00228
00229 s = end + 1;
00230
00231 children_[list_index].second.push_back(new node(doc, this, str, depth+1));
00232 ordered_children_.push_back(node_pos(list_index, children_[list_index].second.size() - 1));
00233 check_ordered_children();
00234
00235 break;
00236 }
00237 case ' ':
00238 case '\t':
00239 case '\n':
00240 ++s;
00241 break;
00242 case '#':
00243 s = strchr(s, '\n');
00244 if(s == NULL) {
00245 throw error("did not find newline after '#'");
00246 }
00247 break;
00248 default: {
00249 const char* end = strchr(s, '=');
00250 if(end == NULL) {
00251 ERR_SWML << "attribute: " << s << "\n";
00252 throw error("did not find '=' after attribute");
00253 }
00254
00255 string_span name(s, end - s);
00256 s = end + 1;
00257 if(*s == '_') {
00258 s = strchr(s, '"');
00259 if(s == NULL) {
00260 throw error("did not find '\"' after '_'");
00261 }
00262 }
00263
00264 if (*s != '"') {
00265 end = strchr(s, '\n');
00266 if (!end) {
00267 ERR_SWML << "ATTR: '" << name << "' (((" << s << ")))\n";
00268 throw error("did not find end of attribute");
00269 }
00270 if (memchr(s, '"', end - s))
00271 throw error("found stray quotes in unquoted value");
00272 goto read_attribute;
00273 }
00274 end = s;
00275 for(;;)
00276 {
00277
00278 while((end = strchr(end+1, '"')) && end[1] == '"') {
00279 #ifdef _MSC_VER
00280 #pragma warning (pop)
00281 #endif
00282 ++end;
00283 }
00284 if(end == NULL)
00285 throw error("did not find end of attribute");
00286
00287
00288 const char *endline = end + 1;
00289 while (*endline == ' ') ++endline;
00290 if (*endline == '\n') break;
00291
00292
00293 if (*(endline++) != '+')
00294 throw error("did not find newline after end of attribute");
00295 if (*(endline++) != '\n')
00296 throw error("did not find newline after '+'");
00297
00298
00299 if (*endline == '#') {
00300 endline = strchr(endline + 1, '\n');
00301 if (!endline)
00302 throw error("did not find newline after '#'");
00303 ++endline;
00304 }
00305
00306
00307 while (*endline == '\t') ++endline;
00308 if (*endline == '_') ++endline;
00309 if (*endline != '"')
00310 throw error("did not find quotes after '+'");
00311 end = endline;
00312 }
00313
00314 ++s;
00315
00316 read_attribute:
00317 string_span value(s, end - s);
00318 if(attr_.empty() == false && !(attr_.back().first < name)) {
00319 ERR_SWML << "attributes: '" << attr_.back().first << "' < '" << name << "'\n";
00320 throw error("attributes not in order");
00321 }
00322
00323 s = end + 1;
00324
00325 attr_.push_back(attribute(name, value));
00326 }
00327 }
00328 }
00329
00330 output_cache_ = string_span(begin, s - begin);
00331 check_ordered_children();
00332 }
00333
00334 node::~node()
00335 {
00336 for(child_map::iterator i = children_.begin(); i != children_.end(); ++i) {
00337 for(child_list::iterator j = i->second.begin(); j != i->second.end(); ++j) {
00338 debug_delete(*j);
00339 }
00340 }
00341 }
00342
00343 namespace {
00344 struct string_span_pair_comparer
00345 {
00346 bool operator()(const string_span& a, const node::attribute& b) const {
00347 return a < b.first;
00348 }
00349
00350 bool operator()(const node::attribute& a, const string_span& b) const {
00351 return a.first < b;
00352 }
00353
00354 bool operator()(const node::attribute& a,
00355 const node::attribute& b) const {
00356 return a.first < b.first;
00357 }
00358 };
00359 }
00360
00361 const string_span& node::operator[](const char* key) const
00362 {
00363 static string_span empty("");
00364 string_span span(key);
00365 std::pair<attribute_list::const_iterator,
00366 attribute_list::const_iterator> range = std::equal_range(attr_.begin(), attr_.end(), span, string_span_pair_comparer());
00367 if(range.first != range.second) {
00368 return range.first->second;
00369 }
00370
00371 return empty;
00372 }
00373
00374 bool node::has_attr(const char* key) const
00375 {
00376 string_span span(key);
00377 std::pair<attribute_list::const_iterator,
00378 attribute_list::const_iterator> range = std::equal_range(attr_.begin(), attr_.end(), span, string_span_pair_comparer());
00379 return range.first != range.second;
00380 }
00381
00382 node& node::set_attr(const char* key, const char* value)
00383 {
00384 set_dirty();
00385
00386 string_span span(key);
00387 std::pair<attribute_list::iterator,
00388 attribute_list::iterator> range = std::equal_range(attr_.begin(), attr_.end(), span, string_span_pair_comparer());
00389 if(range.first != range.second) {
00390 range.first->second = string_span(value);
00391 } else {
00392 attr_.insert(range.first, attribute(span, string_span(value)));
00393 }
00394
00395 return *this;
00396 }
00397
00398 node& node::set_attr_dup(const char* key, const char* value)
00399 {
00400 return set_attr(key, doc_->dup_string(value));
00401 }
00402
00403 node& node::set_attr_dup(const char* key, const string_span& value)
00404 {
00405 char* buf = value.duplicate();
00406 doc_->take_ownership_of_buffer(buf);
00407 return set_attr(key, buf);
00408 }
00409
00410 node& node::set_attr_int(const char* key, int value)
00411 {
00412 char buf[64];
00413 sprintf(buf, "%d", value);
00414 return set_attr_dup(key, buf);
00415 }
00416
00417 node& node::add_child_at(const char* name, size_t index)
00418 {
00419 set_dirty();
00420
00421 const int list_index = get_children(name);
00422 child_list& list = children_[list_index].second;
00423 if(index > list.size()) {
00424 index = list.size();
00425 }
00426
00427 check_ordered_children();
00428 list.insert(list.begin() + index, new node(*doc_, this));
00429 insert_ordered_child(list_index, index);
00430
00431 check_ordered_children();
00432 return *list[index];
00433 }
00434
00435
00436 node& node::add_child(const char* name)
00437 {
00438 set_dirty();
00439
00440 const int list_index = get_children(name);
00441 check_ordered_children();
00442 child_list& list = children_[list_index].second;
00443 list.push_back(new node(*doc_, this));
00444 ordered_children_.push_back(node_pos(list_index, list.size() - 1));
00445 check_ordered_children();
00446 return *list.back();
00447 }
00448
00449 void node::remove_child(const string_span& name, size_t index)
00450 {
00451 set_dirty();
00452
00453
00454 child_map::iterator itor = find_in_map(children_, name);
00455 if(itor == children_.end()) {
00456 return;
00457 }
00458
00459 child_list& list = itor->second;
00460 if(index >= list.size()) {
00461 return;
00462 }
00463
00464 remove_ordered_child(itor - children_.begin(), index);
00465
00466 debug_delete(list[index]);
00467 list.erase(list.begin() + index);
00468
00469 if(list.empty()) {
00470 remove_ordered_child_list(itor - children_.begin());
00471 children_.erase(itor);
00472 }
00473 }
00474
00475 void node::insert_ordered_child(int child_map_index, int child_list_index)
00476 {
00477 bool inserted = false;
00478 std::vector<node_pos>::iterator i = ordered_children_.begin();
00479 while(i != ordered_children_.end()) {
00480 if(i->child_map_index == child_map_index && i->child_list_index > child_list_index) {
00481 i->child_list_index++;
00482 } else if(i->child_map_index == child_map_index && i->child_list_index == child_list_index) {
00483 inserted = true;
00484 i->child_list_index++;
00485 i = ordered_children_.insert(i, node_pos(child_map_index, child_list_index));
00486 ++i;
00487 }
00488
00489 ++i;
00490 }
00491
00492 if(!inserted) {
00493 ordered_children_.push_back(node_pos(child_map_index, child_list_index));
00494 }
00495 }
00496
00497 void node::remove_ordered_child(int child_map_index, int child_list_index)
00498 {
00499 int erase_count = 0;
00500 std::vector<node_pos>::iterator i = ordered_children_.begin();
00501 while(i != ordered_children_.end()) {
00502 if(i->child_map_index == child_map_index && i->child_list_index == child_list_index) {
00503 i = ordered_children_.erase(i);
00504 ++erase_count;
00505 } else {
00506 if(i->child_map_index == child_map_index && i->child_list_index > child_list_index) {
00507 i->child_list_index--;
00508 }
00509 ++i;
00510 }
00511 }
00512
00513 assert(erase_count == 1);
00514 }
00515
00516 void node::insert_ordered_child_list(int child_map_index)
00517 {
00518 std::vector<node_pos>::iterator i = ordered_children_.begin();
00519 while(i != ordered_children_.end()) {
00520 if(i->child_map_index >= child_map_index) {
00521 i->child_map_index++;
00522 }
00523 }
00524 }
00525
00526 void node::remove_ordered_child_list(int child_map_index)
00527 {
00528 std::vector<node_pos>::iterator i = ordered_children_.begin();
00529 while(i != ordered_children_.end()) {
00530 if(i->child_map_index == child_map_index) {
00531 assert(false);
00532 i = ordered_children_.erase(i);
00533 } else {
00534 if(i->child_map_index > child_map_index) {
00535 i->child_map_index--;
00536 }
00537
00538 ++i;
00539 }
00540 }
00541 }
00542
00543 void node::check_ordered_children() const
00544 {
00545
00546 #ifdef CHECK_ORDERED_CHILDREN
00547 std::vector<node_pos>::const_iterator i = ordered_children_.begin();
00548 while(i != ordered_children_.end()) {
00549 assert(i->child_map_index < children_.size());
00550 assert(i->child_list_index < children_[i->child_map_index].second.size());
00551 ++i;
00552 }
00553
00554 for(child_map::const_iterator j = children_.begin(); j != children_.end(); ++j) {
00555 const unsigned short child_map_index = j - children_.begin();
00556 for(child_list::const_iterator k = j->second.begin(); k != j->second.end(); ++k) {
00557 const unsigned short child_list_index = k - j->second.begin();
00558 bool found = false;
00559 for(int n = 0; n != ordered_children_.size(); ++n) {
00560 if(ordered_children_[n].child_map_index == child_map_index &&
00561 ordered_children_[n].child_list_index == child_list_index) {
00562 found = true;
00563 break;
00564 }
00565 }
00566
00567 assert(found);
00568 }
00569 }
00570 #endif // CHECK_ORDERED_CHILDREN
00571 }
00572
00573 void node::remove_child(const char* name, size_t index)
00574 {
00575 remove_child(string_span(name), index);
00576 }
00577
00578 node* node::child(const char* name)
00579 {
00580 for(child_map::iterator i = children_.begin(); i != children_.end(); ++i) {
00581 if(i->first == name) {
00582 assert(i->second.empty() == false);
00583 return i->second.front();
00584 }
00585 }
00586
00587 return NULL;
00588 }
00589
00590 const node* node::child(const char* name) const
00591 {
00592 for(child_map::const_iterator i = children_.begin(); i != children_.end(); ++i) {
00593 if(i->first == name) {
00594 if(i->second.empty()) {
00595 return NULL;
00596 } else {
00597 return i->second.front();
00598 }
00599 }
00600 }
00601
00602 return NULL;
00603 }
00604
00605 const node::child_list& node::children(const char* name) const
00606 {
00607 for(child_map::const_iterator i = children_.begin(); i != children_.end(); ++i) {
00608 if(i->first == name) {
00609 return i->second;
00610 }
00611 }
00612
00613 static const node::child_list empty;
00614 return empty;
00615 }
00616
00617 int node::get_children(const char* name)
00618 {
00619 return get_children(string_span(name));
00620 }
00621
00622 int node::get_children(const string_span& name)
00623 {
00624 for(child_map::iterator i = children_.begin(); i != children_.end(); ++i) {
00625 if(i->first == name) {
00626 return i - children_.begin();
00627 }
00628 }
00629
00630 children_.push_back(child_pair(string_span(name), child_list()));
00631 return children_.size() - 1;
00632 }
00633
00634 node::child_map::const_iterator node::find_in_map(const child_map& m, const string_span& attr)
00635 {
00636 child_map::const_iterator i = m.begin();
00637 for(; i != m.end(); ++i) {
00638 if(i->first == attr) {
00639 break;
00640 }
00641 }
00642
00643 return i;
00644 }
00645
00646 node::child_map::iterator node::find_in_map(child_map& m, const string_span& attr)
00647 {
00648 child_map::iterator i = m.begin();
00649 for(; i != m.end(); ++i) {
00650 if(i->first == attr) {
00651 break;
00652 }
00653 }
00654
00655 return i;
00656 }
00657
00658 const string_span& node::first_child() const
00659 {
00660 if(children_.empty()) {
00661 static const string_span empty;
00662 return empty;
00663 }
00664
00665 return children_.begin()->first;
00666 }
00667
00668 int node::output_size() const
00669 {
00670 check_ordered_children();
00671 if(output_cache_.empty() == false) {
00672 return output_cache_.size();
00673 }
00674
00675 int res = 0;
00676 for(attribute_list::const_iterator i = attr_.begin(); i != attr_.end(); ++i) {
00677 res += i->first.size() + i->second.size() + 4;
00678 }
00679
00680 size_t count_children = 0;
00681 for(child_map::const_iterator i = children_.begin(); i != children_.end(); ++i) {
00682 for(child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
00683 res += i->first.size()*2 + 7;
00684 res += (*j)->output_size();
00685 ++count_children;
00686 }
00687 }
00688
00689 assert(count_children == ordered_children_.size());
00690
00691 return res;
00692 }
00693
00694 void node::shift_buffers(ptrdiff_t offset)
00695 {
00696 if(!output_cache_.empty()) {
00697 output_cache_ = string_span(output_cache_.begin() + offset, output_cache_.size());
00698 }
00699
00700 for(std::vector<attribute>::iterator i = attr_.begin(); i != attr_.end(); ++i) {
00701 i->first = string_span(i->first.begin() + offset, i->first.size());
00702 i->second = string_span(i->second.begin() + offset, i->second.size());
00703 }
00704
00705 for(child_map::iterator i = children_.begin(); i != children_.end(); ++i) {
00706 string_span& key = i->first;
00707 key = string_span(key.begin() + offset, key.size());
00708 for(child_list::iterator j = i->second.begin(); j != i->second.end(); ++j) {
00709 (*j)->shift_buffers(offset);
00710 }
00711 }
00712 }
00713
00714 void node::output(char*& buf, CACHE_STATUS cache_status)
00715 {
00716 if(output_cache_.empty() == false) {
00717 memcpy(buf, output_cache_.begin(), output_cache_.size());
00718 if(cache_status == REFRESH_CACHE) {
00719 shift_buffers(buf - output_cache_.begin());
00720 }
00721 buf += output_cache_.size();
00722 return;
00723 }
00724
00725 char* begin = buf;
00726
00727 for(std::vector<attribute>::iterator i = attr_.begin(); i != attr_.end(); ++i) {
00728 memcpy(buf, i->first.begin(), i->first.size());
00729 i->first = string_span(buf, i->first.size());
00730 buf += i->first.size();
00731 *buf++ = '=';
00732 *buf++ = '"';
00733 memcpy(buf, i->second.begin(), i->second.size());
00734 i->second = string_span(buf, i->second.size());
00735 buf += i->second.size();
00736 *buf++ = '"';
00737 *buf++ = '\n';
00738 }
00739
00740 for(std::vector<node_pos>::const_iterator i = ordered_children_.begin();
00741 i != ordered_children_.end(); ++i) {
00742 assert(i->child_map_index < children_.size());
00743 assert(i->child_list_index < children_[i->child_map_index].second.size());
00744 string_span& attr = children_[i->child_map_index].first;
00745 *buf++ = '[';
00746 memcpy(buf, attr.begin(), attr.size());
00747 attr = string_span(buf, attr.size());
00748 buf += attr.size();
00749 *buf++ = ']';
00750 *buf++ = '\n';
00751 children_[i->child_map_index].second[i->child_list_index]->output(buf, cache_status);
00752 *buf++ = '[';
00753 *buf++ = '/';
00754 memcpy(buf, attr.begin(), attr.size());
00755 buf += attr.size();
00756 *buf++ = ']';
00757 *buf++ = '\n';
00758 }
00759
00760 if(cache_status == REFRESH_CACHE) {
00761 output_cache_ = string_span(begin, buf - begin);
00762 }
00763 }
00764
00765 std::string node_to_string(const node& n)
00766 {
00767
00768
00769 node& mutable_node = const_cast<node&>(n);
00770 std::vector<char> v(mutable_node.output_size());
00771 char* ptr = &v[0];
00772 mutable_node.output(ptr, node::DO_NOT_MODIFY_CACHE);
00773 assert(ptr == &v[0] + v.size());
00774 return std::string(v.begin(), v.end());
00775 }
00776
00777 void node::copy_into(node& n) const
00778 {
00779 n.set_dirty();
00780 for(attribute_list::const_iterator i = attr_.begin(); i != attr_.end(); ++i) {
00781 char* key = i->first.duplicate();
00782 char* value = i->second.duplicate();
00783 n.doc_->take_ownership_of_buffer(key);
00784 n.doc_->take_ownership_of_buffer(value);
00785 n.set_attr(key, value);
00786 }
00787
00788 for(std::vector<node_pos>::const_iterator i = ordered_children_.begin();
00789 i != ordered_children_.end(); ++i) {
00790 assert(i->child_map_index < children_.size());
00791 assert(i->child_list_index < children_[i->child_map_index].second.size());
00792 char* buf = children_[i->child_map_index].first.duplicate();
00793 n.doc_->take_ownership_of_buffer(buf);
00794 children_[i->child_map_index].second[i->child_list_index]->copy_into(n.add_child(buf));
00795 }
00796 }
00797
00798 void node::apply_diff(const node& diff)
00799 {
00800 set_dirty();
00801 const node* inserts = diff.child("insert");
00802 if(inserts != NULL) {
00803 for(attribute_list::const_iterator i = inserts->attr_.begin(); i != inserts->attr_.end(); ++i) {
00804 char* name = i->first.duplicate();
00805 char* value = i->second.duplicate();
00806 set_attr(name, value);
00807 doc_->take_ownership_of_buffer(name);
00808 doc_->take_ownership_of_buffer(value);
00809 }
00810 }
00811
00812 const node* deletes = diff.child("delete");
00813 if(deletes != NULL) {
00814 for(attribute_list::const_iterator i = deletes->attr_.begin(); i != deletes->attr_.end(); ++i) {
00815 std::pair<attribute_list::iterator,
00816 attribute_list::iterator> range = std::equal_range(attr_.begin(), attr_.end(), i->first, string_span_pair_comparer());
00817 if(range.first != range.second) {
00818 attr_.erase(range.first);
00819 }
00820 }
00821 }
00822
00823 const child_list& child_changes = diff.children("change_child");
00824 for(child_list::const_iterator i = child_changes.begin(); i != child_changes.end(); ++i) {
00825 const size_t index = (**i)["index"].to_int();
00826 for(child_map::const_iterator j = (*i)->children_.begin(); j != (*i)->children_.end(); ++j) {
00827 const string_span& name = j->first;
00828 for(child_list::const_iterator k = j->second.begin(); k != j->second.end(); ++k) {
00829 child_map::iterator itor = find_in_map(children_, name);
00830 if(itor != children_.end()) {
00831 if(index < itor->second.size()) {
00832 itor->second[index]->apply_diff(**k);
00833 }
00834 }
00835 }
00836 }
00837 }
00838
00839 const child_list& child_inserts = diff.children("insert_child");
00840 for(child_list::const_iterator i = child_inserts.begin(); i != child_inserts.end(); ++i) {
00841 const size_t index = (**i)["index"].to_int();
00842 for(child_map::const_iterator j = (*i)->children_.begin(); j != (*i)->children_.end(); ++j) {
00843 const string_span& name = j->first;
00844 for(child_list::const_iterator k = j->second.begin(); k != j->second.end(); ++k) {
00845 char* buf = name.duplicate();
00846 doc_->take_ownership_of_buffer(buf);
00847 (*k)->copy_into(add_child_at(buf, index));
00848 }
00849 }
00850 }
00851
00852 const child_list& child_deletes = diff.children("delete_child");
00853 for(child_list::const_iterator i = child_deletes.begin(); i != child_deletes.end(); ++i) {
00854 const size_t index = (**i)["index"].to_int();
00855 for(child_map::const_iterator j = (*i)->children_.begin(); j != (*i)->children_.end(); ++j) {
00856 if(j->second.empty()) {
00857 continue;
00858 }
00859
00860 const string_span& name = j->first;
00861 remove_child(name, index);
00862 }
00863 }
00864 }
00865
00866 void node::set_doc(document* doc)
00867 {
00868 doc_ = doc;
00869
00870 for(child_map::iterator i = children_.begin(); i != children_.end(); ++i) {
00871 for(child_list::iterator j = i->second.begin(); j != i->second.end(); ++j) {
00872 (*j)->set_doc(doc);
00873 }
00874 }
00875 }
00876
00877 int node::nchildren() const
00878 {
00879 int res = 0;
00880 for(child_map::const_iterator i = children_.begin(); i != children_.end(); ++i) {
00881 for(child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
00882 ++res;
00883 res += (*j)->nchildren();
00884 }
00885 }
00886
00887 return res;
00888 }
00889
00890 int node::nattributes_recursive() const
00891 {
00892 int res = attr_.capacity();
00893 for(child_map::const_iterator i = children_.begin(); i != children_.end(); ++i) {
00894 for(child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
00895 res += (*j)->nattributes_recursive();
00896 }
00897 }
00898
00899 return res;
00900 }
00901
00902 void node::set_dirty()
00903 {
00904 for(node* n = this; n != NULL && n->output_cache_.is_null() == false; n = n->parent_) {
00905 n->output_cache_ = string_span();
00906 }
00907 }
00908
00909 document::document() :
00910 compressed_buf_(),
00911 output_(NULL),
00912 buffers_(),
00913 root_(new node(*this, NULL)),
00914 prev_(NULL),
00915 next_(NULL)
00916 {
00917 attach_list();
00918 }
00919
00920 document::document(char* buf, INIT_BUFFER_CONTROL control) :
00921 compressed_buf_(),
00922 output_(buf),
00923 buffers_(),
00924 root_(NULL),
00925 prev_(NULL),
00926 next_(NULL)
00927 {
00928 if(control == INIT_TAKE_OWNERSHIP) {
00929 buffers_.push_back(buf);
00930 }
00931 const char* cbuf = buf;
00932 root_ = new node(*this, NULL, &cbuf);
00933
00934 attach_list();
00935 }
00936
00937 document::document(const char* buf, INIT_STATE state) :
00938 compressed_buf_(),
00939 output_(buf),
00940 buffers_(),
00941 root_(NULL),
00942 prev_(NULL),
00943 next_(NULL)
00944 {
00945 if(state == INIT_COMPRESSED) {
00946 output_compressed();
00947 output_ = NULL;
00948 } else {
00949 root_ = new node(*this, NULL, &buf);
00950 }
00951
00952 attach_list();
00953 }
00954
00955 document::document(string_span compressed_buf) :
00956 compressed_buf_(compressed_buf),
00957 output_(NULL),
00958 buffers_(),
00959 root_(NULL),
00960 prev_(NULL),
00961 next_(NULL)
00962 {
00963 string_span uncompressed_buf;
00964 buffers_.push_back(uncompress_buffer(compressed_buf, &uncompressed_buf));
00965 output_ = uncompressed_buf.begin();
00966 const char* cbuf = output_;
00967 try {
00968 root_ = new node(*this, NULL, &cbuf);
00969 } catch(...) {
00970 delete [] buffers_.front();
00971 buffers_.clear();
00972 throw;
00973 }
00974
00975 attach_list();
00976 }
00977
00978 document::~document()
00979 {
00980 for(std::vector<char*>::iterator i = buffers_.begin(); i != buffers_.end(); ++i) {
00981 delete [] *i;
00982 }
00983
00984 buffers_.clear();
00985 debug_delete(root_);
00986
00987 detach_list();
00988 }
00989
00990 const char* document::dup_string(const char* str)
00991 {
00992 const int len = strlen(str);
00993 char* res = new char[len+1];
00994 memcpy(res, str, len + 1);
00995 buffers_.push_back(res);
00996 return res;
00997 }
00998
00999 const char* document::output()
01000 {
01001 if(output_ && (!root_ || root_->is_dirty() == false)) {
01002 return output_;
01003 }
01004 if(!root_) {
01005 assert(compressed_buf_.empty() == false);
01006 string_span uncompressed_buf;
01007 buffers_.push_back(uncompress_buffer(compressed_buf_, &uncompressed_buf));
01008 output_ = uncompressed_buf.begin();
01009 return output_;
01010 }
01011
01012
01013 compressed_buf_ = string_span();
01014
01015 std::vector<char*> bufs;
01016 bufs.swap(buffers_);
01017
01018 const int buf_size = root_->output_size() + 1;
01019 char* buf;
01020 try {
01021 buf = new char[buf_size];
01022 } catch (std::bad_alloc& e) {
01023 ERR_SWML << "ERROR: Trying to allocate " << buf_size << " bytes. "
01024 << e.what() << std::endl;
01025 throw error("Bad allocation request in output().");
01026 }
01027 buffers_.push_back(buf);
01028 output_ = buf;
01029
01030 root_->output(buf, node::REFRESH_CACHE);
01031 *buf++ = 0;
01032 assert(buf == output_ + buf_size);
01033
01034 for(std::vector<char*>::iterator i = bufs.begin(); i != bufs.end(); ++i) {
01035 delete [] *i;
01036 }
01037
01038 bufs.clear();
01039
01040 return output_;
01041 }
01042
01043 string_span document::output_compressed()
01044 {
01045 if(compressed_buf_.empty() == false &&
01046 (root_ == NULL || root_->is_dirty() == false)) {
01047 assert(*compressed_buf_.begin() == 31);
01048 return compressed_buf_;
01049 }
01050
01051 buffers_.push_back(compress_buffer(output(), &compressed_buf_));
01052 assert(*compressed_buf_.begin() == 31);
01053
01054 return compressed_buf_;
01055 }
01056
01057 void document::compress()
01058 {
01059 output_compressed();
01060 debug_delete(root_);
01061 root_ = NULL;
01062 output_ = NULL;
01063 std::vector<char*> new_buffers;
01064 for(std::vector<char*>::iterator i = buffers_.begin(); i != buffers_.end(); ++i) {
01065 if(*i != compressed_buf_.begin()) {
01066 delete [] *i;
01067 } else {
01068 new_buffers.push_back(*i);
01069 }
01070 }
01071
01072 buffers_.swap(new_buffers);
01073 assert(buffers_.size() == 1);
01074 }
01075
01076 void document::generate_root()
01077 {
01078 if(output_ == NULL) {
01079 assert(compressed_buf_.empty() == false);
01080 string_span uncompressed_buf;
01081 buffers_.push_back(uncompress_buffer(compressed_buf_, &uncompressed_buf));
01082 output_ = uncompressed_buf.begin();
01083 }
01084
01085 assert(root_ == NULL);
01086 const char* cbuf = output_;
01087 root_ = new node(*this, NULL, &cbuf);
01088 }
01089
01090 document* document::clone()
01091 {
01092 char* buf = new char[strlen(output())+1];
01093 strcpy(buf, output());
01094 return new document(buf);
01095 }
01096
01097 void document::swap(document& o)
01098 {
01099 std::swap(compressed_buf_, o.compressed_buf_);
01100 std::swap(output_, o.output_);
01101 buffers_.swap(o.buffers_);
01102 std::swap(root_, o.root_);
01103
01104 root_->set_doc(this);
01105 o.root_->set_doc(&o);
01106 }
01107
01108 void document::clear()
01109 {
01110 compressed_buf_ = string_span();
01111 output_ = NULL;
01112 debug_delete(root_);
01113 root_ = new node(*this, NULL);
01114 for(std::vector<char*>::iterator i = buffers_.begin(); i != buffers_.end(); ++i) {
01115 delete [] *i;
01116 }
01117
01118 buffers_.clear();
01119 }
01120
01121 namespace {
01122 document* head_doc = NULL;
01123 }
01124
01125 void document::attach_list()
01126 {
01127 prev_ = NULL;
01128 next_ = head_doc;
01129
01130 if(next_) {
01131 next_->prev_ = this;
01132 }
01133 head_doc = this;
01134 }
01135
01136 void document::detach_list()
01137 {
01138 if(head_doc == this) {
01139 head_doc = next_;
01140 }
01141
01142 if(next_) {
01143 next_->prev_ = prev_;
01144 }
01145
01146 if(prev_) {
01147 prev_->next_ = next_;
01148 }
01149 next_ = prev_ = NULL;
01150 }
01151
01152 std::string document::stats()
01153 {
01154 std::ostringstream s;
01155 int ndocs = 0;
01156 int ncompressed = 0;
01157 int compressed_size = 0;
01158 int ntext = 0;
01159 int text_size = 0;
01160 int nbuffers = 0;
01161 int nnodes = 0;
01162 int ndirty = 0;
01163 int nattributes = 0;
01164 for(document* d = head_doc; d != NULL; d = d->next_) {
01165 ndocs++;
01166 nbuffers += d->buffers_.size();
01167
01168 if(d->compressed_buf_.is_null() == false) {
01169 ++ncompressed;
01170 compressed_size += d->compressed_buf_.size();
01171 }
01172
01173 if(d->output_) {
01174 ++ntext;
01175 text_size += strlen(d->output_);
01176 }
01177
01178 if(d->root_) {
01179 nnodes += 1 + d->root_->nchildren();
01180 nattributes += d->root_->nattributes_recursive();
01181 }
01182
01183 if(d->root_ && d->root_->is_dirty()) {
01184 ++ndirty;
01185 }
01186 }
01187
01188 const int nodes_alloc = nnodes*(sizeof(node) + 12);
01189 const int attr_alloc = nattributes*(sizeof(string_span)*2);
01190 const int total_alloc = compressed_size + text_size + nodes_alloc + attr_alloc;
01191
01192 s << "WML documents: " << ndocs << "\n"
01193 << "Dirty: " << ndirty << "\n"
01194 << "With compression: " << ncompressed << " (" << compressed_size
01195 << " bytes)\n"
01196 << "With text: " << ntext << " (" << text_size
01197 << " bytes)\n"
01198 << "Nodes: " << nnodes << " (" << nodes_alloc << " bytes)\n"
01199 << "Attr: " << nattributes << " (" << attr_alloc << " bytes)\n"
01200 << "Buffers: " << nbuffers << "\n"
01201 << "Total allocation: " << total_alloc << " bytes\n";
01202
01203 return s.str();
01204 }
01205
01206 }
01207
01208 #ifdef UNIT_TEST_SIMPLE_WML
01209
01210 int main(int argc, char** argv)
01211 {
01212 char* doctext = strdup(
01213 "[test]\n"
01214 "a=\"blah\"\n"
01215 "b=\"blah\"\n"
01216 "c=\"\\\\\"\n"
01217 "d=\"\\\"\"\n"
01218 "[/test]");
01219 std::cerr << doctext << "\n";
01220 simple_wml::document doc(doctext);
01221
01222 simple_wml::node& node = doc.root();
01223 simple_wml::node* test_node = node.child("test");
01224 assert(test_node);
01225 assert((*test_node)["a"] == "blah");
01226 assert((*test_node)["b"] == "blah");
01227 assert((*test_node)["c"] == "\\\\");
01228 assert((*test_node)["d"] == "\\\"");
01229
01230 node.set_attr("blah", "blah");
01231 test_node->set_attr("e", "f");
01232 std::cerr << doc.output();
01233 }
01234
01235 #endif