/* Copyright (C) 2015 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "AtlasObject.h" #include "AtlasObjectImpl.h" #include #include #include #define ATSMARTPTR_IMPL(T) \ template<> void AtSmartPtr::inc_ref() \ { \ if (ptr) ++ptr->refcount; \ } \ \ template<> void AtSmartPtr::dec_ref() \ { \ if (ptr && --ptr->refcount == 0) \ delete ptr; \ } // (Don't set ptr=NULL, since it should never be possible for an // unreferenced pointer to exist; I would rather see it die in debug // mode if that ever happens, instead of just silently ignoring the error.) ATSMARTPTR_IMPL(AtNode) ATSMARTPTR_IMPL(const AtNode) ATSMARTPTR_IMPL(AtIterImpl) ////////////////////////////////////////////////////////////////////////// const AtIter AtIter::operator [] (const char* key) const { if (p) return p->iter->second->getChild(key); else return AtIter(); } AtIter::operator const wchar_t* () const { if (p) return p->iter->second->value.c_str(); else return L""; } //AtIter::operator const AtObj () const const AtObj AtIter::operator * () const { if (p) { AtObj ret; ret.p = p->iter->second; return ret; } else return AtObj(); } AtIter& AtIter::operator ++ () { assert(p); // Increment the internal iterator, and stop if we've run out children // to iterate over. if (p && ++p->iter == p->iter_upperbound) p = NULL; return *this; } bool AtIter::defined() const { return (bool)p; } bool AtIter::hasContent() const { if (!p) return false; if (! p->iter->second) return false; return p->iter->second->hasContent(); } size_t AtIter::count() const { if (!p) return 0; return std::distance(p->iter, p->iter_upperbound); } ////////////////////////////////////////////////////////////////////////// const AtIter AtObj::operator [] (const char* key) const { if (p) return p->getChild(key); else // This object doesn't exist, so return another object that doesn't exist return AtIter(); } AtObj::operator const wchar_t* () const { if (p) return p->value.c_str(); else return L""; } double AtObj::getDouble() const { double val = 0; if (p) { std::wstringstream s; s << p->value; s >> val; } return val; } int AtObj::getInt() const { int val = 0; if (p) { std::wstringstream s; s << p->value; s >> val; } return val; } void AtObj::add(const char* key, AtObj& data) { if (!p) p = new AtNode(); p = p->addChild(key, data.p); } void AtObj::add(const char* key, const wxString& value) { add(key, value.wc_str()); } void AtObj::add(const char* key, const wchar_t* value) { const AtNode* o = new AtNode(value); if (!p) p = new AtNode(); p = p->addChild(key, AtNode::Ptr(o)); } void AtObj::set(const char* key, AtObj& data) { if (!p) p = new AtNode(); p = p->setChild(key, data.p); } void AtObj::set(const char* key, const wxString& value) { set(key, value.wc_str()); } void AtObj::set(const char* key, const wchar_t* value) { const AtNode* o = new AtNode(value); if (!p) p = new AtNode(); p = p->setChild(key, AtNode::Ptr(o)); } void AtObj::setBool(const char* key, bool value) { AtNode* o = new AtNode(value ? L"true" : L"false"); o->children.insert(AtNode::child_pairtype("@boolean", AtNode::Ptr(new AtNode()))); if (!p) p = new AtNode(); p = p->setChild(key, AtNode::Ptr(o)); } void AtObj::setDouble(const char* key, double value) { std::wstringstream str; str << value; AtNode* o = new AtNode(str.str().c_str()); o->children.insert(AtNode::child_pairtype("@number", AtNode::Ptr(new AtNode()))); if (!p) p = new AtNode(); p = p->setChild(key, AtNode::Ptr(o)); } void AtObj::setInt(const char* key, int value) { std::wstringstream str; str << value; AtNode* o = new AtNode(str.str().c_str()); o->children.insert(AtNode::child_pairtype("@number", AtNode::Ptr(new AtNode()))); if (!p) p = new AtNode(); p = p->setChild(key, AtNode::Ptr(o)); } void AtObj::setString(const wchar_t* value) { if (!p) p = new AtNode(); p = p->setValue(value); } void AtObj::addOverlay(AtObj& data) { if (!p) p = new AtNode(); p = p->addOverlay(data.p); } bool AtObj::hasContent() const { if (!p) return false; return p->hasContent(); } ////////////////////////////////////////////////////////////////////////// const AtIter AtNode::getChild(const char* key) const { // Find the range of matching children AtNode::child_maptype::const_iterator it = children.lower_bound(key); AtNode::child_maptype::const_iterator it_upper = children.upper_bound(key); if (it == it_upper) // No match found return AtIter(); AtIter obj; obj.p = new AtIterImpl(it, it_upper); return obj; } bool AtNode::hasContent() const { if (value.length()) return true; for (child_maptype::const_iterator it = children.begin(); it != children.end(); ++it) if (it->second && it->second->hasContent()) return true; return false; } const AtNode::Ptr AtNode::setValue(const wchar_t* value) const { AtNode* newNode = new AtNode(); newNode->children = children; newNode->value = value; return AtNode::Ptr(newNode); } const AtNode::Ptr AtNode::setChild(const char* key, const AtNode::Ptr &data) const { AtNode* newNode = new AtNode(this); newNode->children.erase(key); newNode->children.insert(AtNode::child_pairtype(key, data)); return AtNode::Ptr(newNode); } const AtNode::Ptr AtNode::addChild(const char* key, const AtNode::Ptr &data) const { AtNode* newNode = new AtNode(this); newNode->children.insert(AtNode::child_pairtype(key, data)); return AtNode::Ptr(newNode); } const AtNode::Ptr AtNode::addOverlay(const AtNode::Ptr &data) const { AtNode* newNode = new AtNode(this); // Delete old childs that are also in the overlay for (AtNode::child_maptype::const_iterator it = data->children.begin(); it != data->children.end(); ++it) newNode->children.erase(it->first); // Add the overlay childs back in for (AtNode::child_maptype::const_iterator it = data->children.begin(); it != data->children.end(); ++it) newNode->children.insert(*it); return AtNode::Ptr(newNode); } ////////////////////////////////////////////////////////////////////////// AtObj AtlasObject::TrimEmptyChildren(AtObj& obj) { AtObj ret; for (AtNode::child_maptype::const_iterator it = obj.p->children.begin(); it != obj.p->children.end(); ++it) { if (it->second && it->second->hasContent()) { AtObj node; node.p = it->second; ret.add(it->first.c_str(), node); } } return ret; }