wxString GUI::GetDataDirectory() { std::string cfg_str = g_settings.getString(Config::DATA_DIRECTORY); if(cfg_str.size()) { FileName dir; dir.Assign(wxstr(cfg_str)); wxString path; if(dir.DirExists()) { path = dir.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR); return path; } } // Silently reset directory FileName exec_directory; try { exec_directory = dynamic_cast<wxStandardPaths&>(wxStandardPaths::Get()).GetExecutablePath(); } catch(std::bad_cast) { throw; // Crash application (this should never happend anyways...) } exec_directory.AppendDir(wxT("data")); return exec_directory.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR); }
wxString GUI::GetLocalDirectory() { if(g_settings.getInteger(Config::INDIRECTORY_INSTALLATION)) { FileName dir = GetDataDirectory(); dir.AppendDir(wxT("user")); dir.Mkdir(0755, wxPATH_MKDIR_FULL); return dir.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);; } else { FileName dir = dynamic_cast<wxStandardPaths&>(wxStandardPaths::Get()).GetUserDataDir(); #ifdef __WINDOWS__ dir.AppendDir(wxT("Remere's Map Editor")); #else dir.AppendDir(wxT(".rme")); #endif dir.Mkdir(0755, wxPATH_MKDIR_FULL); return dir.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR); } }
bool Materials::unserializeMaterials(const FileName& filename, xmlNodePtr root, wxString& error, wxArrayString& warnings) { xmlNodePtr materialNode = root->children; wxString warning; while(materialNode) { warning = wxT(""); if(xmlStrcmp(materialNode->name,(const xmlChar*)"include") == 0) { std::string include_file; if(readXMLValue(materialNode, "file", include_file)) { FileName include_name; include_name.SetPath(filename.GetPath()); include_name.SetFullName(wxstr(include_file)); wxString suberror; bool success = loadMaterials(include_name, suberror, warnings); if(!success) warnings.push_back(wxT("Error while loading file \"") + wxstr(include_file) + wxT("\": ") + suberror); } } else if(xmlStrcmp(materialNode->name,(const xmlChar*)"metaitem") == 0) { item_db.loadMetaItem(materialNode); } else if(xmlStrcmp(materialNode->name,(const xmlChar*)"border") == 0) { brushes.unserializeBorder(materialNode, warnings); if(warning.size()) warnings.push_back(wxT("materials.xml: ") + warning); } else if(xmlStrcmp(materialNode->name,(const xmlChar*)"brush") == 0) { brushes.unserializeBrush(materialNode, warnings); if(warning.size()) warnings.push_back(wxT("materials.xml: ") + warning); } else if(xmlStrcmp(materialNode->name,(const xmlChar*)"tileset") == 0) { unserializeTileset(materialNode, warnings); } materialNode = materialNode->next; } return true; }
wxString GUI::GetExtensionsDirectory() { std::string cfg_str = g_settings.getString(Config::EXTENSIONS_DIRECTORY); if(cfg_str.size()) { FileName dir; dir.Assign(wxstr(cfg_str)); wxString path; if(dir.DirExists()) { path = dir.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR); return path; } } // Silently reset directory FileName local_directory = GetLocalDirectory(); local_directory.AppendDir(wxT("extensions")); local_directory.Mkdir(0755, wxPATH_MKDIR_FULL); return local_directory.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR); }
bool Materials::unserializeMaterials(const FileName& filename, pugi::xml_node node, wxString& error, wxArrayString& warnings) { wxString warning; pugi::xml_attribute attribute; for(pugi::xml_node childNode = node.first_child(); childNode; childNode = childNode.next_sibling()) { const std::string& childName = as_lower_str(childNode.name()); if(childName == "include") { if(!(attribute = childNode.attribute("file"))) { continue; } FileName includeName; includeName.SetPath(filename.GetPath()); includeName.SetFullName(wxString(attribute.as_string(), wxConvUTF8)); wxString subError; if(!loadMaterials(includeName, subError, warnings)) { warnings.push_back("Error while loading file \"" + includeName.GetFullName() + "\": " + subError); } } else if(childName == "metaitem") { g_items.loadMetaItem(childNode); } else if(childName == "border") { g_brushes.unserializeBorder(childNode, warnings); if(warning.size()) { warnings.push_back("materials.xml: " + warning); } } else if(childName == "brush") { g_brushes.unserializeBrush(childNode, warnings); if(warning.size()) { warnings.push_back("materials.xml: " + warning); } } else if(childName == "tileset") { unserializeTileset(childNode, warnings); } } return true; }
bool ItemDatabase::loadFromOtb(const FileName& datafile, wxString& error, wxArrayString& warnings) { std::string filename = nstr((datafile.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR) + datafile.GetFullName())); DiskNodeFileReadHandle f(filename, StringVector(1, "OTBI")); if(!f.isOk()) { error = wxT("Couldn't open file \"") + wxstr(filename) + wxT("\":") + wxstr(f.getErrorMessage()); return false; } BinaryNode* root = f.getRootNode(); #define safe_get(node, func, ...) do {\ if(!node->get##func(__VA_ARGS__)) {\ error = wxstr(f.getErrorMessage()); \ return false; \ } \ } while(false) // Read root flags root->skip(1); // Type info //uint32_t flags = root->skip(4); // Unused? uint8_t attr; safe_get(root, U8, attr); if(attr == ROOT_ATTR_VERSION) { uint16_t datalen; if(!root->getU16(datalen) || datalen != 4 + 4 + 4 + 1*128) { error = wxT("items.otb: Size of version header is invalid, updated .otb version?"); return false; } safe_get(root, U32, MajorVersion); // items otb format file version safe_get(root, U32, MinorVersion); // client version safe_get(root, U32, BuildNumber); // revision std::string csd; csd.resize(128); if(!root->getRAW((uint8_t*)csd.data(), 128)) { // CSDVersion ?? error = wxstr(f.getErrorMessage()); return false; } } else { error = wxT("Expected ROOT_ATTR_VERSION as first node of items.otb!"); } if(settings.getInteger(Config::CHECK_SIGNATURES)) { if(gui.GetCurrentVersion().getOTBVersion().format_version != MajorVersion) { error = wxT("Unsupported items.otb version (version ") + i2ws(MajorVersion) + wxT(")"); return false; } } BinaryNode* itemNode = root->getChild(); switch(MajorVersion) { case 1: return loadFromOtbVer1(itemNode, error, warnings); case 2: return loadFromOtbVer2(itemNode, error, warnings); case 3: return loadFromOtbVer3(itemNode, error, warnings); } return true; }
bool Materials::loadExtensions(FileName directoryName, wxString& error, wxArrayString& warnings) { directoryName.Mkdir(0755, wxPATH_MKDIR_FULL); // Create if it doesn't exist wxDir ext_dir(directoryName.GetPath()); if(!ext_dir.IsOpened()) { error = "Could not open extensions directory."; return false; } wxString filename; if(!ext_dir.GetFirst(&filename)) { // No extensions found return true; } StringVector clientVersions; do { FileName fn; fn.SetPath(directoryName.GetPath()); fn.SetFullName(filename); if(fn.GetExt() != "xml") { continue; } pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(fn.GetFullPath().mb_str()); if(!result) { warnings.push_back("Could not open " + filename + " (file not found or syntax error)"); continue; } pugi::xml_node extensionNode = doc.child("materialsextension"); if(!extensionNode) { warnings.push_back(filename + ": Invalid rootheader."); continue; } pugi::xml_attribute attribute; if(!(attribute = extensionNode.attribute("name"))) { warnings.push_back(filename + ": Couldn't read extension name."); continue; } const std::string& extensionName = attribute.as_string(); if(!(attribute = extensionNode.attribute("author"))) { warnings.push_back(filename + ": Couldn't read extension name."); continue; } const std::string& extensionAuthor = attribute.as_string(); if(!(attribute = extensionNode.attribute("description"))) { warnings.push_back(filename + ": Couldn't read extension name."); continue; } const std::string& extensionDescription = attribute.as_string(); if(extensionName.empty() || extensionAuthor.empty() || extensionDescription.empty()) { warnings.push_back(filename + ": Couldn't read extension attributes (name, author, description)."); continue; } std::string extensionUrl = extensionNode.attribute("url").as_string(); extensionUrl.erase(std::remove(extensionUrl.begin(), extensionUrl.end(), '\'')); std::string extensionAuthorLink = extensionNode.attribute("authorurl").as_string(); extensionAuthorLink.erase(std::remove(extensionAuthorLink.begin(), extensionAuthorLink.end(), '\'')); MaterialsExtension* materialExtension = newd MaterialsExtension(extensionName, extensionAuthor, extensionDescription); materialExtension->url = extensionUrl; materialExtension->author_url = extensionAuthorLink; if((attribute = extensionNode.attribute("client"))) { clientVersions.clear(); const std::string& extensionClientString = attribute.as_string(); size_t lastPosition = 0; size_t position = extensionClientString.find(';'); while(position != std::string::npos) { clientVersions.push_back(extensionClientString.substr(lastPosition, position - lastPosition)); lastPosition = position + 1; position = extensionClientString.find(';', lastPosition); } clientVersions.push_back(extensionClientString.substr(lastPosition)); for(const std::string& version : clientVersions) { materialExtension->addVersion(version); } std::sort(materialExtension->version_list.begin(), materialExtension->version_list.end(), VersionComparisonPredicate); auto duplicate = std::unique(materialExtension->version_list.begin(), materialExtension->version_list.end()); while(duplicate != materialExtension->version_list.end()) { materialExtension->version_list.erase(duplicate); duplicate = std::unique(materialExtension->version_list.begin(), materialExtension->version_list.end()); } } else { warnings.push_back(filename + ": Extension is not available for any version."); } extensions.push_back(materialExtension); if(materialExtension->isForVersion(g_gui.GetCurrentVersionID())) { unserializeMaterials(filename, extensionNode, error, warnings); } } while(ext_dir.GetNext(&filename)); return true; }
bool Materials::loadExtensions(FileName directoryName, wxString& error, wxArrayString& warnings) { directoryName.Mkdir(0755, wxPATH_MKDIR_FULL); // Create if it doesn't exist wxDir ext_dir(directoryName.GetPath()); if(ext_dir.IsOpened() == false) { error = wxT("Could not open extensions directory."); return false; } wxString filename; if(!ext_dir.GetFirst(&filename)) { // No extensions found return true; } do { FileName fn; fn.SetPath(directoryName.GetPath()); fn.SetFullName(filename); if(fn.GetExt() != wxT("xml")) continue; xmlDocPtr doc = xmlParseFile(fn.GetFullPath().mb_str()); if(doc) { xmlNodePtr root = xmlDocGetRootElement(doc); if(xmlStrcmp(root->name,(const xmlChar*)"materialsextension") != 0){ xmlFreeDoc(doc); warnings.push_back(filename + wxT(": Invalid rootheader.")); continue; } std::string ext_name, ext_url, ext_author, ext_author_link, ext_desc, ext_client_str; StringVector clientVersions; if( !readXMLValue(root, "name", ext_name) || !readXMLValue(root, "author", ext_author) || !readXMLValue(root, "description", ext_desc)) { warnings.push_back(filename + wxT(": Couldn't read extension attributes (name, author, description).")); continue; } readXMLValue(root, "url", ext_url); ext_url.erase(std::remove(ext_url.begin(), ext_url.end(), '\''), ext_url.end()); readXMLValue(root, "authorurl", ext_author_link); ext_author_link.erase(std::remove(ext_author_link.begin(), ext_author_link.end(), '\''), ext_author_link.end()); MaterialsExtension* me = newd MaterialsExtension(ext_name, ext_author, ext_desc); me->url = ext_url; me->author_url = ext_author_link; if(readXMLValue(root, "client", ext_client_str)) { size_t last_pos = std::numeric_limits<size_t>::max(); size_t pos; do { size_t to_pos = (last_pos == std::numeric_limits<size_t>::max()? 0 : last_pos+1); pos = ext_client_str.find(';', to_pos); if(size_t(pos) != std::string::npos) { clientVersions.push_back(ext_client_str.substr(to_pos, pos-(to_pos))); last_pos = pos; } else { clientVersions.push_back(ext_client_str.substr(to_pos)); break; } } while(true); for(StringVector::iterator iter = clientVersions.begin(); iter != clientVersions.end(); ++iter) { me->addVersion(*iter); } std::sort(me->version_list.begin(), me->version_list.end(), VersionComparisonPredicate); me->version_list.erase(std::unique(me->version_list.begin(), me->version_list.end()), me->version_list.end()); } else { warnings.push_back(filename + wxT(": Extension is not available for any version.")); } extensions.push_back(me); if(me->isForVersion(gui.GetCurrentVersionID())) { unserializeMaterials(filename, root, error, warnings); } } else { warnings.push_back(wxT("Could not open ") + filename + wxT(" (file not found or syntax error)")); continue; } } while(ext_dir.GetNext(&filename)); return true; }