2012-06-29 16:49:59 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Copyright (C) 2012 FIX94
|
|
|
|
*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
****************************************************************************/
|
2012-04-10 19:12:38 +02:00
|
|
|
#include <gccore.h>
|
|
|
|
#include <ogcsys.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2012-07-27 19:26:49 +02:00
|
|
|
#include <malloc.h>
|
2012-06-29 16:49:59 +02:00
|
|
|
|
2012-04-10 19:12:38 +02:00
|
|
|
#include "plugin.hpp"
|
|
|
|
#include "gui/text.hpp"
|
2012-04-12 00:01:41 +02:00
|
|
|
#include "gecko/gecko.h"
|
2012-05-23 18:27:55 +02:00
|
|
|
#include "devicemounter/PartitionHandle.h"
|
|
|
|
#include "devicemounter/DeviceHandler.hpp"
|
2012-06-16 19:03:23 +02:00
|
|
|
#include "types.h"
|
2012-06-08 21:29:23 +02:00
|
|
|
#include "crc32.h"
|
2012-04-12 00:01:41 +02:00
|
|
|
|
2012-10-04 16:35:08 +02:00
|
|
|
void Plugin::init(const string& m_pluginsDir)
|
2012-04-10 19:12:38 +02:00
|
|
|
{
|
|
|
|
pluginsDir = m_pluginsDir;
|
|
|
|
//Ready to add plugins
|
|
|
|
adding = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Plugin::EndAdd()
|
|
|
|
{
|
|
|
|
adding = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Plugin::Cleanup()
|
|
|
|
{
|
2012-10-01 21:55:55 +02:00
|
|
|
Plugins.clear();
|
|
|
|
adding = true;
|
2012-04-10 19:12:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Plugin::AddPlugin(Config &plugin)
|
|
|
|
{
|
|
|
|
if(!adding)
|
|
|
|
return false;
|
2012-04-12 00:01:41 +02:00
|
|
|
|
2012-05-01 15:30:16 +02:00
|
|
|
PluginOptions NewPlugin;
|
2012-10-04 16:35:08 +02:00
|
|
|
NewPlugin.DolName = plugin.getString(PLUGIN_DOMAIN, "dolFile");
|
|
|
|
NewPlugin.coverFolder = plugin.getString(PLUGIN_DOMAIN, "coverFolder");
|
|
|
|
NewPlugin.magicWord = strtoul(plugin.getString(PLUGIN_DOMAIN, "magic").c_str(), NULL, 16);
|
|
|
|
NewPlugin.caseColor = strtoul(plugin.getString(PLUGIN_DOMAIN, "coverColor").c_str(), NULL, 16);
|
2012-10-01 21:55:55 +02:00
|
|
|
NewPlugin.Args = plugin.getStrings(PLUGIN_DOMAIN, "arguments", '|');
|
2012-10-04 16:35:08 +02:00
|
|
|
string PluginName = plugin.getString(PLUGIN_DOMAIN, "displayname");
|
|
|
|
if(PluginName.size() < 2)
|
2012-05-11 20:46:43 +02:00
|
|
|
{
|
|
|
|
PluginName = NewPlugin.DolName;
|
|
|
|
PluginName.erase(PluginName.end() - 4, PluginName.end());
|
|
|
|
}
|
|
|
|
NewPlugin.DisplayName.fromUTF8(PluginName.c_str());
|
2012-10-04 16:35:08 +02:00
|
|
|
NewPlugin.consoleCoverID = plugin.getString(PLUGIN_DOMAIN,"consoleCoverID");
|
2012-05-11 20:46:43 +02:00
|
|
|
|
2012-10-04 16:35:08 +02:00
|
|
|
const char *bannerfilepath = fmt("%s/%s", pluginsDir.c_str(), plugin.getString(PLUGIN_DOMAIN,"bannerSound").c_str());
|
2012-10-01 21:55:55 +02:00
|
|
|
FILE *fp = fopen(bannerfilepath, "rb");
|
|
|
|
if(fp != NULL)
|
2012-04-10 19:12:38 +02:00
|
|
|
{
|
2012-10-01 21:55:55 +02:00
|
|
|
fseek(fp, 0, SEEK_END);
|
|
|
|
NewPlugin.BannerSound = string(bannerfilepath);
|
|
|
|
NewPlugin.BannerSoundSize = ftell(fp);
|
|
|
|
rewind(fp);
|
|
|
|
fclose(fp);
|
2012-04-10 19:12:38 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-10-01 21:55:55 +02:00
|
|
|
NewPlugin.BannerSound = std::string();
|
2012-05-01 15:30:16 +02:00
|
|
|
NewPlugin.BannerSoundSize = 0;
|
2012-04-10 19:12:38 +02:00
|
|
|
}
|
2012-10-01 21:55:55 +02:00
|
|
|
Plugins.push_back(NewPlugin);
|
2012-04-10 19:12:38 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-05-04 20:05:41 +02:00
|
|
|
s8 Plugin::GetPluginPosition(u32 magic)
|
2012-04-14 21:43:37 +02:00
|
|
|
{
|
2012-05-01 15:30:16 +02:00
|
|
|
for(u8 pos = 0; pos < Plugins.size(); pos++)
|
2012-04-14 21:43:37 +02:00
|
|
|
{
|
2012-05-01 15:30:16 +02:00
|
|
|
if(magic == Plugins[pos].magicWord)
|
2012-05-04 20:05:41 +02:00
|
|
|
return pos;
|
2012-04-14 21:43:37 +02:00
|
|
|
}
|
2012-05-04 20:05:41 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-04-10 19:12:38 +02:00
|
|
|
u8* Plugin::GetBannerSound(u32 magic)
|
|
|
|
{
|
2012-05-04 20:05:41 +02:00
|
|
|
if((Plugin_Pos = GetPluginPosition(magic)) >= 0)
|
2012-10-01 21:55:55 +02:00
|
|
|
{
|
|
|
|
u8 *FileReadBuffer = NULL;
|
|
|
|
FILE *fp = fopen(Plugins[Plugin_Pos].BannerSound.c_str(), "rb");
|
|
|
|
if(fp)
|
|
|
|
{
|
|
|
|
FileReadBuffer = (u8*)MEM2_alloc(Plugins[Plugin_Pos].BannerSoundSize);
|
|
|
|
fread(FileReadBuffer, 1, Plugins[Plugin_Pos].BannerSoundSize, fp);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
return FileReadBuffer;
|
|
|
|
}
|
2012-04-10 19:12:38 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 Plugin::GetBannerSoundSize()
|
|
|
|
{
|
|
|
|
//We call that directly after GetBannerSound, so no need to search for the magic again
|
2012-05-04 20:05:41 +02:00
|
|
|
if(Plugin_Pos >= 0)
|
|
|
|
return Plugins[Plugin_Pos].BannerSoundSize;
|
2012-04-10 19:12:38 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* Plugin::GetDolName(u32 magic)
|
|
|
|
{
|
2012-05-04 20:05:41 +02:00
|
|
|
if((Plugin_Pos = GetPluginPosition(magic)) >= 0)
|
|
|
|
return (char*)Plugins[Plugin_Pos].DolName.c_str();
|
2012-10-04 16:35:08 +02:00
|
|
|
return NULL;
|
2012-05-01 15:30:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
char* Plugin::GetCoverFolderName(u32 magic)
|
|
|
|
{
|
2012-05-04 20:05:41 +02:00
|
|
|
if((Plugin_Pos = GetPluginPosition(magic)) >= 0)
|
|
|
|
return (char*)Plugins[Plugin_Pos].coverFolder.c_str();
|
2012-10-04 16:35:08 +02:00
|
|
|
return NULL;
|
2012-04-10 19:12:38 +02:00
|
|
|
}
|
2012-04-12 00:01:41 +02:00
|
|
|
|
2012-05-05 22:07:54 +02:00
|
|
|
bool Plugin::PluginExist(u8 pos)
|
|
|
|
{
|
|
|
|
if(pos < Plugins.size())
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
wstringEx Plugin::GetPluginName(u8 pos)
|
|
|
|
{
|
2012-05-11 20:46:43 +02:00
|
|
|
return Plugins[pos].DisplayName;
|
2012-05-05 22:07:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Plugin::SetEnablePlugin(Config &cfg, u8 pos, u8 ForceMode)
|
|
|
|
{
|
|
|
|
if(pos < Plugins.size())
|
|
|
|
{
|
2012-06-01 17:05:05 +02:00
|
|
|
char PluginMagicWord[9];
|
2012-10-04 16:35:08 +02:00
|
|
|
memset(PluginMagicWord, 0, sizeof(PluginMagicWord));
|
|
|
|
strncpy(PluginMagicWord, fmt("%08x", Plugins[pos].magicWord), 8);
|
2012-05-05 22:07:54 +02:00
|
|
|
if(ForceMode == 1)
|
2012-10-01 21:55:55 +02:00
|
|
|
cfg.setBool(PLUGIN_DOMAIN, PluginMagicWord, false);
|
2012-05-05 22:07:54 +02:00
|
|
|
else if(ForceMode == 2)
|
2012-10-01 21:55:55 +02:00
|
|
|
cfg.setBool(PLUGIN_DOMAIN, PluginMagicWord, true);
|
2012-05-05 22:07:54 +02:00
|
|
|
else
|
2012-10-01 21:55:55 +02:00
|
|
|
cfg.setBool(PLUGIN_DOMAIN, PluginMagicWord, cfg.getBool(PLUGIN_DOMAIN, PluginMagicWord) ? false : true);
|
2012-05-05 22:07:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-13 00:25:22 +02:00
|
|
|
const vector<bool> &Plugin::GetEnabledPlugins(Config &cfg)
|
2012-05-05 22:07:54 +02:00
|
|
|
{
|
2012-10-04 16:35:08 +02:00
|
|
|
enabledPlugins.clear();
|
2012-06-01 15:58:19 +02:00
|
|
|
char PluginMagicWord[9];
|
2012-05-05 22:07:54 +02:00
|
|
|
u8 enabledPluginsNumber = 0;
|
|
|
|
for(u8 i = 0; i < Plugins.size(); i++)
|
|
|
|
{
|
2012-10-04 16:35:08 +02:00
|
|
|
memset(PluginMagicWord, 0, sizeof(PluginMagicWord));
|
|
|
|
strncpy(PluginMagicWord, fmt("%08x", Plugins[i].magicWord), 8);
|
2012-10-01 21:55:55 +02:00
|
|
|
if(cfg.getBool(PLUGIN_DOMAIN, PluginMagicWord, true))
|
2012-05-05 22:07:54 +02:00
|
|
|
{
|
|
|
|
enabledPluginsNumber++;
|
|
|
|
enabledPlugins.push_back(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
enabledPlugins.push_back(false);
|
|
|
|
}
|
|
|
|
if(enabledPluginsNumber == Plugins.size())
|
|
|
|
enabledPlugins.clear();
|
2012-10-13 00:25:22 +02:00
|
|
|
return enabledPlugins;
|
2012-05-05 22:07:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 Plugin::getPluginMagic(u8 pos)
|
|
|
|
{
|
|
|
|
return Plugins[pos].magicWord;
|
|
|
|
}
|
|
|
|
|
2012-10-13 00:25:22 +02:00
|
|
|
vector<dir_discHdr> Plugin::ParseScummvmINI(Config &ini, const char *Device, u32 MagicWord)
|
2012-04-12 00:01:41 +02:00
|
|
|
{
|
|
|
|
gprintf("Parsing scummvm.ini\n");
|
2012-05-06 14:03:43 +02:00
|
|
|
vector<dir_discHdr> gameHeader;
|
2012-04-28 18:52:41 +02:00
|
|
|
if(!ini.loaded())
|
|
|
|
return gameHeader;
|
2012-05-29 15:49:28 +02:00
|
|
|
|
2012-10-04 16:35:08 +02:00
|
|
|
const string *GameDomain = &ini.firstDomain();
|
|
|
|
dir_discHdr ListElement;
|
2012-04-12 00:01:41 +02:00
|
|
|
while(1)
|
|
|
|
{
|
2012-10-04 16:35:08 +02:00
|
|
|
if(GameDomain->size() < 2)
|
2012-04-21 17:41:18 +02:00
|
|
|
break;
|
2012-10-04 16:35:08 +02:00
|
|
|
const string &GameName = ini.getString(*GameDomain, "description");
|
2012-10-13 00:25:22 +02:00
|
|
|
if(GameName.size() < 2 || strncasecmp(Device, ini.getString(*GameDomain, "path").c_str(), 2) != 0)
|
2012-04-12 00:01:41 +02:00
|
|
|
{
|
2012-10-04 16:35:08 +02:00
|
|
|
GameDomain = &ini.nextDomain();
|
2012-04-12 00:01:41 +02:00
|
|
|
continue;
|
|
|
|
}
|
2012-10-04 16:35:08 +02:00
|
|
|
memset((void*)&ListElement, 0, sizeof(dir_discHdr));
|
|
|
|
strncpy((char*)ListElement.id, PLUGIN_DOMAIN, 6);
|
|
|
|
ListElement.casecolor = Plugins.back().caseColor;
|
|
|
|
mbstowcs(ListElement.title, GameName.c_str(), 63);
|
|
|
|
strncpy(ListElement.path, GameDomain->c_str(), sizeof(ListElement.path));
|
|
|
|
gprintf("Found: %s\n", GameDomain->c_str());
|
2012-10-13 00:25:22 +02:00
|
|
|
ListElement.settings[0] = MagicWord;
|
2012-10-04 16:35:08 +02:00
|
|
|
ListElement.type = TYPE_PLUGIN;
|
|
|
|
gameHeader.push_back(ListElement);
|
|
|
|
GameDomain = &ini.nextDomain();
|
2012-04-12 00:01:41 +02:00
|
|
|
}
|
|
|
|
return gameHeader;
|
|
|
|
}
|
2012-05-23 18:27:55 +02:00
|
|
|
|
2012-10-04 16:35:08 +02:00
|
|
|
vector<string> Plugin::CreateArgs(const string& device, const string& path,
|
|
|
|
const string& title, const string& loader, u32 magic)
|
2012-05-23 18:27:55 +02:00
|
|
|
{
|
|
|
|
vector<string> args;
|
2012-10-01 21:55:55 +02:00
|
|
|
Plugin_Pos = GetPluginPosition(magic);
|
|
|
|
if(Plugin_Pos < 0)
|
|
|
|
return args;
|
2012-10-04 16:35:08 +02:00
|
|
|
for(vector<string>::const_iterator arg = Plugins[Plugin_Pos].Args.begin();
|
|
|
|
arg != Plugins[Plugin_Pos].Args.end(); ++arg)
|
2012-05-23 18:27:55 +02:00
|
|
|
{
|
2012-10-01 21:55:55 +02:00
|
|
|
string Argument(*arg);
|
|
|
|
if(Argument.find(PLUGIN_DEV) != string::npos)
|
|
|
|
Argument.replace(Argument.find(PLUGIN_DEV), strlen(PLUGIN_DEV), device);
|
|
|
|
if(Argument.find(PLUGIN_PATH) != string::npos)
|
|
|
|
Argument.replace(Argument.find(PLUGIN_PATH), strlen(PLUGIN_PATH), path);
|
|
|
|
if(Argument.find(PLUGIN_NAME) != string::npos)
|
|
|
|
Argument.replace(Argument.find(PLUGIN_NAME), strlen(PLUGIN_NAME), title);
|
|
|
|
if(Argument.find(PLUGIN_LDR) != string::npos)
|
|
|
|
Argument.replace(Argument.find(PLUGIN_LDR), strlen(PLUGIN_LDR), loader);
|
|
|
|
args.push_back(Argument);
|
2012-05-23 18:27:55 +02:00
|
|
|
}
|
|
|
|
return args;
|
|
|
|
}
|
|
|
|
|
2012-10-04 16:35:08 +02:00
|
|
|
string Plugin::GenerateCoverLink(dir_discHdr gameHeader, const string& constURL, Config &Checksums)
|
2012-06-08 21:29:23 +02:00
|
|
|
{
|
2012-10-04 16:35:08 +02:00
|
|
|
string url(constURL);
|
2012-06-17 12:22:00 +02:00
|
|
|
Plugin_Pos = GetPluginPosition(gameHeader.settings[0]);
|
2012-06-08 21:29:23 +02:00
|
|
|
|
|
|
|
if(url.find(TAG_LOC) != url.npos)
|
|
|
|
url.replace(url.find(TAG_LOC), strlen(TAG_LOC), "EN");
|
|
|
|
|
|
|
|
if(url.find(TAG_CONSOLE) != url.npos)
|
|
|
|
url.replace(url.find(TAG_CONSOLE), strlen(TAG_CONSOLE), (Plugins[Plugin_Pos].consoleCoverID.size() ? Plugins[Plugin_Pos].consoleCoverID.c_str() : "nintendo"));
|
|
|
|
|
2012-06-17 13:01:43 +02:00
|
|
|
char gamePath[256];
|
|
|
|
if(string(gameHeader.path).find_last_of("/") != string::npos)
|
2012-06-17 13:23:55 +02:00
|
|
|
strncpy(gamePath, &gameHeader.path[string(gameHeader.path).find_last_of("/")+1], sizeof(gamePath));
|
2012-06-17 13:01:43 +02:00
|
|
|
else
|
|
|
|
strncpy(gamePath, gameHeader.path, sizeof(gamePath));
|
2012-10-04 16:35:08 +02:00
|
|
|
const string& cachedCRC = Checksums.getString("CHECKSUMS", gamePath);
|
2012-06-08 21:29:23 +02:00
|
|
|
char crc_string[9];
|
2012-10-04 16:35:08 +02:00
|
|
|
memset(crc_string, 0, sizeof(crc_string));
|
|
|
|
if(cachedCRC.size() > 1)
|
2012-06-17 13:01:43 +02:00
|
|
|
{
|
2012-06-17 13:12:07 +02:00
|
|
|
gprintf("CRC32 of %s is cached\n", gamePath);
|
2012-10-04 16:35:08 +02:00
|
|
|
strncpy(crc_string, cachedCRC.c_str(), 8);
|
2012-06-17 13:01:43 +02:00
|
|
|
}
|
2012-06-08 23:25:54 +02:00
|
|
|
else
|
|
|
|
{
|
2012-06-17 13:12:07 +02:00
|
|
|
gprintf("Generating CRC32 for %s\n", gamePath);
|
2012-06-17 15:34:20 +02:00
|
|
|
u32 buffer;
|
|
|
|
ifstream infile;
|
|
|
|
if(strstr(gameHeader.path, ".zip") != NULL)
|
2012-06-17 13:12:07 +02:00
|
|
|
{
|
2012-06-17 15:34:20 +02:00
|
|
|
infile.open(gameHeader.path, ios::binary);
|
|
|
|
infile.seekg(0x0e, ios::beg);
|
|
|
|
infile.read((char*)&buffer, 8);
|
|
|
|
infile.close();
|
2012-10-04 16:35:08 +02:00
|
|
|
strncpy(crc_string, fmt("%08x", (u32)__builtin_bswap32(buffer)), 8);
|
2012-06-17 13:12:07 +02:00
|
|
|
}
|
2012-06-17 15:34:20 +02:00
|
|
|
else if(strstr(gameHeader.path, ".7z") != NULL)
|
2012-06-17 13:12:07 +02:00
|
|
|
{
|
|
|
|
infile.open(gameHeader.path, ios::binary);
|
2012-06-17 15:34:20 +02:00
|
|
|
infile.seekg(-8, ios::end);
|
|
|
|
while(infile.tellg())
|
|
|
|
{
|
|
|
|
infile.read((char*)&buffer, 8);
|
|
|
|
if(buffer == 0x00050111)
|
|
|
|
break;
|
|
|
|
infile.seekg(-9, ios::cur);
|
|
|
|
}
|
|
|
|
infile.seekg(-13, ios::cur);
|
|
|
|
infile.read((char*)&buffer, 8);
|
2012-06-17 13:12:07 +02:00
|
|
|
infile.close();
|
2012-10-04 16:35:08 +02:00
|
|
|
strncpy(crc_string, fmt("%08x", (u32)__builtin_bswap32(buffer)), 8);
|
2012-06-17 13:12:07 +02:00
|
|
|
}
|
2012-06-17 15:34:20 +02:00
|
|
|
else
|
2012-10-04 16:35:08 +02:00
|
|
|
strncpy(crc_string, fmt("%08x", crc32file(gameHeader.path)), 8);
|
2012-06-17 15:34:20 +02:00
|
|
|
Checksums.setString("CHECKSUMS", gamePath, crc_string);
|
|
|
|
Checksums.save();
|
2012-06-08 23:25:54 +02:00
|
|
|
}
|
2012-06-08 21:29:23 +02:00
|
|
|
url.replace(url.find(TAG_GAME_ID), strlen(TAG_GAME_ID), upperCase(crc_string).c_str());
|
|
|
|
gprintf("URL: %s\n", url.c_str());
|
|
|
|
return url;
|
|
|
|
}
|