/* Copyright (C) 2014 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 "JSONSpiritInclude.h" #if defined(_MSC_VER) # pragma warning(disable:4996) // deprecated CRT #endif #include "wx/log.h" #include static AtSmartPtr ConvertNode(json_spirit::Value node); AtObj AtlasObject::LoadFromJSON(const std::string& json) { json_spirit::Value rootnode; json_spirit::read_string(json, rootnode); AtObj obj; obj.p = ConvertNode(rootnode); return obj; } // Convert from a JSON to an AtNode static AtSmartPtr ConvertNode(json_spirit::Value node) { AtSmartPtr obj (new AtNode()); if (node.type() == json_spirit::str_type) { obj->value = std::wstring(node.get_str().begin(),node.get_str().end()); } else if (node.type() == json_spirit::int_type || node.type() == json_spirit::real_type) { std::wstringstream stream; if (node.type() == json_spirit::int_type) stream << node.get_int(); if (node.type() == json_spirit::real_type) stream << node.get_real(); obj->value = stream.str().c_str(); obj->children.insert(AtNode::child_pairtype( "@number", AtSmartPtr(new AtNode()) )); } else if (node.type() == json_spirit::bool_type) { if (node.get_bool()) obj->value = L"true"; else obj->value = L"false"; obj->children.insert(AtNode::child_pairtype( "@boolean", AtSmartPtr(new AtNode()) )); } else if (node.type() == json_spirit::array_type) { obj->children.insert(AtNode::child_pairtype( "@array", AtSmartPtr(new AtNode()) )); json_spirit::Array nodeChildren = node.get_array(); json_spirit::Array::iterator itr = nodeChildren.begin(); for (; itr != nodeChildren.end(); itr++) { obj->children.insert(AtNode::child_pairtype( "item", ConvertNode(*itr) )); } } else if (node.type() == json_spirit::obj_type) { json_spirit::Object objectProperties = node.get_obj(); json_spirit::Object::iterator itr = objectProperties.begin(); for (; itr != objectProperties.end(); itr++) { obj->children.insert(AtNode::child_pairtype( itr->name_, ConvertNode(itr->value_) )); } } else if (node.type() == json_spirit::null_type) { return obj; } else { assert(! "Unimplemented type found when parsing JSON!"); } return obj; } json_spirit::Value BuildJSONNode(AtNode::Ptr p) { if (!p) { json_spirit::Value rval; return rval; } // Special case for numbers/booleans to allow round-tripping if (p->children.count("@number")) { // Convert to double std::wstringstream str; str << p->value; double val = 0; str >> val; json_spirit::Value rval(val); return rval; } else if (p->children.count("@boolean")) { bool val = false; if (p->value == L"true") val = true; json_spirit::Value rval(val); return rval; } // If no children, then use the value string instead if (p->children.empty()) { json_spirit::Value rval(std::string(p->value.begin(), p->value.end())); return rval; } if (p->children.find("@array") != p->children.end()) { json_spirit::Array rval; // Find the children AtNode::child_maptype::const_iterator lower = p->children.lower_bound("item"); AtNode::child_maptype::const_iterator upper = p->children.upper_bound("item"); unsigned int idx = 0; for (AtNode::child_maptype::const_iterator it = lower; it != upper; ++it) { json_spirit::Value child = BuildJSONNode(it->second); rval.push_back(child); ++idx; } return rval; } else { json_spirit::Object rval; for (AtNode::child_maptype::const_iterator it = p->children.begin(); it != p->children.end(); ++it) { json_spirit::Value child = BuildJSONNode(it->second); // We don't serialize childs with null value. // Instead of something like this we omit the whole property: "StartingCamera": null // There's no special reason for that, it's just the same behaviour the previous implementations had. if (child.type() != json_spirit::null_type) rval.push_back(json_spirit::Pair(it->first.c_str(), child)); } return rval; } } std::string AtlasObject::SaveToJSON(AtObj& obj) { json_spirit::Value root = BuildJSONNode(obj.p); std::string ret = json_spirit::write_string(root, 0); return ret; }