Skip to content
Snippets Groups Projects
coreinfo.cpp 3.12 KiB
Newer Older
  • Learn to ignore specific revisions
  • Vicki Pfau's avatar
    Vicki Pfau committed
    #include "json.hpp"
    
    #include "coreinfo.h"
    #include "data.h"
    
    #include "utils.h"
    
    Vicki Pfau's avatar
    Vicki Pfau committed
    
    using namespace std;
    using nlohmann::json;
    
    namespace Retro {
    
    static string s_coreDirectory;
    static unordered_map<string, string> s_extensionToCore;
    static unordered_map<string, string> s_coreToLib;
    static json s_cores;
    
    string corePath(const string& hint) {
    	if (s_coreDirectory.size()) {
    		return s_coreDirectory;
    	}
    	const char* envDir = getenv("RETRO_CORE_PATH");
    	if (envDir) {
    		s_coreDirectory = envDir;
    	} else if (hint.size()) {
    
    Vicki Pfau's avatar
    Vicki Pfau committed
    		s_coreDirectory = drillUp({ "cores" }, ".", hint);
    
    Vicki Pfau's avatar
    Vicki Pfau committed
    	} else {
    		s_coreDirectory = ".";
    	}
    	return s_coreDirectory;
    }
    
    string libForCore(const string& core) {
    	return s_coreToLib[core];
    }
    
    string coreForRom(const string& rom) {
    	size_t dot = rom.find_last_of('.');
    	if (dot == string::npos) {
    		return {};
    	}
    	string extName = rom.substr(dot + 1);
    	if (s_extensionToCore.find(extName) == s_extensionToCore.end()) {
    		return {};
    	}
    	return s_extensionToCore[extName];
    }
    
    vector<string> buttons(const string& core) {
    	vector<string> results;
    	for (const auto& button : s_cores[core]["buttons"]) {
    		if (!button.is_string()) {
    			results.emplace_back();
    			continue;
    		}
    		results.emplace_back(static_cast<const string&>(button));
    	}
    	return results;
    }
    
    vector<string> keybinds(const string& core) {
    	vector<string> results;
    	for (const auto& button : s_cores[core]["keybinds"]) {
    		if (!button.is_string()) {
    			results.emplace_back();
    			continue;
    		}
    		results.emplace_back(static_cast<const string&>(button));
    	}
    	return results;
    }
    
    size_t ramBase(const string& core) {
    	return s_cores[core].value("rambase", 0);
    }
    
    void configureData(GameData* data, const string& core) {
    	if (s_cores[core].find("types") != s_cores[core].end()) {
    		vector<Retro::DataType> typesVec;
    		for (const string& type : s_cores[core]["types"]) {
    			typesVec.emplace_back(type);
    		}
    		data->setTypes(typesVec);
    	}
    	if (s_cores[core].find("overlay") != s_cores[core].end()) {
    		const auto& overlay = s_cores[core]["overlay"];
    		data->addressSpace().setOverlay(Retro::MemoryOverlay{
    			static_cast<char>(static_cast<const string&>(overlay[0])[0]),
    			static_cast<char>(static_cast<const string&>(overlay[1])[0]),
    			static_cast<size_t>(overlay[2]) });
    	}
    	data->setButtons(Retro::buttons(core));
    	if (s_cores[core].find("actions") != s_cores[core].end()) {
    		data->setActions(static_cast<const vector<vector<vector<string>>>&>(s_cores[core]["actions"]));
    	}
    }
    
    bool loadCoreInfo(const string& jsonData) {
    	json coreInfo;
    	istringstream jsonStream(jsonData);
    	try {
    		jsonStream >> coreInfo;
    		s_cores = coreInfo;
    	} catch (invalid_argument&) {
    		return false;
    	}
    
    	for (auto core = coreInfo.cbegin(); core != coreInfo.cend(); ++core) {
    		for (auto ext = core->at("ext").cbegin(); ext != core->at("ext").cend(); ++ext) {
    			s_extensionToCore[*ext] = core.key();
    		}
    		s_coreToLib[core.key()] = core->at("lib");
    	}
    	return true;
    }
    
    vector<string> cores() {
    	vector<string> c;
    	for (const auto& core : s_coreToLib) {
    		c.emplace_back(core.first);
    	}
    	return c;
    }
    
    vector<string> extensions() {
    	vector<string> e;
    	for (const auto& ext : s_extensionToCore) {
    		e.emplace_back(ext.first);
    	}
    	return e;
    }
    }