ctr_Repair/trunk/ConsoleDataMigration/sources/ConsoleRestore/Importer.cpp
N2614 0e74bf736e ヒープを共有しているのでスレッドごとに限界サイズまで確保しないように
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@319 385bec56-5757-e545-9c3a-d8741f4650f1
2011-06-06 12:11:36 +00:00

1863 lines
62 KiB
C++

/*---------------------------------------------------------------------------*
Project: Horizon
File: Importer.cpp
Copyright 2009 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Rev$
*---------------------------------------------------------------------------*/
#include <nn.h>
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/cfg/CTR/cfg_ApiInit.h>
#include <nn/cfg/CTR/cfg_ApiNor.h> // cfg:norの初期化に必要
#include <nn/cfg/CTR/cfg_Api.h>
#include <nn/am/am_ApiSystemMenu.h>
#include <nn/cfg/CTR/cfg_NtrSettings.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/cfg/CTR/detail/cfg_DataStructures.h>
#include <nn/cfg/CTR/detail/cfg_Keys.h>
#include <nn/cfg/CTR/detail/cfg_Default.h>
#include <nn/drivers/aes/CTR/ARM946ES/driverAes_Types.h>
#include <nn/crypto/crypto_SwAesCtrContext.h>
#include <nn/ac/CTR/private/ac_NetworkSetting.h>
#include <nn/ac/CTR/private/ac_InternalApi.h>
#include <nn/socket.h>
#include <nn/nwm/CTR/nwm_InfraAPI.h>
#include <nn/mcu.h>
#include <nn/drivers/mcu/CTR/driverMcuRegisterMap.h>
#include "FileName.h"
#include "Importer.h"
#include "SdMountManager.h"
#include "HeapManager.h"
#include "SdReaderWriter.h"
#include "CommonLogger.h"
#include "FileTransfer.h"
#include "common_Types.h"
#include "Aes_define.h"
#include "configLoader.h"
#include "PlayHistoryManager.h"
#include "FileChecker.h"
#include "VersionDetect.h"
#include <string>
#include <cstring>
namespace ConsoleRestore
{
namespace
{
const size_t IMPORT_THREAD_STACK_SIZE = 0x4000;
nn::os::Thread s_ImportThread;
nn::os::StackBuffer<IMPORT_THREAD_STACK_SIZE> s_ImportThreadStack;
const size_t TIME_ZONE_LENGTH = 9; // "+23:45"
char s_TimeZoneStr[TIME_ZONE_LENGTH];
TimeZone s_TimeZone;
const size_t NTP_SERVER_NAME_LENGTH = 256;
char s_NtpServerName[NTP_SERVER_NAME_LENGTH];
bool s_CheckedEqualsDeviceIdFileandDeviceId = false;
bool s_CheckedEqualsRegionDataandRegion = false;
bool s_ReadSerialNumber = false;
struct SdFileSize
{
s64 totalFileSize;
s64 twlFileSize;
s64 twlSoundFileSize;
s64 twlPhotoFileSize;
s64 ctrFileSize;
};
SdFileSize s_SdFileSize;
// シリアルナンバー
u8 s_SerialNo[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN];
// 空のファイルを作成する
bool CreateEmptyFile(const wchar_t* path);
// SDからNANDにセーブデータをコピーする
void ImportSaveData();
// SDからNORにNORデータをコピーする
nn::Result ImportNorData();
// SDカードに保存してあるバージョン情報
common::VerDef s_SDVersionData;
// SDカードから読み込んだファイル一覧
common::ImportDataList s_FileLists;
}
// SDからファイル一覧を読み込む
nn::Result ReadFileList(SdFileSize* sdFileSize, common::ImportDataList* fileList);
CheckedNetworkSetting s_CurrentNetowrkSetting1;
void ConvertTimeZoneString(const char* str)
{
s_TimeZone.hour = 0;
s_TimeZone.minutes = 0;
s_TimeZone.isMinus = false;
bool hour = true;
bool ten = true;
u32 count = 0;
for(u32 i = 0; i < TIME_ZONE_LENGTH && count < 2; i++)
{
switch (str[i])
{
case ':':
{
hour = false;
}
break;
case '"':
{
// 2回読んだら終了
count++;
}
break;
case '+':
{
s_TimeZone.isMinus = false;
}
break;
case '-':
{
s_TimeZone.isMinus = true;
}
break;
default:
{
if(hour)
{
if(ten)
{
s_TimeZone.hour += (str[i] - '0') * 10;
ten = false;
}
else
{
s_TimeZone.hour += str[i] - '0';
ten = true;
}
}
else
{
if(ten)
{
s_TimeZone.minutes += (str[i] - '0') * 10;
ten = false;
}
else
{
s_TimeZone.minutes += str[i] - '0';
ten = true;
}
}
}
break;
}
}
NN_LOG("Converted TimeZone = ");
if(s_TimeZone.isMinus)
{
NN_LOG("-");
}
NN_LOG("%02d:%02d\n", s_TimeZone.hour, s_TimeZone.minutes);
}
namespace
{
bool CreateEmptyFile(const wchar_t* path)
{
nn::Result result;
bool create = false;
result = common::SdMountManager::Mount();
if (result.IsSuccess())
{
nn::fs::FileOutputStream fos;
result = fos.TryInitialize(path, true);
if(result.IsSuccess())
{
fos.TryFlush();
create = true;
}
fos.Finalize();
}
common::SdMountManager::Unmount();
return create;
}
}
nn::Result ReadSerialNumber(u8* serial)
{
static nn::Result result = nn::ResultSuccess();
if(s_ReadSerialNumber)
{
std::memcpy(serial, s_SerialNo, sizeof(s_SerialNo));
return result;
}
COMMON_LOGGER("Read Serial Number in SD.\n");
size_t readSize;
common::SdReaderWriter sdReader;
size_t bufSize = 1024;
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize);
if(buf != NULL)
{
result = sdReader.ReadBufWithCmac(common::SERIAL_PATHNAME, buf, bufSize, &readSize);
if(result.IsSuccess())
{
std::memcpy(s_SerialNo, buf, sizeof(s_SerialNo));
std::memcpy(serial, s_SerialNo, sizeof(s_SerialNo));
s_ReadSerialNumber = true;
}
common::HeapManager::GetHeap()->Free(buf);
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
nn::Result EqualsDeviceIdFileandDeviceId(common::HardwareStateManager& manager)
{
static nn::Result result = nn::ResultSuccess();
if(s_CheckedEqualsDeviceIdFileandDeviceId)
{
return result;
}
COMMON_LOGGER("Check Device Id\n");
bit32 sdDeviceId;
common::SdReaderWriter sdReader;
size_t totalSize;
size_t bufSize = 1024;
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize);
if (buf != NULL)
{
result = sdReader.ReadBufWithCmac(common::DEVICE_ID_PATHNAME, buf, bufSize, &totalSize);
if (result.IsSuccess())
{
s_CheckedEqualsDeviceIdFileandDeviceId = true;
std::memcpy(&sdDeviceId, buf, sizeof(sdDeviceId));
if (manager.GetDeviceId() == sdDeviceId)
{
result = nn::ResultSuccess();
}
else
{
result = nn::Result(nn::Result::LEVEL_STATUS, nn::Result::SUMMARY_INVALID_RESULT_VALUE,
nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_INVALID_RESULT_VALUE);
}
}
common::HeapManager::GetHeap()->Free(buf);
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
nn::Result EqualsRegionDataandRegion()
{
static nn::Result result = nn::ResultSuccess();
if(s_CheckedEqualsRegionDataandRegion)
{
return result;
}
COMMON_LOGGER("Check Region\n");
nn::cfg::CTR::CfgRegionCode region;
region = nn::cfg::CTR::GetRegion();
nn::cfg::CTR::CfgRegionCode sdRegion;
common::SdReaderWriter sdReader;
size_t readSize;
size_t bufSize = 1024;
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize);
if (buf != NULL)
{
result = sdReader.ReadBufWithCmac(common::REGION_DATA_PATHNAME, buf, bufSize, &readSize);
if (result.IsSuccess())
{
std::memcpy(&sdRegion, buf, sizeof(sdRegion));
s_CheckedEqualsRegionDataandRegion = true;
if(region == sdRegion)
{
result = nn::ResultSuccess();
}
else
{
result = nn::Result(nn::Result::LEVEL_STATUS, nn::Result::SUMMARY_INVALID_RESULT_VALUE,
nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_INVALID_RESULT_VALUE);
}
}
common::HeapManager::GetHeap()->Free(buf);
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
void SetCountry(nn::cfg::CTR::CfgCountryCode countryCode)
{
using namespace nn::cfg::CTR;
using namespace nn::cfg::CTR::detail;
SimpleAddressIdCfgData simpleAddressId;
TwlCountryCodeCfgData countryData;
nn::cfg::CTR::system::Initialize();
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::GetConfig(&simpleAddressId, sizeof(SimpleAddressIdCfgData), GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID)));
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::GetConfig(&countryData, sizeof(TwlCountryCodeCfgData), GET_CFG_KEY(NN_CFG_TWL, NN_CFG_TWL_COUNTRY_CODE)));
nn::cfg::CTR::system::Finalize();
simpleAddressId.id = (countryCode << CFG_SIMPLE_ADDRESS_ID_COUNTRY_SHIFT) | (1
<< CFG_SIMPLE_ADDRESS_ID_REGION_SHIFT);
countryData.country = countryCode;
nn::cfg::CTR::system::Initialize();
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::SetConfig(GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID), &simpleAddressId, sizeof(SimpleAddressIdCfgData)));
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::SetConfig(GET_CFG_KEY(NN_CFG_TWL, NN_CFG_TWL_COUNTRY_CODE), &countryData, sizeof(TwlCountryCodeCfgData)));
nn::cfg::CTR::system::FlushConfig();
nn::cfg::CTR::system::Finalize();
}
void SetLanguage(nn::cfg::CTR::CfgLanguageCode languageCode)
{
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::init::SetConfig(
GET_CFG_KEY(nn::cfg::CTR::detail::NN_CFG_USER_INFO,
nn::cfg::CTR::detail::NN_CFG_USER_INFO_LANGUAGE),
&languageCode,
sizeof(nn::cfg::CTR::detail::LanguageCfgData)));
NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::init::FlushConfig());
nn::cfg::nor::CTR::Initialize();
NN_UTIL_PANIC_IF_FAILED(nn::cfg::nor::CTR::SetLanguage(static_cast<nn::cfg::CTR::CfgLanguageCode>(languageCode)));
nn::cfg::nor::CTR::Finalize();
}
nn::Result ImportCountryLanguageData()
{
nn::Result result = nn::ResultSuccess();
if (common::ExistsCountryLanguageFile())
{
size_t bufSize = 1024;
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize);
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::COUNTRY_SETTING_PATHNAME, buf, bufSize, &readSize);
if (result.IsSuccess())
{
// SDから読み出し成功
SetCountry(reinterpret_cast<common::CfgCountryLanguage*> (buf)->country);
SetLanguage(reinterpret_cast<common::CfgCountryLanguage*> (buf)->language);
}
common::HeapManager::GetHeap()->Free(buf);
NN_UTIL_RETURN_IF_FAILED(result);
}
}
else
{
// リージョンから適当な国を指定する
nn::cfg::CTR::CfgRegionCode region;
region = nn::cfg::CTR::GetRegion();
NN_LOG("Country Setting does not exist. Use Default Setting\n");
switch(region)
{
case nn::cfg::CTR::CFG_REGION_JAPAN:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_JAPAN);
}
break;
case nn::cfg::CTR::CFG_REGION_AMERICA:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_UNITED_STATES);
}
break;
case nn::cfg::CTR::CFG_REGION_EUROPE:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_FRANCE);
}
break;
case nn::cfg::CTR::CFG_REGION_AUSTRALIA:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_AUSTRALIA);
}
break;
case nn::cfg::CTR::CFG_REGION_CHINA:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_CHINA);
}
break;
case nn::cfg::CTR::CFG_REGION_KOREA:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_SOUTH_KOREA);
}
break;
case nn::cfg::CTR::CFG_REGION_TAIWAN:
{
SetCountry(nn::cfg::CTR::CFG_COUNTRY_TAIWAN);
}
break;
}
}
return result;
}
inline u8 DecimalToBcd(u8 param)
{
u8 theTen, theOne;
theTen = param / 10;
theOne = param - theTen * 10;
return (theTen << 4 | theOne);
}
nn::Result ImportMcuRtc(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Import RTC Data.\n");
nn::Result result = nn::ResultSuccess();
nn::Handle handle = manager.GetMcuHandle();
if(handle.IsValid())
{
if (common::CheckFileExists(common::MCU_RTC_PATHNAME))
{
size_t bufSize = 1024;
NN_LOG("AllocatableSize = %d\n", bufSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize);
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::MCU_RTC_PATHNAME, buf, bufSize, &readSize);
if (result.IsSuccess())
{
// mcuを使ってセットする
nn::mcu::CTR::HwCheck mcu(handle);
nn::mcu::CTR::RtcData* rtc = reinterpret_cast<nn::mcu::CTR::RtcData*> (buf);
NN_LOG("RTC = 20%02d/%02d/%02d %02d:%02d:%02d\n", rtc->m_Year, rtc->m_Month, rtc->m_Day, rtc->m_Hour, rtc->m_Minute, rtc->m_Second);
// BCD変換が必要
size_t RTC_PARAM_SIZE = sizeof(nn::mcu::CTR::RtcData);
u8 bcd[RTC_PARAM_SIZE];
for (int i = 0; i < RTC_PARAM_SIZE; i++)
{
bcd[i] = DecimalToBcd(reinterpret_cast<u8*> (rtc)[i]);
}
const u8 RETRY = 10;
for (u8 i = 0; i < RETRY; i++)
{
result = mcu.WriteBySend(nn::drivers::mcu::CTR::MCU_RTC_SEC_ADDR, bcd, RTC_PARAM_SIZE);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if(result.IsSuccess())
{
break;
}
nn::os::Thread::Sleep(
nn::fnd::TimeSpan::FromMilliSeconds(
nn::os::Tick::GetSystemCurrent().ToTimeSpan().GetMilliSeconds() % 100));
}
}
common::HeapManager::GetHeap()->Free(buf);
NN_UTIL_RETURN_IF_FAILED(result);
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
}
}
else
{
result = nn::Result(nn::Result::LEVEL_PERMANENT, nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_INVALID_HANDLE);
}
return result;
}
void InitializeFileSystem()
{
nn::Result result;
for (u32 i = 0; i < common::TWL_PATHNAME_MAX; i++)
{
result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[i], common::TWL_FS_ARCHIVE_KIND[i]);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsSuccess())
{
nn::fs::Directory dir;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
std::wstring currentDirectory = common::NAND_TWL_ROOT_PATHNAME_WITH_SLASH_TABLE[i];
result = dir.TryInitialize(currentDirectory.c_str());
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
if (result.IsFailure())
{
dir.Finalize();
}
if (numEntry == 0)
{
// ルートディレクトリを閉じる
dir.Finalize();
// ルートディレクトリの子を開く
for (entryIndex = entryList.begin(); entryIndex != entryList.end(); entryIndex++)
{
// ディレクトリなら削除する
if (entryIndex->attributes.isDirectory)
{
NN_LOG("Try Delete %ls%ls/\n", currentDirectory.c_str(), entryIndex->entryName);
result = nn::fs::TryDeleteDirectoryRecursively((currentDirectory + ::std::wstring(
entryIndex->entryName)).c_str());
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
}
// ファイルなら削除する
else
{
NN_LOG("Try Delete %ls%ls\n", currentDirectory.c_str(), entryIndex->entryName);
result = nn::fs::TryDeleteFile(
(currentDirectory + ::std::wstring(entryIndex->entryName)).c_str());
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
}
}
// 削除完了
break;
}
else
{
// vectorに保存する
entryList.push_back(entry);
if (entry.attributes.isDirectory)
{
NN_LOG("%ls%ls/\n", currentDirectory.c_str(), entry.entryName);
}
else
{
NN_LOG("%ls%ls\n", currentDirectory.c_str(), entry.entryName);
}
}
}
}
nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[i]);
}
nn::fs::InitializeCtrFileSystem();
}
nn::Result ImportIvs()
{
nn::Result result = nn::ResultSuccess();
nn::fs::FileOutputStream fos;
size_t bufSize = 1024;
void* enc = common::HeapManager::GetHeap()->Allocate(bufSize);
if (enc != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::IVS_PATHNAME, enc, bufSize, &readSize);
if(result.IsSuccess())
{
// SDから読み出し成功
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
if (result.IsSuccess())
{
void *dec = common::HeapManager::GetHeap()->Allocate(readSize);
if (dec != NULL)
{
// AES復号化する
nn::crypto::Initialize();
nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key));
swAesCtrContest.Decrypt(dec, enc, readSize);
// IVS書き込み
result = fos.TryInitialize(common::IVS_NAND_PATHNAME, true);
if (result.IsSuccess())
{
if (result.IsSuccess())
{
s32 writeSize;
result = fos.TryWrite(&writeSize, dec, readSize, true);
if (result.IsSuccess())
{
COMMON_LOGGER("Import IVS.\n");
}
}
}
common::HeapManager::GetHeap()->Free(dec);
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
}
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
}
common::HeapManager::GetHeap()->Free(enc);
NN_UTIL_RETURN_IF_FAILED(result);
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
void ImportThreadFunc()
{
nn::Result result;
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = common::SdMountManager::Mount();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize();
NN_LOG("AllocatableSize = %d\n", bufSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize, AES_BLOCK_SIZE);
if (buf != NULL)
{
common::CopyDirectory(
&s_FileLists,
(::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(),
common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH,
buf, bufSize, false, NULL, NULL);
common::HeapManager::GetHeap()->Free(buf);
}
common::SdMountManager::Unmount();
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
NN_LOG("Import Thread Finalize\n");
}
namespace
{
void ImportSaveData()
{
// SDカードからNANDに読み込み
nn::Result result;
// ファイルサイズ設定
common::InitializeTransferProgress(s_SdFileSize.ctrFileSize);
// SDカードにあるセーブデータディレクトリ以下のデータをNANDにコピー
COMMON_LOGGER("Import NAND Data Start...\n");
s_ImportThread.Start(ImportThreadFunc, s_ImportThreadStack);
}
nn::Result ImportNorData()
{
COMMON_LOGGER("Import NOR Data.\n");
nn::Result result = nn::ResultSuccess();
nn::cfg::nor::CTR::Initialize();
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize() / 2;
NN_LOG("AllocatableSize = %d\n", bufSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize);
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::NOR_PATHNAME, buf, bufSize, &readSize);
if(result.IsSuccess())
{
// cfgを使ってセットする
result = nn::cfg::nor::CTR::SetNtrSetting(&reinterpret_cast<common::NtrNorData*>(buf)->ntrConfig.ncd,
&reinterpret_cast<common::NtrNorData*>(buf)->ntrConfig.ncd_ex);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
// WiFiコネクションIDが仮の値であればWiFi設定は移行しない
// TWL修理に準拠している
u64 attestedUserId1 = 0;
u64 attestedUserId2 = 0;
const u32 WIFI_CONNECTION_USERID_OFFSET1 = 0xf0;
const u32 WIFI_CONNECTION_USERID_OFFSET2 = 0x1f0;
const u32 USERID_SIZE = 6;
const bit64 USERID_MASK = 0x7FFFFFFFFFF; // 43bit
void* NtrWifiSettingAddr = &reinterpret_cast<common::NtrNorData*>(buf)->NtrWiFiSetting;
std::memcpy(&attestedUserId1,
&reinterpret_cast<u8*>(NtrWifiSettingAddr)[WIFI_CONNECTION_USERID_OFFSET1],
USERID_SIZE);
attestedUserId1 &= USERID_MASK;
std::memcpy(&attestedUserId2,
&reinterpret_cast<u8*>(NtrWifiSettingAddr)[WIFI_CONNECTION_USERID_OFFSET2],
USERID_SIZE);
attestedUserId2 &= USERID_MASK;
if (attestedUserId1 == attestedUserId2 && attestedUserId1 != 0)
{
// TWL WiFi設定
result = nn::cfg::nor::CTR::WriteTwlWifiSetting(0,
reinterpret_cast<common::NtrNorData*> (buf)->TwlWiFiSetting, common::TWL_WIFI_SETTING_SIZE);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
// NTR WiFi設定
result = nn::cfg::nor::CTR::WriteNtrWifiSetting(0,
reinterpret_cast<common::NtrNorData*> (buf)->NtrWiFiSetting, common::NTR_WIFI_SETTING_SIZE);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
}
}
common::HeapManager::GetHeap()->Free(buf);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
}
nn::Result ReadVersionData()
{
nn::Result result = nn::ResultSuccess();
std::memset(&s_SDVersionData, 0, sizeof(common::VerDef));
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize() / 2;
NN_LOG("AllocatableSize = %d\n", bufSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize);
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::VERSION_DATA_PATHNAME, buf, bufSize, &readSize);
if(result.IsSuccess())
{
// バージョン情報を保持する
std::memcpy(&s_SDVersionData, buf, readSize);
NN_LOG("SD Version = %02d.%02d.%02d-%02d\n", s_SDVersionData.cup.majorVersion,
s_SDVersionData.cup.minorVersion,
s_SDVersionData.cup.microVersion,
s_SDVersionData.nup.majorVersion);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
}
common::HeapManager::GetHeap()->Free(buf);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
}
else
{
COMMON_LOGGER("Failed Allocate Heap!!\n");
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
bool ExistsIvsDirectory(std::string& ivsRoot)
{
nn::Result result;
nn::fs::Directory dir;
common::SdMountManager::Mount();
result = dir.TryInitialize(common::SD_NINTENDO_3DS_ROOT_PATH);
if(result.IsFailure())
{
NN_DBG_PRINT_RESULT(result);
common::SdMountManager::Unmount();
return false;
}
wchar_t ivs[34];
std::mbstowcs(ivs, ivsRoot.c_str(), ivsRoot.size() + 1);
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
if (result.IsFailure())
{
dir.Finalize();
common::SdMountManager::Unmount();
return false;
}
if (numEntry == 0)
{
dir.Finalize();
common::SdMountManager::Unmount();
return false;
}
else
{
// 比較する
if (entry.attributes.isDirectory)
{
NN_LOG("%ls\n", entry.entryName);
if(std::wcscmp(ivs, entry.entryName) == 0)
{
common::SdMountManager::Unmount();
return true;
}
}
}
}
}
void Cleanup()
{
nn::Result result;
bool execCleanup;
result = nn::am::NeedsCleanup(&execCleanup, nn::fs::MEDIA_TYPE_NAND);
if(result.IsSuccess())
{
if(execCleanup)
{
COMMON_LOGGER("Cleanup NAND\n");
nn::am::DoCleanup(nn::fs::MEDIA_TYPE_NAND);
}
}
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
}
void DeleteAllCheckFiles()
{
nn::Result result;
common::SdMountManager::Mount();
for(u32 i = 0; i < sizeof(CHECK_FILENAME_TABLE) / sizeof(CHECK_FILENAME_TABLE[0]); i++)
{
if(common::CheckFileExists(CHECK_FILENAME_TABLE[i]))
{
result = nn::fs::TryDeleteFile(CHECK_FILENAME_TABLE[i]);
COMMON_LOGGER_RESULT_IF_FAILED(result);
}
}
common::SdMountManager::Unmount();
}
void FinalizeImportThread()
{
s_ImportThread.Join();
s_ImportThread.Finalize();
}
bool IsImportThreadFinished()
{
return s_ImportThread.IsValid() && !s_ImportThread.IsAlive();
}
void CreateWriteFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_WRITE_FINISHED]);
common::ClearFileCheck(common::EXISTS_WRITE_FINISHED);
}
void CreateConsoleInitializedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_CONSOLE_INTIALIZED]);
common::ClearFileCheck(common::EXISTS_CONSOLE_INTIALIZED);
}
void CreateUpdateFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_UPDATE_FINISHED]);
common::ClearFileCheck(common::EXISTS_UPDATE_FINISHED);
}
void CreateRtcSyncFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_RTC_SYNC_FINISHED]);
common::ClearFileCheck(common::EXISTS_RTC_SYNC_FINISHED);
}
void CreateDownloadIvsFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_DOWNLOAD_IVS]);
common::ClearFileCheck(common::EXISTS_DOWNLOAD_IVS);
}
void CreateDeleteAccountFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_DELETE_ACCOUNT]);
common::ClearFileCheck(common::EXISTS_DELETE_ACCOUNT);
}
void CreateTransferAccountFinishedFile()
{
CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_TRANSFER_ACCOUNT]);
common::ClearFileCheck(common::EXISTS_TRANSFER_ACCOUNT);
}
u32 GetImportProgress()
{
return common::GetProgress();
}
bool UpdateNetworkSetting(nn::ac::NetworkSetting& networkSetting)
{
nn::Result result;
bool retval = true;
result = nn::ac::InitializeInternal();
if(result.IsFailure())
{
retval = false;
COMMON_LOGGER("Error: nn::ac::InitializeInternal() failed\n");
}
else
{
//特に入力させる必要のない自動で設定する項目
networkSetting.wireless.enable = true;
networkSetting.wireless.multiSsid.enable = false;
networkSetting.ip.enableDHCP = true;
networkSetting.scanlessConnect.hasConnected = false;
networkSetting.proxy.enable = false;
networkSetting.other.enableUPnP = false;
// 現在のインターネット設定1を一時的に保持
result = nn::ac::LoadNetworkSetting(0, s_CurrentNetowrkSetting1.setting);
if(result.IsSuccess())
{
s_CurrentNetowrkSetting1.isValid = true;
}
else
{
s_CurrentNetowrkSetting1.isValid = false;
}
result = nn::ac::UpdateNetworkSetting( 0, networkSetting );
if(!result.IsSuccess())
{
retval = false;
COMMON_LOGGER("Error: SetNetworkSetting (Update Error)\n");
}
else
{
result = nn::ac::FinalizeInternal();
if (!result.IsSuccess())
{
retval = false;
COMMON_LOGGER("Error: SetNetworkSetting (Finalize Error)\n");
}
}
}
return retval;
}
bool ReadSetting(bool* nupOnly, bool* getIvs, bool* checkSd, bool* skipNup)
{
nn::Result result;
bool retval = true;
common::ConfigFileLoader configfileLoader;
common::SdMountManager::Mount();
size_t size = 10240;
void* heapAddr = common::HeapManager::GetHeap()->Allocate(size);
if(heapAddr != NULL)
{
result = configfileLoader.Initialize(common::AP_SETTING_PATHNAME, heapAddr, size);
if (result.IsSuccess())
{
nn::ac::NetworkSetting networkSetting;
{
const char* ssid = configfileLoader.ReadAsChar(L"SSID"); // SSID
if(ssid == NULL)
{
COMMON_LOGGER("SSID: is missing\n");
retval = false;
}
else
{
std::strncpy(reinterpret_cast<char*> (networkSetting.wireless.essidSecurity.ssid), ssid, 32);
networkSetting.wireless.essidSecurity.ssidLength = std::strlen(ssid) % 33;
COMMON_LOGGER("SSID = %s\n", networkSetting.wireless.essidSecurity.ssid);
}
}
{
const char* mode = configfileLoader.ReadAsChar(L"MODE"); // MODE
if(mode == NULL)
{
COMMON_LOGGER("MODE: is missing\n");
retval = false;
}
else
{
if (std::strcmp(mode, "OPEN") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::OPEN;
}
else if (std::strcmp(mode, "WEP40") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_40BIT;
}
else if (std::strcmp(mode, "WEP104") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_104BIT;
}
else if (std::strcmp(mode, "WEP128") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_128BIT;
}
else if (std::strcmp(mode, "WPA-TKIP") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA_TKIP;
}
else if (std::strcmp(mode, "WPA2-TKIP") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA2_TKIP;
}
else if (std::strcmp(mode, "WPA-AES") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA_AES;
}
else if (std::strcmp(mode, "WPA2-AES") == 0)
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA2_AES;
}
else
{
networkSetting.wireless.essidSecurity.securityMode = nn::ac::OPEN;
}
switch (networkSetting.wireless.essidSecurity.securityMode)
{
case nn::ac::OPEN:
{
COMMON_LOGGER("MODE = OPEN\n");
}
break;
case nn::ac::WEP_40BIT:
{
COMMON_LOGGER("MODE = WEP_40BIT\n");
}
break;
case nn::ac::WEP_104BIT:
{
COMMON_LOGGER("MODE = WEP_104BIT\n");
}
break;
case nn::ac::WEP_128BIT:
{
COMMON_LOGGER("MODE = WEP_128BIT\n");
}
break;
case nn::ac::WPA_TKIP:
{
COMMON_LOGGER("MODE = WPA_TKIP\n");
}
break;
case nn::ac::WPA2_TKIP:
{
COMMON_LOGGER("MODE = WPA2_TKIP\n");
}
break;
case nn::ac::WPA_AES:
{
COMMON_LOGGER("MODE = WPA_AES\n");
}
break;
case nn::ac::WPA2_AES:
{
COMMON_LOGGER("MODE = WPA2_AES\n");
}
break;
}
}
}
{
const char* pass = configfileLoader.ReadAsChar(L"PASS"); // PASS
if(pass == NULL)
{
COMMON_LOGGER("PASS: is missing\n");
retval = false;
}
else
{
switch (networkSetting.wireless.essidSecurity.securityMode)
{
case nn::ac::WEP_40BIT:
case nn::ac::WEP_104BIT:
case nn::ac::WEP_128BIT:
{
std::strncpy(reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.passphrase),
pass, 64);
std::memcpy(networkSetting.wireless.essidSecurity.key,
networkSetting.wireless.essidSecurity.passphrase, 64);
}
break;
case nn::ac::WPA_TKIP:
case nn::ac::WPA2_TKIP:
case nn::ac::WPA_AES:
case nn::ac::WPA2_AES:
{
std::strncpy(reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.passphrase),
pass, 64);
size_t phrase_size = std::strlen(
reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.passphrase));
nn::nwm::Ssid ssid(reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.ssid));
nn::nwm::ConvertPasswordToPsk(
reinterpret_cast<char *> (networkSetting.wireless.essidSecurity.passphrase),
phrase_size, ssid, networkSetting.wireless.essidSecurity.key);
}
break;
case nn::ac::OPEN:
default:
{
//do nothing
}
break;
}
}
}
{
s32 dnsAuto; // DNS_AUTO
if(configfileLoader.ReadAsChar(L"DNS_AUTO") == NULL)
{
COMMON_LOGGER("DNS_AUTO: is missing\n");
retval = false;
}
else
{
dnsAuto = configfileLoader.ReadAsInteger(L"DNS_AUTO");
if (dnsAuto == 1)
{
networkSetting.ip.autoDNSSetting = true;
}
else
{
networkSetting.ip.autoDNSSetting = false;
}
COMMON_LOGGER("DNS_AUTO = %d\n", networkSetting.ip.autoDNSSetting);
}
}
{
const char* dnsPrimary = configfileLoader.ReadAsChar(L"DNS_PRI"); // プライマリDNS
if(!networkSetting.ip.autoDNSSetting)
{
if (dnsPrimary == NULL)
{
COMMON_LOGGER("DNS_PRI: is missing\n");
retval = false;
}
else
{
u8 dns[4];
nn::socket::InAddr addr;
if (1 == nn::socket::InetAtoN(dnsPrimary, &addr))
{
dns[3] = (0xff & (addr.addr >> 24));
dns[2] = (0xff & (addr.addr >> 16));
dns[1] = (0xff & (addr.addr >> 8));
dns[0] = (0xff & (addr.addr));
}
std::memcpy(networkSetting.ip.dns[0], dns, 4);
COMMON_LOGGER("DNS_PRI = %03d.%03d.%03d.%03d\n", networkSetting.ip.dns[0][0],
networkSetting.ip.dns[0][1],
networkSetting.ip.dns[0][2],
networkSetting.ip.dns[0][3]);
}
}
}
{
const char* dnsSecondary = configfileLoader.ReadAsChar(L"DNS_SEC"); // セカンダリDNS
if(!networkSetting.ip.autoDNSSetting)
{
if(dnsSecondary == NULL)
{
COMMON_LOGGER("DNS_SEC: is missing\n");
retval = false;
}
else
{
u8 dns[4];
nn::socket::InAddr addr;
if (1 == nn::socket::InetAtoN(dnsSecondary, &addr))
{
dns[3] = (0xff & (addr.addr >> 24));
dns[2] = (0xff & (addr.addr >> 16));
dns[1] = (0xff & (addr.addr >> 8));
dns[0] = (0xff & (addr.addr));
}
std::memcpy(networkSetting.ip.dns[1], dns, 4);
COMMON_LOGGER("DNS_SEC = %03d.%03d.%03d.%03d\n", networkSetting.ip.dns[1][0],
networkSetting.ip.dns[1][1],
networkSetting.ip.dns[1][2],
networkSetting.ip.dns[1][3]);
}
}
}
{
const char* ntpServerName = configfileLoader.ReadAsChar(L"NTPSRV"); // NTPサーバ
if(ntpServerName == NULL)
{
COMMON_LOGGER("NTPSRV: is missing\n");
retval = false;
}
else
{
std::strlcpy(s_NtpServerName, ntpServerName, sizeof(s_NtpServerName));
COMMON_LOGGER("NTPSRV = %s\n", s_NtpServerName);
}
}
{
const char* timeZone = configfileLoader.ReadAsChar(L"TIMEZONE"); // タイムゾーン
if(timeZone == NULL)
{
COMMON_LOGGER("TIMEZONE: is missing\n");
retval = false;
}
else
{
std::strlcpy(s_TimeZoneStr, timeZone, sizeof(s_TimeZoneStr));
COMMON_LOGGER("TIMEZONE = %s\n", s_TimeZoneStr);
ConvertTimeZoneString(s_TimeZoneStr);
}
}
{
const wchar_t* const NUP_ONLY_STR = L"NUP_ONLY";
NN_NULL_ASSERT(nupOnly);
if (configfileLoader.ReadAsChar(NUP_ONLY_STR) != NULL)
{
s32 num = configfileLoader.ReadAsInteger(NUP_ONLY_STR);
if (num == 1)
{
*nupOnly = true;
COMMON_LOGGER("NUP Only Mode.\n");
}
}
}
{
const wchar_t* const GET_IVS_STR = L"GET_IVS";
NN_NULL_ASSERT(getIvs);
if (configfileLoader.ReadAsChar(GET_IVS_STR) != NULL)
{
s32 num = configfileLoader.ReadAsInteger(GET_IVS_STR);
if (num == 1)
{
*getIvs = true;
COMMON_LOGGER("GET IVS Mode.\n");
}
}
}
{
const wchar_t* const CHECK_SD_STR = L"CHECK_SD";
NN_NULL_ASSERT(checkSd);
if (configfileLoader.ReadAsChar(CHECK_SD_STR) != NULL)
{
s32 num = configfileLoader.ReadAsInteger(CHECK_SD_STR);
if (num == 1)
{
*checkSd = true;
COMMON_LOGGER("CHECK SD Mode.\n");
}
}
}
{
const wchar_t* const SKIP_NUP_STR = L"SKIP_NUP";
NN_NULL_ASSERT(skipNup);
if (configfileLoader.ReadAsChar(SKIP_NUP_STR) != NULL)
{
s32 num = configfileLoader.ReadAsInteger(SKIP_NUP_STR);
if (num == 1)
{
*skipNup = true;
COMMON_LOGGER("Skip NUP Mode.\n");
}
}
}
configfileLoader.Finalize();
// 書き込み完了しなければfalse
if(!UpdateNetworkSetting(networkSetting))
{
retval = false;
}
}
else
{
NN_LOG("configfileLoader Initialize Failed\n");
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
retval = false;
}
common::HeapManager::GetHeap()->Free(heapAddr);
}
else
{
NN_LOG("Can't Allocate Heap\n");
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
retval = false;
}
common::SdMountManager::Unmount();
return retval;
}
char* GetNtpServerName()
{
return s_NtpServerName;
}
TimeZone GetTimeZone()
{
return s_TimeZone;
}
CheckedNetworkSetting* GetTempNetworkSetting()
{
return &s_CurrentNetowrkSetting1;
}
void ImportTwlData(enum common::TWL_PATH_INDEX path, s64 fileSize)
{
NN_ASSERT(path < common::TWL_PATHNAME_MAX);
nn::Result result;
result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[path], common::TWL_FS_ARCHIVE_KIND[path]);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = common::SdMountManager::Mount();
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize();
NN_LOG("AllocatableSize = %d\n", bufSize);
// ファイルサイズ設定
common::InitializeTransferProgress(fileSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize, AES_BLOCK_SIZE);
if (buf != NULL)
{
wchar_t archiveName[nn::fs::MAX_FILE_PATH_LENGTH];
::std::mbstowcs(archiveName, common::TWL_ARCHIVE_NAME_TABLE[path], std::strlen(common::TWL_ARCHIVE_NAME_TABLE[path]) + 1);
std::wstring archiveString(archiveName);
common::CopyDirectory(
&s_FileLists,
(::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(),
(archiveString + ::std::wstring(L"/")).c_str(),
buf, bufSize, false, NULL, NULL);
common::HeapManager::GetHeap()->Free(buf);
}
common::SdMountManager::Unmount();
nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[path]);
}
void ImportTwlTitleSaveData(s64 fileSize)
{
nn::Result result;
result = nn::fs::MountSpecialArchive(common::NAND_TWL_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_TWL_NAND);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = common::SdMountManager::Mount();
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize();
NN_LOG("AllocatableSize = %d\n", bufSize);
// ファイルサイズ設定
common::InitializeTransferProgress(fileSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize, AES_BLOCK_SIZE);
if (buf != NULL)
{
common::CopyDirectory(
&s_FileLists,
(::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str(),
(std::wstring(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH) + ::std::wstring(L"/")).c_str(),
buf, bufSize, false, NULL, NULL);
common::HeapManager::GetHeap()->Free(buf);
}
common::SdMountManager::Unmount();
nn::fs::Unmount(common::NAND_TWL_ARCHIVE_NAME);
}
void ImportTwlPhotoDataFunc()
{
COMMON_LOGGER("Import Twl Photo Data.\n");
ImportTwlData(common::TWL_PHOTO, s_SdFileSize.twlPhotoFileSize);
}
void ImportTwlSoundDataFunc()
{
COMMON_LOGGER("Import Twl Sound Data.\n");
ImportTwlData(common::TWL_SOUND, s_SdFileSize.twlSoundFileSize);
}
void ImportTwlSaveDataFunc()
{
COMMON_LOGGER("Import Twl Save Data.\n");
ImportTwlTitleSaveData(s_SdFileSize.twlFileSize);
}
void ImportTwlPhotoData()
{
s_ImportThread.Start(ImportTwlPhotoDataFunc, s_ImportThreadStack);
}
void ImportTwlSoundData()
{
s_ImportThread.Start(ImportTwlSoundDataFunc, s_ImportThreadStack);
}
void ImportTwlSaveData()
{
s_ImportThread.Start(ImportTwlSaveDataFunc, s_ImportThreadStack);
}
void ClearFileReadResult()
{
s_CheckedEqualsDeviceIdFileandDeviceId = false;
s_CheckedEqualsRegionDataandRegion = false;
s_ReadSerialNumber = false;
}
void ImportPlayHistoryThreadFunc()
{
common::PlayHistoryManager historyManager;
COMMON_LOGGER("Import PlayHistory\n");
historyManager.Import();
}
void ImportPlayHistory()
{
s_ImportThread.Start(ImportPlayHistoryThreadFunc, s_ImportThreadStack);
}
void ExportCalData()
{
using namespace nn::cfg::CTR::detail;
nn::Result result;
common::CfgCalData cfgCalData;
common::SdReaderWriter sdWriter;
COMMON_LOGGER("Export CalData\n");
common::SdMountManager::Mount();
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.touchPanelCfgData, sizeof(TouchPanelCfgData),
GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_TOUCHPANEL));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.lcdFlickerCfgData, sizeof(LcdFlickerCfgData),
GET_CFG_KEY(NN_CFG_LCD, NN_CFG_LCD_CAL_FLICKER));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.fcramCfgData, sizeof(FcramCfgData),
GET_CFG_KEY(NN_CFG_FCRAM, NN_CFG_FCRAM_CAL_DELAY));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.rtcCfgData, sizeof(RtcCfgData),
GET_CFG_KEY(NN_CFG_RTC, NN_CFG_RTC_CAL_COMPENSATION));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.gyroscopeCfgData, sizeof(GyroscopeCfgData),
GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_GYROSCOPE));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.accelCfgData, sizeof(AccelCfgData),
GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_ACCELEROMETER));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.codecCfgData, sizeof(CodecCfgData),
GET_CFG_KEY(NN_CFG_CODEC, NN_CFG_CODEC_CAL));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::GetConfig(&cfgCalData.mcuSlideVolumeRangeCfgData, sizeof(McuSlideVolumeRangeCfgData),
GET_CFG_KEY(NN_CFG_MCU, NN_CFG_MCU_SLIDE_VOLUME));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
sdWriter.WriteBufWithCmac(common::CFG_CALIBRATION_PATHNAME, &cfgCalData, sizeof(cfgCalData));
common::SdMountManager::Unmount();
}
nn::Result ImportCalData(common::CfgCalData *data)
{
using namespace nn::cfg::CTR::detail;
nn::Result result = nn::ResultSuccess();
COMMON_LOGGER("Import CalData\n");
common::SdMountManager::Mount();
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize() / 2;
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize);
if (buf != NULL)
{
common::SdReaderWriter sdReader;
size_t readSize;
result = sdReader.ReadBufWithCmac(common::CFG_CALIBRATION_PATHNAME, buf, bufSize, &readSize);
if(result.IsSuccess())
{
// SDから読み出し成功
std::memcpy(data, buf, readSize);
}
common::HeapManager::GetHeap()->Free(buf);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
common::SdMountManager::Unmount();
return result;
}
nn::Result InitializeHardwareDependentSetting()
{
using namespace nn::cfg::CTR::detail;
nn::Result result = nn::ResultSuccess();
common::CfgCalData cfgCalData;
result = ImportCalData(&cfgCalData);
NN_UTIL_RETURN_IF_FAILED(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_TOUCHPANEL),
&cfgCalData.touchPanelCfgData, sizeof(TouchPanelCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_LCD, NN_CFG_LCD_CAL_FLICKER),
&cfgCalData.lcdFlickerCfgData, sizeof(LcdFlickerCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_FCRAM, NN_CFG_FCRAM_CAL_DELAY), &cfgCalData.fcramCfgData,
sizeof(FcramCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_RTC, NN_CFG_RTC_CAL_COMPENSATION),
&cfgCalData.rtcCfgData, sizeof(RtcCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_GYROSCOPE),
&cfgCalData.gyroscopeCfgData, sizeof(GyroscopeCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_ACCELEROMETER),
&cfgCalData.accelCfgData, sizeof(AccelCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_CODEC, NN_CFG_CODEC_CAL), &cfgCalData.codecCfgData,
sizeof(CodecCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_MCU, NN_CFG_MCU_SLIDE_VOLUME),
&cfgCalData.mcuSlideVolumeRangeCfgData, sizeof(McuSlideVolumeRangeCfgData));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_LOG("Set cfgCalData\n");
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
nn::cfg::CTR::init::ResetCameraCalibration();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
nn::cfg::CTR::init::ResetAnalogStickCalibration();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return result;
}
nn::Result SetupFileList()
{
std::memset(&s_SdFileSize, 0, sizeof(s_SdFileSize));
// ファイル一覧を読み込む
nn::Result result = ReadFileList(&s_SdFileSize, &s_FileLists);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result ReadFileList(SdFileSize* sdFiles, common::ImportDataList* fileList)
{
nn::Result result = nn::ResultSuccess();
COMMON_LOGGER("Read File List\n");
size_t readSize;
common::SdReaderWriter sdReader;
s64 fileSize;
{
nn::fs::FileInputStream file;
// サイズ取得のため一時的に開く
result = file.TryInitialize(common::FILE_LIST_PATHNAME);
NN_UTIL_RETURN_IF_FAILED(result);
result = file.TryGetSize(&fileSize);
if (result.IsFailure())
{
file.Finalize();
return result;
}
file.Finalize();
}
void* buf = common::HeapManager::GetHeap()->Allocate(fileSize);
if(buf != NULL)
{
result = sdReader.ReadBufWithCmac(common::FILE_LIST_PATHNAME, buf, fileSize, &readSize);
if(result.IsSuccess())
{
// ファイル一覧
const char comma[] = ",";
const char newLine[] = "\n";
char *token = NULL;
token = std::strtok(reinterpret_cast<char*>(buf), comma);
bool parseFileName = false;
common::ImportDataEntry entry;
entry.fileName = std::string(token);
while( token != NULL)
{
if(parseFileName)
{
token = std::strtok(NULL, comma);
if(token != NULL)
{
entry.fileName = std::string(token);
}
}
else
{
token = std::strtok(NULL, newLine);
if(token != NULL)
{
s64 size = std::atoll(token);
if(size != -1)
{
entry.isDirectory = false;
sdFiles->totalFileSize += size;
wchar_t wcToken[nn::fs::MAX_FILE_PATH_LENGTH];
if(std::mbstowcs(wcToken, entry.fileName.c_str(), entry.fileName.size()) != entry.fileName.size() - 1)
{
if(std::wcsstr(wcToken, common::SD_SAVEDATA_ROOT_NAME) != NULL)
{
sdFiles->ctrFileSize += size;
}
else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME) != NULL)
{
sdFiles->twlPhotoFileSize += size;
}
else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME) != NULL)
{
sdFiles->twlSoundFileSize += size;
}
else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_ROOT_NAME) != NULL)
{
sdFiles->twlFileSize += size;
}
}
}
else
{
entry.isDirectory = true;
}
fileList->push_back(entry);
}
}
parseFileName = !parseFileName;
}
}
common::HeapManager::GetHeap()->Free(buf);
}
else
{
result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return result;
}
nn::Result ImportData()
{
static nn::Result result = nn::ResultSuccess();
static bool init = true;
if(init)
{
init = false;
// NANDのごみを削除する
Cleanup();
// SDカードのIVSファイルを書き込む
result = ImportIvs();
NN_UTIL_RETURN_IF_FAILED(result);
// NORデータを書き込む
result = ImportNorData();
NN_UTIL_RETURN_IF_FAILED(result);
// 固体固有calLデータをSDカードに出力する
// 本体初期化後はcal値が設定されている
ExportCalData();
// SDカードのセーブデータをNANDに書き込む
ImportSaveData();
}
return result;
}
}