server/simple_wml.cpp

Go to the documentation of this file.
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 }  // namespace
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                 // Read until the first single double quote.
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                 // Stop if newline.
00288                 const char *endline = end + 1;
00289                 while (*endline == ' ') ++endline;
00290                 if (*endline == '\n') break;
00291 
00292                 // Read concatenation marker.
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                 // Read textdomain marker.
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                 // Read indentation and start of string.
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     //if we don't already have a vector for this item we don't want to add one.
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 // only define this symbol in debug mode to work out child ordering.
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     //calling output with status=DO_NOT_MODIFY_CACHE really doesn't modify the
00768     //node, so we can do it safely
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     //we're dirty, so the compressed buf must also be dirty; clear it.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:10 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs