// wxMASSManager // Copyright (C) 2020 Guillaume Jacquemin // // This program 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 3 of the License, or // (at your option) any later version. // // This program 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 this program. If not, see . #include #if !(CORRADE_VERSION_YEAR * 100 + CORRADE_VERSION_MONTH >= 202006) #error This application requires Corrade 2020.06 or later to build. #endif #include #include #include #include #include "Profile.h" constexpr char company_name_locator[] = { 'C', 'o', 'm', 'p', 'a', 'n', 'y', 'N', 'a', 'm', 'e', '\0', 0x0C, '\0', '\0', '\0', 'S', 't', 'r', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' }; constexpr char active_slot_locator[] = { 'A', 'c', 't', 'i', 'v', 'e', 'F', 'r', 'a', 'm', 'e', 'S', 'l', 'o', 't', '\0', 0x0C, '\0', '\0', '\0', 'I', 'n', 't', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' }; constexpr char credits_locator[] = { 'C', 'r', 'e', 'd', 'i', 't', '\0', 0x0C, '\0', '\0', '\0', 'I', 'n', 't', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' }; using namespace Corrade; Profile::Profile(const std::string& path) { auto map = Utility::Directory::mapRead(path); if(!map) { _lastError = "Couldn't memory-map " + Utility::Directory::filename(path); return; } _profileDirectory = Utility::Directory::path(path); _filename = Utility::Directory::filename(path); if(Utility::String::beginsWith(_filename, "Demo")) { _type = ProfileType::Demo; } else { _type = ProfileType::FullGame; } _steamId = Utility::String::ltrim(Utility::String::rtrim(_filename, ".sav"), (_type == ProfileType::Demo ? "Demo" : "") + std::string{"Profile"}); auto it = std::search(map.begin(), map.end(), &company_name_locator[0], &company_name_locator[27]); if(it == map.end()) { _lastError = "Couldn't find a company name in " + _filename; return; } _companyName = std::string{it + 41}; _valid = true; } auto Profile::valid() const -> bool { return _valid; } auto Profile::lastError() const -> std::string const& { return _lastError; } auto Profile::filename() const -> std::string const& { return _filename; } auto Profile::type() const -> ProfileType { return _type; } auto Profile::steamId() const -> std::string const& { return _steamId; } auto Profile::companyName() const -> std::string const& { return _companyName; } auto Profile::activeFrameSlot() const -> std::int8_t { return _activeFrameSlot; } auto Profile::getActiveFrameSlot() -> std::int8_t { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &active_slot_locator[0], &active_slot_locator[31]); if(iter == mmap.end()) { if(std::search(mmap.begin(), mmap.end(), &credits_locator[0], &credits_locator[22]) != mmap.end()) { _activeFrameSlot = 0; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _activeFrameSlot = -1; } } else { _activeFrameSlot = *(iter + 41); } return _activeFrameSlot; } auto Profile::credits() const -> std::int32_t { return _credits; } auto Profile::getCredits() -> std::int32_t { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &credits_locator[0], &credits_locator[22]); if(iter != mmap.end()) { _credits = ((*(iter + 0x20)) << 0) + ((*(iter + 0x21)) << 8) + ((*(iter + 0x22)) << 16) + ((*(iter + 0x23)) << 24); } else{ _credits = -1; } return _credits; }