diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj
index b969d9d142..141b797be7 100644
--- a/Source/Core/Core/Core.vcxproj
+++ b/Source/Core/Core/Core.vcxproj
@@ -203,7 +203,7 @@
-
+
@@ -408,7 +408,7 @@
-
+
diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters
index 185642dc3e..7d498e2f03 100644
--- a/Source/Core/Core/Core.vcxproj.filters
+++ b/Source/Core/Core/Core.vcxproj.filters
@@ -559,7 +559,7 @@
HW %28Flipper/Hollywood%29\GCMemcard
-
+
Boot
@@ -1045,7 +1045,7 @@
IPC HLE %28IOS/Starlet%29\Net
-
+
Boot
diff --git a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp
index 0353351cc1..45a010d13a 100644
--- a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp
+++ b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp
@@ -1,429 +1,445 @@
-// Copyright (C) 2003 Dolphin Project.
-
-// 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, version 2.0.
-
-// 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 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
-
-#include "Common.h"
-#include "CommonPaths.h"
-#include "FileUtil.h"
-#include "NandPaths.h"
-
-#include "../PowerPC/PowerPC.h"
-#include "../Core.h"
-#include "../HW/EXI_DeviceIPL.h"
-#include "../HW/Memmap.h"
-#include "../HW/DVDInterface.h"
-#include "../HW/CPU.h"
-
-#include "../Host.h"
-#include "../VolumeHandler.h"
-#include "../PatchEngine.h"
-#include "../MemTools.h"
-
-#include "../ConfigManager.h"
-#include "VolumeCreator.h"
-#include "Boot.h"
-#include "HLE/HLE.h"
-#include "SettingsGenerator.h"
-
-void CBoot::RunFunction(u32 _iAddr)
-{
- PC = _iAddr;
- LR = 0x00;
-
- while (PC != 0x00)
- PowerPC::SingleStep();
-}
-
-// __________________________________________________________________________________________________
-// GameCube Bootstrap 2 HLE:
-// copy the apploader to 0x81200000
-// execute the apploader, function by function, using the above utility.
-bool CBoot::EmulatedBS2_GC()
-{
- INFO_LOG(BOOT, "Faking GC BS2...");
-
- UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
- m_MSR.FP = 1;
-
- // Clear ALL memory
- Memory::Clear();
-
- // Write necessary values
- // Here we write values to memory that the apploader does not take care of. Game info goes
- // to 0x80000000 according to yagcd 4.2.
- DVDInterface::DVDRead(0x00000000, 0x80000000, 0x20); // write disc info
-
- Memory::Write_U32(0x0D15EA5E, 0x80000020); // booted from bootrom. 0xE5207C22 = booted from jtag
- Memory::Write_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail)
- // TODO determine why some games fail when using a retail id. (Seem to take different EXI paths, see ikaruga for example)
- Memory::Write_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see yagcd 4.2.1.1.2
-
- Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC
- ? 0 : 1, 0x800000CC); // fake the VI Init of the IPL (yagcd 4.2.1.4)
-
- Memory::Write_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external (retail consoles have no external ARAM)
-
- Memory::Write_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed
- Memory::Write_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed
-
- Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
- Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
- Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
-
- Memory::Write_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, 0x800030D8); // preset time base ticks
- // HIO checks this
- //Memory::Write_U16(0x8200, 0x000030e6); // Console type
-
- HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
-
- // Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc,
- // but the size can differ between discs. Compare with yagcd chap 13.
- u32 iAppLoaderOffset = 0x2440;
- u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
- u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14) + VolumeHandler::Read32(iAppLoaderOffset + 0x18);
- if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
- {
- INFO_LOG(BOOT, "GC BS2: Not running apploader!");
- return false;
- }
- VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
-
- // Setup pointers like real BS2 does
- if (SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC)
- {
- PowerPC::ppcState.gpr[1] = 0x81566550; // StackPointer, used to be set to 0x816ffff0
- PowerPC::ppcState.gpr[2] = 0x81465cc0; // global pointer to Small Data Area 2 Base (haven't seen anything use it...meh)
- PowerPC::ppcState.gpr[13] = 0x81465320; // global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it)
- }
- else
- {
- PowerPC::ppcState.gpr[1] = 0x815edca8;
- PowerPC::ppcState.gpr[2] = 0x814b5b20;
- PowerPC::ppcState.gpr[13] = 0x814b4fc0;
- }
-
- // TODO - Make Apploader(or just RunFunction()) debuggable!!!
-
- // Call iAppLoaderEntry.
- DEBUG_LOG(MASTER_LOG, "Call iAppLoaderEntry");
- u32 iAppLoaderFuncAddr = 0x80003100;
- PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
- PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
- PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
- RunFunction(iAppLoaderEntry);
- u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 0);
- u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 4);
- u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 8);
-
- // iAppLoaderInit
- DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit");
- PowerPC::ppcState.gpr[3] = 0x81300000;
- RunFunction(iAppLoaderInit);
-
- // iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem).
- // To give you an idea about where the stuff is located on the disc take a look at yagcd
- // ch 13.
- DEBUG_LOG(MASTER_LOG, "Call iAppLoaderMain");
- do
- {
- PowerPC::ppcState.gpr[3] = 0x81300004;
- PowerPC::ppcState.gpr[4] = 0x81300008;
- PowerPC::ppcState.gpr[5] = 0x8130000c;
-
- RunFunction(iAppLoaderMain);
-
- u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
- u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
- u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c);
-
- INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
- DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
-
- } while(PowerPC::ppcState.gpr[3] != 0x00);
-
- // iAppLoaderClose
- DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose");
- RunFunction(iAppLoaderClose);
-
- // return
- PC = PowerPC::ppcState.gpr[3];
-
- // Load patches
- std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
- PatchEngine::LoadPatches(gameID.c_str());
-
- PowerPC::ppcState.DebugCount = 0;
-
- // If we have any patches that need to be applied very early, here's a good place
- PatchEngine::ApplyFramePatches();
-
- return true;
-}
-
-bool CBoot::SetupWiiMemory(unsigned int _CountryCode)
-{
- INFO_LOG(BOOT, "Setup Wii Memory...");
-
- // Write the 256 byte setting.txt to memory. This may not be needed as
- // most or all games read the setting.txt file from
- // \title\00000001\00000002\data\setting.txt directly after the read the
- // SYSCONF file. The games also read it to 0x3800, what is a little strange
- // however is that it only reads the first 100 bytes of it.
- std::string settings_Filename(Common::GetTitleDataPath(TITLEID_SYSMENU) + WII_SETTING);
- std::string area, model, code, video, game;
-
-
- switch((DiscIO::IVolume::ECountry)_CountryCode)
- {
- case DiscIO::IVolume::COUNTRY_KOREA:
- case DiscIO::IVolume::COUNTRY_TAIWAN:
- // TODO: Determine if Korea / Taiwan have their own specific settings.
- case DiscIO::IVolume::COUNTRY_JAPAN:
- area = "JPN";
- video = "NTSC";
- break;
-
- case DiscIO::IVolume::COUNTRY_USA:
- area = "USA";
- video = "NTSC";
- break;
-
- case DiscIO::IVolume::COUNTRY_EUROPE:
- area = "EUR";
- video = "PAL";
- break;
-
- default:
- // PanicAlertT("SetupWiiMem: Unknown country. Wii boot process will be switched to European settings.");
- area = "EUR";
- video = "PAL";
- break;
- }
-
- model = "RVL-001(" + area + ")";
- code = "L" + area.substr(0,1);
- game = area.substr(0,2);
-
- SettingsGenerator gen;
+// Copyright (C) 2003 Dolphin Project.
+
+// 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, version 2.0.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "Common.h"
+#include "CommonPaths.h"
+#include "FileUtil.h"
+#include "NandPaths.h"
+
+#include "../PowerPC/PowerPC.h"
+#include "../Core.h"
+#include "../HW/EXI_DeviceIPL.h"
+#include "../HW/Memmap.h"
+#include "../HW/DVDInterface.h"
+#include "../HW/CPU.h"
+
+#include "../Host.h"
+#include "../VolumeHandler.h"
+#include "../PatchEngine.h"
+#include "../MemTools.h"
+
+#include "../ConfigManager.h"
+#include "VolumeCreator.h"
+#include "Boot.h"
+#include "HLE/HLE.h"
+#include "SettingsHandler.h"
+
+void CBoot::RunFunction(u32 _iAddr)
+{
+ PC = _iAddr;
+ LR = 0x00;
+
+ while (PC != 0x00)
+ PowerPC::SingleStep();
+}
+
+// __________________________________________________________________________________________________
+// GameCube Bootstrap 2 HLE:
+// copy the apploader to 0x81200000
+// execute the apploader, function by function, using the above utility.
+bool CBoot::EmulatedBS2_GC()
+{
+ INFO_LOG(BOOT, "Faking GC BS2...");
+
+ UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
+ m_MSR.FP = 1;
+
+ // Clear ALL memory
+ Memory::Clear();
+
+ // Write necessary values
+ // Here we write values to memory that the apploader does not take care of. Game info goes
+ // to 0x80000000 according to yagcd 4.2.
+ DVDInterface::DVDRead(0x00000000, 0x80000000, 0x20); // write disc info
+
+ Memory::Write_U32(0x0D15EA5E, 0x80000020); // booted from bootrom. 0xE5207C22 = booted from jtag
+ Memory::Write_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail)
+ // TODO determine why some games fail when using a retail id. (Seem to take different EXI paths, see ikaruga for example)
+ Memory::Write_U32(0x10000006, 0x8000002C); // Console type - DevKit (retail ID == 0x00000003) see yagcd 4.2.1.1.2
+
+ Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC
+ ? 0 : 1, 0x800000CC); // fake the VI Init of the IPL (yagcd 4.2.1.4)
+
+ Memory::Write_U32(0x01000000, 0x800000d0); // ARAM Size. 16MB main + 4/16/32MB external (retail consoles have no external ARAM)
+
+ Memory::Write_U32(0x09a7ec80, 0x800000F8); // Bus Clock Speed
+ Memory::Write_U32(0x1cf7c580, 0x800000FC); // CPU Clock Speed
+
+ Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
+ Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
+ Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
+
+ Memory::Write_U64((u64)CEXIIPL::GetGCTime() * (u64)40500000, 0x800030D8); // preset time base ticks
+ // HIO checks this
+ //Memory::Write_U16(0x8200, 0x000030e6); // Console type
+
+ HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
+
+ // Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc,
+ // but the size can differ between discs. Compare with yagcd chap 13.
+ u32 iAppLoaderOffset = 0x2440;
+ u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
+ u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14) + VolumeHandler::Read32(iAppLoaderOffset + 0x18);
+ if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
+ {
+ INFO_LOG(BOOT, "GC BS2: Not running apploader!");
+ return false;
+ }
+ VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
+
+ // Setup pointers like real BS2 does
+ if (SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC)
+ {
+ PowerPC::ppcState.gpr[1] = 0x81566550; // StackPointer, used to be set to 0x816ffff0
+ PowerPC::ppcState.gpr[2] = 0x81465cc0; // global pointer to Small Data Area 2 Base (haven't seen anything use it...meh)
+ PowerPC::ppcState.gpr[13] = 0x81465320; // global pointer to Small Data Area Base (Luigi's Mansion's apploader uses it)
+ }
+ else
+ {
+ PowerPC::ppcState.gpr[1] = 0x815edca8;
+ PowerPC::ppcState.gpr[2] = 0x814b5b20;
+ PowerPC::ppcState.gpr[13] = 0x814b4fc0;
+ }
+
+ // TODO - Make Apploader(or just RunFunction()) debuggable!!!
+
+ // Call iAppLoaderEntry.
+ DEBUG_LOG(MASTER_LOG, "Call iAppLoaderEntry");
+ u32 iAppLoaderFuncAddr = 0x80003100;
+ PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
+ PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
+ PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
+ RunFunction(iAppLoaderEntry);
+ u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 0);
+ u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 4);
+ u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr + 8);
+
+ // iAppLoaderInit
+ DEBUG_LOG(MASTER_LOG, "Call iAppLoaderInit");
+ PowerPC::ppcState.gpr[3] = 0x81300000;
+ RunFunction(iAppLoaderInit);
+
+ // iAppLoaderMain - Here we load the apploader, the DOL (the exe) and the FST (filesystem).
+ // To give you an idea about where the stuff is located on the disc take a look at yagcd
+ // ch 13.
+ DEBUG_LOG(MASTER_LOG, "Call iAppLoaderMain");
+ do
+ {
+ PowerPC::ppcState.gpr[3] = 0x81300004;
+ PowerPC::ppcState.gpr[4] = 0x81300008;
+ PowerPC::ppcState.gpr[5] = 0x8130000c;
+
+ RunFunction(iAppLoaderMain);
+
+ u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
+ u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
+ u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c);
+
+ INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
+ DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
+
+ } while(PowerPC::ppcState.gpr[3] != 0x00);
+
+ // iAppLoaderClose
+ DEBUG_LOG(MASTER_LOG, "call iAppLoaderClose");
+ RunFunction(iAppLoaderClose);
+
+ // return
+ PC = PowerPC::ppcState.gpr[3];
+
+ // Load patches
+ std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
+ PatchEngine::LoadPatches(gameID.c_str());
+
+ PowerPC::ppcState.DebugCount = 0;
+
+ // If we have any patches that need to be applied very early, here's a good place
+ PatchEngine::ApplyFramePatches();
+
+ return true;
+}
+
+bool CBoot::SetupWiiMemory(unsigned int _CountryCode)
+{
+ INFO_LOG(BOOT, "Setup Wii Memory...");
+
+ // Write the 256 byte setting.txt to memory. This may not be needed as
+ // most or all games read the setting.txt file from
+ // \title\00000001\00000002\data\setting.txt directly after the read the
+ // SYSCONF file. The games also read it to 0x3800, what is a little strange
+ // however is that it only reads the first 100 bytes of it.
+ std::string settings_Filename(Common::GetTitleDataPath(TITLEID_SYSMENU) + WII_SETTING);
+ std::string area, model, code, video, game;
+
+
+ switch((DiscIO::IVolume::ECountry)_CountryCode)
+ {
+ case DiscIO::IVolume::COUNTRY_KOREA:
+ case DiscIO::IVolume::COUNTRY_TAIWAN:
+ // TODO: Determine if Korea / Taiwan have their own specific settings.
+ case DiscIO::IVolume::COUNTRY_JAPAN:
+ area = "JPN";
+ video = "NTSC";
+ break;
+
+ case DiscIO::IVolume::COUNTRY_USA:
+ area = "USA";
+ video = "NTSC";
+ break;
+
+ case DiscIO::IVolume::COUNTRY_EUROPE:
+ area = "EUR";
+ video = "PAL";
+ break;
+
+ default:
+ // PanicAlertT("SetupWiiMem: Unknown country. Wii boot process will be switched to European settings.");
+ area = "EUR";
+ video = "PAL";
+ break;
+ }
+
+ model = "RVL-001(" + area + ")";
+ code = "L" + area.substr(0,1);
+ game = area.substr(0,2);
+
+
+ SettingsHandler gen;
+ std::string serno = "";
+ if (File::Exists(settings_Filename))
+ {
+ File::IOFile settingsFileHandle(settings_Filename, "rb");
+ if(settingsFileHandle.ReadBytes((void*)gen.GetData(), SETTINGS_SIZE)){
+ gen.Decrypt();
+ serno = gen.GetValue("SERNO");
+ gen.Reset();
+ }
+ File::Delete(settings_Filename);
+ }
+
+ if(serno.empty() || serno == "000000000"){
+ serno = gen.generateSerialNumber();
+ INFO_LOG(BOOT, "No previous serial number found, generated one instead: %s", serno.c_str());
+ }else{
+ INFO_LOG(BOOT, "Using serial number: %s", serno.c_str());
+ }
+
gen.AddSetting("AREA", area.c_str());
gen.AddSetting("MODEL", model.c_str());
gen.AddSetting("DVD", "0");
gen.AddSetting("MPCH", "0x7FFE");
gen.AddSetting("CODE", code.c_str());
- gen.AddSetting("SERNO", "000000000");
+ gen.AddSetting("SERNO", serno.c_str());
gen.AddSetting("VIDEO", video.c_str());
- gen.AddSetting("GAME", game.c_str());
-
-
- if (File::Exists(settings_Filename))
- {
- File::Delete(settings_Filename);
- }
- File::CreateFullPath(settings_Filename);
-
- {
- File::IOFile settingsFileHandle(settings_Filename, "wb");
-
- if (!settingsFileHandle.WriteBytes(gen.GetData(), SETTINGS_SIZE))
- {
- PanicAlertT("SetupWiiMem: Cant create setting file");
- return false;
- }
- Memory::WriteBigEData(gen.GetData(), 0x3800, SETTINGS_SIZE);
- }
-
- /*
- Set hardcoded global variables to Wii memory. These are partly collected from
- Wiibrew. These values are needed for the games to function correctly. A few
- values in this region will also be placed here by the game as it boots.
- They are:
- 0x80000038 Start of FST
- 0x8000003c Size of FST Size
- 0x80000060 Copyright code
- */
-
- DVDInterface::DVDRead(0x00000000, 0x00000000, 0x20); // Game Code
- Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
- Memory::Write_U32(0x00000001, 0x00000024); // Unknown
- Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB
- Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model
- Memory::Write_U32(0x00000000, 0x00000030); // Init
- Memory::Write_U32(0x817FEC60, 0x00000034); // Init
- // 38, 3C should get start, size of FST through apploader
- Memory::Write_U32(0x38a00040, 0x00000060); // Exception init
- Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
- Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?)
- Memory::Write_U32(0x8179b500, 0x000000f4); // __start
- Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
- Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
- Memory::Write_U16(0x0000, 0x000030e6); // Console type
- Memory::Write_U32(0x00000000, 0x000030c0); // EXI
- Memory::Write_U32(0x00000000, 0x000030c4); // EXI
- Memory::Write_U32(0x00000000, 0x000030dc); // Time
- Memory::Write_U32(0x00000000, 0x000030d8); // Time
- Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
- Memory::Write_U32(0x01800000, 0x00003100); // BAT
- Memory::Write_U32(0x01800000, 0x00003104); // BAT
- Memory::Write_U32(0x00000000, 0x0000310c); // Init
- Memory::Write_U32(0x8179d500, 0x00003110); // Init
- Memory::Write_U32(0x04000000, 0x00003118); // Unknown
- Memory::Write_U32(0x04000000, 0x0000311c); // BAT
- Memory::Write_U32(0x93400000, 0x00003120); // BAT
- Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low
- Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high
- Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low
- Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high
- Memory::Write_U32(0x00000011, 0x00003138); // Console type
- // 40 is copied from 88 after running apploader
- Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4)
- Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007)
- Memory::Write_U16(0x0113, 0x0000315e); // Apploader
- Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code
- Memory::Write_U32(0x00000000, 0x00003160); // Init semaphore (sysmenu waits for this to clear)
- Memory::Write_U32(0x00090204, 0x00003188); // Expected IOS revision
-
- Memory::Write_U8(0x80, 0x0000315c); // OSInit
- Memory::Write_U16(0x0000, 0x000030e0); // PADInit
- Memory::Write_U32(0x80000000, 0x00003184); // GameID Address
-
- // Fake the VI Init of the IPL
- Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC ? 0 : 1, 0x000000CC);
-
- // Clear exception handler. Why? Don't we begin with only zeros?
- for (int i = 0x3000; i <= 0x3038; i += 4)
- {
- Memory::Write_U32(0x00000000, 0x80000000 + i);
- }
- return true;
-}
-
-// __________________________________________________________________________________________________
-// Wii Bootstrap 2 HLE:
-// copy the apploader to 0x81200000
-// execute the apploader
-bool CBoot::EmulatedBS2_Wii()
-{
- INFO_LOG(BOOT, "Faking Wii BS2...");
-
- // setup wii memory
- DiscIO::IVolume::ECountry CountryCode = DiscIO::IVolume::COUNTRY_UNKNOWN;
- if (VolumeHandler::IsValid())
- CountryCode = VolumeHandler::GetVolume()->GetCountry();
- if (SetupWiiMemory(CountryCode) == false)
- return false;
-
- // This is some kind of consistency check that is compared to the 0x00
- // values as the game boots. This location keep the 4 byte ID for as long
- // as the game is running. The 6 byte ID at 0x00 is overwritten sometime
- // after this check during booting.
- VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4);
-
- // Execute the apploader
- bool apploaderRan = false;
- if (VolumeHandler::IsValid() && VolumeHandler::IsWii())
- {
- UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
- m_MSR.FP = 1;
-
- Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
- Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
- Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
-
- HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
-
- PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
-
- u32 iAppLoaderOffset = 0x2440; // 0x1c40;
-
- // Load Apploader to Memory
- u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
- u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
- if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
- {
- ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
- return false;
- }
- VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
-
- //call iAppLoaderEntry
- DEBUG_LOG(BOOT, "Call iAppLoaderEntry");
-
- u32 iAppLoaderFuncAddr = 0x80004000;
- PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
- PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
- PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
- RunFunction(iAppLoaderEntry);
- u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
- u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
- u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
-
- // iAppLoaderInit
- DEBUG_LOG(BOOT, "Run iAppLoaderInit");
- PowerPC::ppcState.gpr[3] = 0x81300000;
- RunFunction(iAppLoaderInit);
-
- // Let the apploader load the exe to memory. At this point I get an unknown IPC command
- // (command zero) when I load Wii Sports or other games a second time. I don't notice
- // any side effects however. It's a little disconcerting however that Start after Stop
- // behaves differently than the first Start after starting Dolphin. It means something
- // was not reset correctly.
- DEBUG_LOG(BOOT, "Run iAppLoaderMain");
- do
- {
- PowerPC::ppcState.gpr[3] = 0x81300004;
- PowerPC::ppcState.gpr[4] = 0x81300008;
- PowerPC::ppcState.gpr[5] = 0x8130000c;
-
- RunFunction(iAppLoaderMain);
-
- u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
- u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
- u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2;
-
- INFO_LOG(BOOT, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength);
- DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
- } while(PowerPC::ppcState.gpr[3] != 0x00);
-
- // iAppLoaderClose
- DEBUG_LOG(BOOT, "Run iAppLoaderClose");
- RunFunction(iAppLoaderClose);
-
- apploaderRan = true;
-
- // Pass the "#002 check"
- // Apploader writes the IOS version and revision here, we copy it
- // Fake IOSv9 r2.4 if no version is found (elf loading)
- u32 firmwareVer = Memory::Read_U32(0x80003188);
- Memory::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x00003140);
-
- // Load patches and run startup patches
- std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
- PatchEngine::LoadPatches(gameID.c_str());
-
- // return
- PC = PowerPC::ppcState.gpr[3];
- }
-
- PowerPC::ppcState.DebugCount = 0;
-
- return apploaderRan;
-}
-
-// Returns true if apploader has run successfully
-bool CBoot::EmulatedBS2(bool _bIsWii)
-{
- return _bIsWii ? EmulatedBS2_Wii() : EmulatedBS2_GC();
-}
+ gen.AddSetting("GAME", game.c_str());
+
+
+ File::CreateFullPath(settings_Filename);
+
+ {
+ File::IOFile settingsFileHandle(settings_Filename, "wb");
+
+ if (!settingsFileHandle.WriteBytes(gen.GetData(), SETTINGS_SIZE))
+ {
+ PanicAlertT("SetupWiiMem: Cant create setting file");
+ return false;
+ }
+ Memory::WriteBigEData(gen.GetData(), 0x3800, SETTINGS_SIZE);
+ }
+
+ /*
+ Set hardcoded global variables to Wii memory. These are partly collected from
+ Wiibrew. These values are needed for the games to function correctly. A few
+ values in this region will also be placed here by the game as it boots.
+ They are:
+ 0x80000038 Start of FST
+ 0x8000003c Size of FST Size
+ 0x80000060 Copyright code
+ */
+
+ DVDInterface::DVDRead(0x00000000, 0x00000000, 0x20); // Game Code
+ Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
+ Memory::Write_U32(0x00000001, 0x00000024); // Unknown
+ Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB
+ Memory::Write_U32(0x00000023, 0x0000002c); // Production Board Model
+ Memory::Write_U32(0x00000000, 0x00000030); // Init
+ Memory::Write_U32(0x817FEC60, 0x00000034); // Init
+ // 38, 3C should get start, size of FST through apploader
+ Memory::Write_U32(0x38a00040, 0x00000060); // Exception init
+ Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
+ Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?)
+ Memory::Write_U32(0x8179b500, 0x000000f4); // __start
+ Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
+ Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
+ Memory::Write_U16(0x0000, 0x000030e6); // Console type
+ Memory::Write_U32(0x00000000, 0x000030c0); // EXI
+ Memory::Write_U32(0x00000000, 0x000030c4); // EXI
+ Memory::Write_U32(0x00000000, 0x000030dc); // Time
+ Memory::Write_U32(0x00000000, 0x000030d8); // Time
+ Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
+ Memory::Write_U32(0x01800000, 0x00003100); // BAT
+ Memory::Write_U32(0x01800000, 0x00003104); // BAT
+ Memory::Write_U32(0x00000000, 0x0000310c); // Init
+ Memory::Write_U32(0x8179d500, 0x00003110); // Init
+ Memory::Write_U32(0x04000000, 0x00003118); // Unknown
+ Memory::Write_U32(0x04000000, 0x0000311c); // BAT
+ Memory::Write_U32(0x93400000, 0x00003120); // BAT
+ Memory::Write_U32(0x90000800, 0x00003124); // Init - MEM2 low
+ Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high
+ Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low
+ Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high
+ Memory::Write_U32(0x00000011, 0x00003138); // Console type
+ // 40 is copied from 88 after running apploader
+ Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4)
+ Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007)
+ Memory::Write_U16(0x0113, 0x0000315e); // Apploader
+ Memory::Write_U32(0x0000FF16, 0x00003158); // DDR ram vendor code
+ Memory::Write_U32(0x00000000, 0x00003160); // Init semaphore (sysmenu waits for this to clear)
+ Memory::Write_U32(0x00090204, 0x00003188); // Expected IOS revision
+
+ Memory::Write_U8(0x80, 0x0000315c); // OSInit
+ Memory::Write_U16(0x0000, 0x000030e0); // PADInit
+ Memory::Write_U32(0x80000000, 0x00003184); // GameID Address
+
+ // Fake the VI Init of the IPL
+ Memory::Write_U32(SConfig::GetInstance().m_LocalCoreStartupParameter.bNTSC ? 0 : 1, 0x000000CC);
+
+ // Clear exception handler. Why? Don't we begin with only zeros?
+ for (int i = 0x3000; i <= 0x3038; i += 4)
+ {
+ Memory::Write_U32(0x00000000, 0x80000000 + i);
+ }
+ return true;
+}
+
+// __________________________________________________________________________________________________
+// Wii Bootstrap 2 HLE:
+// copy the apploader to 0x81200000
+// execute the apploader
+bool CBoot::EmulatedBS2_Wii()
+{
+ INFO_LOG(BOOT, "Faking Wii BS2...");
+
+ // setup wii memory
+ DiscIO::IVolume::ECountry CountryCode = DiscIO::IVolume::COUNTRY_UNKNOWN;
+ if (VolumeHandler::IsValid())
+ CountryCode = VolumeHandler::GetVolume()->GetCountry();
+ if (SetupWiiMemory(CountryCode) == false)
+ return false;
+
+ // This is some kind of consistency check that is compared to the 0x00
+ // values as the game boots. This location keep the 4 byte ID for as long
+ // as the game is running. The 6 byte ID at 0x00 is overwritten sometime
+ // after this check during booting.
+ VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4);
+
+ // Execute the apploader
+ bool apploaderRan = false;
+ if (VolumeHandler::IsValid() && VolumeHandler::IsWii())
+ {
+ UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
+ m_MSR.FP = 1;
+
+ Memory::Write_U32(0x4c000064, 0x80000300); // write default DFI Handler: rfi
+ Memory::Write_U32(0x4c000064, 0x80000800); // write default FPU Handler: rfi
+ Memory::Write_U32(0x4c000064, 0x80000C00); // write default Syscall Handler: rfi
+
+ HLE::Patch(0x81300000, "OSReport"); // HLE OSReport for Apploader
+
+ PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer
+
+ u32 iAppLoaderOffset = 0x2440; // 0x1c40;
+
+ // Load Apploader to Memory
+ u32 iAppLoaderEntry = VolumeHandler::Read32(iAppLoaderOffset + 0x10);
+ u32 iAppLoaderSize = VolumeHandler::Read32(iAppLoaderOffset + 0x14);
+ if ((iAppLoaderEntry == (u32)-1) || (iAppLoaderSize == (u32)-1))
+ {
+ ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
+ return false;
+ }
+ VolumeHandler::ReadToPtr(Memory::GetPointer(0x81200000), iAppLoaderOffset + 0x20, iAppLoaderSize);
+
+ //call iAppLoaderEntry
+ DEBUG_LOG(BOOT, "Call iAppLoaderEntry");
+
+ u32 iAppLoaderFuncAddr = 0x80004000;
+ PowerPC::ppcState.gpr[3] = iAppLoaderFuncAddr + 0;
+ PowerPC::ppcState.gpr[4] = iAppLoaderFuncAddr + 4;
+ PowerPC::ppcState.gpr[5] = iAppLoaderFuncAddr + 8;
+ RunFunction(iAppLoaderEntry);
+ u32 iAppLoaderInit = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+0);
+ u32 iAppLoaderMain = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+4);
+ u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
+
+ // iAppLoaderInit
+ DEBUG_LOG(BOOT, "Run iAppLoaderInit");
+ PowerPC::ppcState.gpr[3] = 0x81300000;
+ RunFunction(iAppLoaderInit);
+
+ // Let the apploader load the exe to memory. At this point I get an unknown IPC command
+ // (command zero) when I load Wii Sports or other games a second time. I don't notice
+ // any side effects however. It's a little disconcerting however that Start after Stop
+ // behaves differently than the first Start after starting Dolphin. It means something
+ // was not reset correctly.
+ DEBUG_LOG(BOOT, "Run iAppLoaderMain");
+ do
+ {
+ PowerPC::ppcState.gpr[3] = 0x81300004;
+ PowerPC::ppcState.gpr[4] = 0x81300008;
+ PowerPC::ppcState.gpr[5] = 0x8130000c;
+
+ RunFunction(iAppLoaderMain);
+
+ u32 iRamAddress = Memory::ReadUnchecked_U32(0x81300004);
+ u32 iLength = Memory::ReadUnchecked_U32(0x81300008);
+ u32 iDVDOffset = Memory::ReadUnchecked_U32(0x8130000c) << 2;
+
+ INFO_LOG(BOOT, "DVDRead: offset: %08x memOffse: %08x length: %i", iDVDOffset, iRamAddress, iLength);
+ DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength);
+ } while(PowerPC::ppcState.gpr[3] != 0x00);
+
+ // iAppLoaderClose
+ DEBUG_LOG(BOOT, "Run iAppLoaderClose");
+ RunFunction(iAppLoaderClose);
+
+ apploaderRan = true;
+
+ // Pass the "#002 check"
+ // Apploader writes the IOS version and revision here, we copy it
+ // Fake IOSv9 r2.4 if no version is found (elf loading)
+ u32 firmwareVer = Memory::Read_U32(0x80003188);
+ Memory::Write_U32(firmwareVer ? firmwareVer : 0x00090204, 0x00003140);
+
+ // Load patches and run startup patches
+ std::string gameID = VolumeHandler::GetVolume()->GetUniqueID();
+ PatchEngine::LoadPatches(gameID.c_str());
+
+ // return
+ PC = PowerPC::ppcState.gpr[3];
+ }
+
+ PowerPC::ppcState.DebugCount = 0;
+
+ return apploaderRan;
+}
+
+// Returns true if apploader has run successfully
+bool CBoot::EmulatedBS2(bool _bIsWii)
+{
+ return _bIsWii ? EmulatedBS2_Wii() : EmulatedBS2_GC();
+}
diff --git a/Source/Core/Core/Src/Boot/SettingsHandler.cpp b/Source/Core/Core/Src/Boot/SettingsHandler.cpp
new file mode 100644
index 0000000000..9d115e373d
--- /dev/null
+++ b/Source/Core/Core/Src/Boot/SettingsHandler.cpp
@@ -0,0 +1,136 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// 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, version 2.0.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+// Thanks to Treeki for writing the original class - 29/01/2012
+
+#include "Common.h"
+#include "CommonPaths.h"
+#include "Timer.h"
+#include "SettingsHandler.h"
+
+#include
+
+#ifdef _WIN32
+#include
+#include
+#include
+#else
+#include
+#endif
+
+SettingsHandler::SettingsHandler()
+{
+ Reset();
+}
+
+const u8* SettingsHandler::GetData() const
+{
+ return m_buffer;
+}
+
+const std::string SettingsHandler::GetValue(std::string key)
+{
+ std::string delim = std::string("\r\n");
+ std::string toFind = delim + key + "=";
+ size_t found = decoded.find(toFind);
+ if (found!=std::string::npos){
+ size_t delimFound = decoded.find(delim, found+toFind.length());
+ if (delimFound == std::string::npos)
+ delimFound = decoded.length()-1;
+ return decoded.substr(found+toFind.length(), delimFound - (found+toFind.length()));
+ }else{
+ toFind = key + "=";
+ size_t found = decoded.find(toFind);
+ if (found==0){
+ size_t delimFound = decoded.find(delim, found+toFind.length());
+ if (delimFound == std::string::npos)
+ delimFound = decoded.length()-1;
+ return decoded.substr(found+toFind.length(), delimFound - (found+toFind.length()));
+ }
+ }
+
+ return "";
+}
+
+
+void SettingsHandler::Decrypt()
+{
+ const u8 *str = m_buffer;
+ while(*str != 0){
+
+ if (m_position >= SETTINGS_SIZE)
+ return;
+ decoded.push_back((u8)(m_buffer[m_position] ^ m_key));
+ m_position++;
+ str++;
+ m_key = ((m_key >> 31) | (m_key << 1));
+ }
+}
+
+void SettingsHandler::Reset()
+{
+ decoded = "";
+ m_position = 0;
+ m_key = 0x73B5DBFA;
+ memset(m_buffer, 0, SETTINGS_SIZE);
+}
+
+void SettingsHandler::AddSetting(const char *key, const char *value)
+{
+ while (*key != 0)
+ {
+ WriteByte(*key);
+ key++;
+ }
+
+ WriteByte('=');
+
+ while (*value != 0)
+ {
+ WriteByte(*value);
+ value++;
+ }
+
+ WriteByte(13);
+ WriteByte(10);
+}
+
+void SettingsHandler::WriteByte(u8 b)
+{
+ if (m_position >= SETTINGS_SIZE)
+ return;
+
+ m_buffer[m_position] = b ^ m_key;
+ m_position++;
+ m_key = ((m_key >> 31) | (m_key << 1));
+}
+
+std::string SettingsHandler::generateSerialNumber()
+{
+ time_t rawtime;
+ struct tm * timeinfo;
+ char buffer [12];
+ char serialNumber [12];
+
+ time ( &rawtime );
+ timeinfo = localtime ( &rawtime );
+ strftime (buffer,11,"%j%H%M%S",timeinfo);
+
+ snprintf(serialNumber,11, "%s%i", buffer, (Common::Timer::GetTimeMs()>>1)&0xF);
+ serialNumber[10] = 0;
+ return std::string(serialNumber);
+}
\ No newline at end of file
diff --git a/Source/Core/Core/Src/Boot/SettingsHandler.h b/Source/Core/Core/Src/Boot/SettingsHandler.h
new file mode 100644
index 0000000000..55295ece17
--- /dev/null
+++ b/Source/Core/Core/Src/Boot/SettingsHandler.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// 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, version 2.0.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+// Thanks to Treeki for writing the original class - 29/01/2012
+
+#ifndef _SETTINGS_HANDLER_H
+#define _SETTINGS_HANDLER_H
+
+#include
+
+#include "Common.h"
+#include "../CoreParameter.h"
+#define SETTINGS_SIZE 0x100
+
+class SettingsHandler
+{
+public:
+ SettingsHandler();
+
+ void AddSetting(const char *key, const char *value);
+
+ const u8 *GetData() const;
+ const std::string GetValue(std::string key);
+
+ void Decrypt();
+ void Reset();
+ std::string generateSerialNumber();
+private:
+ void WriteByte(u8 b);
+
+ u8 m_buffer[SETTINGS_SIZE];
+ u32 m_position, m_key;
+ std::string decoded;
+};
+
+#endif