2ndNUP対応版、SimpleAddress.regionIdを修正するようにしたバージョン

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@555 385bec56-5757-e545-9c3a-d8741f4650f1
This commit is contained in:
N2614 2012-01-13 08:21:59 +00:00
parent 9f33776eeb
commit 9339091b25
509 changed files with 27462 additions and 0 deletions

View File

@ -0,0 +1,15 @@
【ビルド環境】
・SDK
Horizon trunk r43280以降
・cygwin
・subversion
【ビルド時の注意】
開発機・量産機でAES鍵を変えるため、マスタリング用ビルド時は
sources\common\Aes_define.h
#define USE_PROD_KEY
を有効にすること。

View File

@ -0,0 +1,106 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Checker.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 "common_Types.h"
#include "CommonLogger.h"
#include "HeapManager.h"
#include "SaveDataChecker.h"
#include <nn/drivers/aes/CTR/ARM946ES/driverAes_Types.h>
namespace ConsoleBackup
{
namespace
{
const size_t CHECKER_STACK_SIZE = 0x4000;
nn::os::Thread s_CheckerThread;
nn::os::StackBuffer<CHECKER_STACK_SIZE> s_CheckerThreadStackSize;
nn::Result s_CheckerResult;
NandSavedataChecker* s_pChecker;
bool s_CheckErrorOccured = false;
}
s32 GetCheckSaveDataProgress()
{
if(s_pChecker != NULL)
{
return s_pChecker->GetProgress();
}
else
{
return 0;
}
}
void CheckSaveDataThreadFunc(bool erase)
{
size_t bufSize = common::GetAllocatableSize();
if(bufSize > common::FILE_COPY_HEAP_SIZE)
{
bufSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager heap(bufSize);
if (heap.GetAddr() != NULL)
{
s_pChecker = new NandSavedataChecker(heap.GetAddr(), bufSize);
s_CheckerResult = s_pChecker->CleanUp(erase);
}
else
{
s_CheckerResult = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE,
nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
}
void StartSaveDataCheck(bool erase)
{
s_CheckerThread.Start(CheckSaveDataThreadFunc, erase, s_CheckerThreadStackSize);
}
bool IsCheckSaveDataFinished()
{
return s_CheckerThread.IsValid() && !s_CheckerThread.IsAlive();
}
void FinalizeSaveDataCheck()
{
s_CheckerThread.Join();
s_CheckerThread.Finalize();
if(s_pChecker != NULL)
{
s_CheckErrorOccured = s_pChecker->GetCheckErrorOccured();
delete s_pChecker;
}
}
bool CheckSaveDataErrorOccured()
{
return s_CheckErrorOccured;
}
bool CheckSaveDataSucceeded()
{
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(s_CheckerResult);
return s_CheckerResult.IsSuccess();
}
}

View File

@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Checker.h
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$
*---------------------------------------------------------------------------*/
#ifndef CHECKER_H_
#define CHECKER_H_
namespace ConsoleBackup
{
s32 GetCheckSaveDataProgress();
//!@ brief セーブデータのチェックを開始する
//!@ param[in] erase エラー発生時にファイルを削除するかどうか
void StartSaveDataCheck(bool erase);
bool IsCheckSaveDataFinished();
void FinalizeSaveDataCheck();
bool CheckSaveDataErrorOccured();
bool CheckSaveDataSucceeded();
}
#endif /* CHECKER_H_ */

View File

@ -0,0 +1,322 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: ConsoleBackup.cpp
Copyright (C)2009 Nintendo Co., Ltd. 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/version.h>
#include <nn/ptm/CTR/ptm_ApiSysmenu.h>
#include <nn/mcu.h>
#include <nn/cfg/CTR/cfg_Api.h>
#include <nn/cfg/CTR/cfg_ApiInit.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/ps.h>
#include <nn/nwm.h>
#include <nn/ac.h>
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/fs/fs_ApiSysSaveData.h>
#include <nn/cfg/CTR/cfg_ApiNor.h>
#include <nn/os/os_SharedInfo.h>
#include <nn/pl/CTR/pl_Version.h>
#include <nn/fs/fs_ApiSharedExtSaveData.h>
#include <nn/nim.h>
#include <nn/ndm.h>
#include <nn/am.h>
#include "demo.h"
#include <vector>
#include <string>
#include "DrawSystemState.h"
#include "FileName.h"
#include "Controller.h"
#include "SimplePlayer.h"
#include "Exporter.h"
#include "CommonLogger.h"
#include "SDMountManager.h"
#include "HeapManager.h"
#include "common_Types.h"
#include "VersionDetect.h"
#include "Util.h"
#include "ResFont.h"
#include "HardwareStateManager.h"
// バージョン表示用
#include "version.h"
namespace {
// グラフィックスに割り当てるメモリ
const size_t s_GxHeapSize = 0x800000;
common::Util s_HwUtility;
} // namespace <unnamed>
extern "C" void nninitSetupDaemons(void)
{
}
namespace ConsoleBackup{
extern "C" void nnMain(void)
{
nn::Result result;
// os の初期化
nn::os::Initialize();
// fs の初期化
nn::fs::Initialize();
// appletの初期化
nn::applet::Enable( false );
// hid の初期化
result = nn::hid::Initialize();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
// ndmの初期化
result = nn::ndm::Initialize();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
// 全デーモンの自律動作をacの自動接続も含めて止める
result = nn::ndm::SuspendScheduler();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
// cfg の初期化
nn::cfg::CTR::init::Initialize();
nn::cfg::CTR::system::Initialize();
// 時計設定用ptm初期化
nn::ptm::CTR::InitializeForSystemMenu();
// ps の初期化
nn::ps::Initialize();
// amの初期化
nn::am::InitializeForLocalImporter();
// ヒープの確保
common::InitializeHeap();
// RenderSystem の準備
common::HeapManager gxHeapManager(s_GxHeapSize);
uptr heapForGx = reinterpret_cast<uptr>(gxHeapManager.GetAddr());
demo::RenderSystemDrawing renderSystem;
renderSystem.Initialize(heapForGx, s_GxHeapSize);
// ResFontの初期化
common::InitializeResFont();
// サウンドスレッドの起動
common::InitializeSimplePlayer();
// ログ描画の初期化
common::Logger::GetLoggerInstance()->Initialize(common::CONSOLE_WIDTH, common::CONSOLE_HEIGHT,
common::CONSOLE_MAX_LINE, &renderSystem);
// RenderSystemを作ってからログが出せる
common::Logger::InitializeEjectThread();
common::Logger::SetEjectHandler(OnSdEjected);
common::Logger::SetInsertHandler(OnSdInserted);
// 起動時に削除
common::Logger::GetLoggerInstance()->ClearSdLog();
COMMON_LOGGER("\n");
COMMON_LOGGER("CTR Console Backup start\n");
// ボタン入力
nn::hid::PadReader s_PadReader;
nn::hid::PadStatus padStatus;
// データの準備
s_HwUtility.InitializeForBackup();
common::HardwareStateManager manager(s_HwUtility);
// 情報出力
COMMON_LOGGER("CTR Console Backup %s-%s\n", CONSOLE_REPAIR_VERSION_MAJOR, CONSOLE_REPAIR_VERSION_MINOR);
COMMON_LOGGER("System Ver. %d.%d.%d-%d\n",
s_HwUtility.GetCupMajorVersion(),
s_HwUtility.GetCupMinorVersion(),
s_HwUtility.GetCupMicroVersion(),
s_HwUtility.GetNupVersion());
COMMON_LOGGER("System Region %s\n", s_HwUtility.GetRegionCodeA3());
COMMON_LOGGER("Serial Number %s\n", s_HwUtility.GetSerialNumber());
COMMON_LOGGER("Device ID %llu\n", s_HwUtility.GetInfraDeviceId());
COMMON_LOGGER("MAC Address %s\n", s_HwUtility.GetMacAddress());
bool flip = false;
bool continueBackup = false;
bool forceDelete = false;
for(;;)
{
bool nextStep = false;
s_PadReader.ReadLatest(&padStatus);
// AまたはSTARTボタンで進行
if(padStatus.trigger & nn::hid::BUTTON_A ||
padStatus.trigger & nn::hid::BUTTON_START)
{
nextStep = true;
if(padStatus.hold & nn::hid::BUTTON_LEFT)
{
forceDelete = true;
}
}
// LまたはRボタンで上下画面フリップ
if(padStatus.trigger & nn::hid::BUTTON_R ||
padStatus.trigger & nn::hid::BUTTON_L)
{
flip = !flip;
}
// コンソールスクロール
if(padStatus.hold & nn::hid::BUTTON_UP)
{
common::Logger::GetLoggerInstance()->ScrollUp();
}
// コンソールスクロール
if(padStatus.hold & nn::hid::BUTTON_DOWN)
{
common::Logger::GetLoggerInstance()->ScrollDown();
}
if(padStatus.hold & nn::hid::BUTTON_LEFT)
{
common::Logger::GetLoggerInstance()->ScrollToBegin();
}
if(padStatus.hold & nn::hid::BUTTON_RIGHT)
{
common::Logger::GetLoggerInstance()->ScrollToEnd();
}
// 情報更新
// ACアダプタ
std::string adapterState;
if(manager.IsAdapterConnected())
{
adapterState += ::std::string("Connected");
}
else
{
adapterState += ::std::string("Not Connected");
}
// 操作用メッセージ
// 進捗確認メッセージを兼ねる?
::std::vector<std::string> operationMessage;
ControlState(manager, operationMessage, nextStep, continueBackup, forceDelete);
nn::util::FloatColor titleColor;
titleColor.r = 0.3f;
titleColor.g = 0.f;
titleColor.b = 0.2f;
// 上画面表示
common::DrawSystemState("CTR Console Backup",
renderSystem,
titleColor,
flip,
adapterState,
s_HwUtility.GetCupMajorVersion(),
s_HwUtility.GetCupMinorVersion(),
s_HwUtility.GetCupMicroVersion(),
s_HwUtility.GetNupVersion(),
s_HwUtility.GetBatteryRemain(),
s_HwUtility.GetInfraDeviceId(),
s_HwUtility.GetFriendcode(),
GetProgress(),
IsBackupFailed(),
IsBackupSucceeded(),
IsBackupWarning(),
s_HwUtility.GetMacAddress(),
operationMessage,
s_HwUtility.GetRegion(),
s_HwUtility.GetSerialNumber(),
s_HwUtility.HasReadFriendCode()
);
if (GetBackupMode() == BACKUP_MODE_DELETE_IF_FAILED)
{
const u8 spaceSize = 10;
const u8 lineBottom = 23;
const u32 screenWidth = 400;
renderSystem.SetColor(1.f, 1.f, 1.f);
renderSystem.DrawText(0, lineBottom * spaceSize, "Delete Error File Mode");
renderSystem.SetColor(titleColor.r, titleColor.g, titleColor.b);
renderSystem.FillRectangle(0, lineBottom * spaceSize, screenWidth, spaceSize);
renderSystem.SetColor(1.f, 1.f, 1.f);
}
renderSystem.SwapBuffers();
// デフォルトで下画面に描画するもの
renderSystem.SetRenderTarget(common::GetRenderTarget(NN_GX_DISPLAY1, flip));
if(IsBackupSucceeded())
{
renderSystem.SetClearColor(common::GetRenderTarget(NN_GX_DISPLAY1, flip), SUCCESS_COLOR);
}
if(IsBackupWarning())
{
renderSystem.SetClearColor(common::GetRenderTarget(NN_GX_DISPLAY1, flip), WARN_COLOR);
}
else if(IsBackupFailed())
{
renderSystem.SetClearColor(common::GetRenderTarget(NN_GX_DISPLAY1, flip), FAIL_COLOR);
}
renderSystem.Clear();
renderSystem.SetColor(1.f, 1.f, 1.f);
common::Logger::GetLoggerInstance()->DrawConsole();
renderSystem.SwapBuffers();
renderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
// 電源長押しで終了
if ( nn::applet::IsExpectedToCloseApplication())
{
common::Logger::GetLoggerInstance()->Finalize();
// アンマウント
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
nn::fs::Unmount(common::SDMC_ARCHIVE_NAME);
renderSystem.Finalize();
nn::ps::Finalize();
nn::ptm::CTR::FinalizeForSystemMenu();
nn::cfg::CTR::system::Finalize();
nn::cfg::CTR::init::Finalize();
nn::hid::Finalize();
nn::fs::Finalize();
nn::applet::PrepareToCloseApplication();
nn::applet::CloseApplication();
}
}
}
}

View File

@ -0,0 +1,45 @@
BasicInfo:
Title : ConsoleBackup
ProductCode: CTR-P-22TA
BackupMemoryType: None
TitleInfo:
Use: Evaluation
Category: Application
UniqueId: 0xf8021
Version: 0
SystemControlInfo:
AppType : Application
StackSize : 0x4000
Dependency :
- codec
- hid
- gsp
- nwm
AccessControlInfo:
Priority : 16
DisableDebug : true
FileSystemAccess:
- DirectSdmc
- Debug
- Core
- CategoryFileSystemTool
- ExportImportIvs
IoAccessControl:
- FsMountCardSpi
- FsMountNand
- FsMountTwln
Option:
FreeProductCode: true
CardInfo:
CardDevice: None
Rom:
# ROM に含めるファイルシステムのルートパスを指定します。
HostRoot: "$(ROMFS_ROOT)"

View File

@ -0,0 +1,508 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Controller.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 "Controller.h"
#include "FileChecker.h"
#include "Exporter.h"
#include "SimplePlayer.h"
#include "CommonLogger.h"
#include "Checker.h"
#include "FileTransfer.h"
#include <nn.h>
namespace ConsoleBackup
{
namespace
{
typedef enum BackupState
{
STARTUP, // 初期値
CHECK_SAVEDATA, // セーブデータの確認
EXPORT_TWL_NAND, // TWLセーブデータ領域の吸出し中
EXPORT_TWL_SOUND, // TWLサウンド領域の吸出し中
EXPORT_TWL_PHOTO, // TWL写真領域の吸出し中
EXPORT_CTR_NAND, // 吸出し中
DELETE_NIM, // nimのシステムセーブデータ削除
DONE, // 吸出し完了
FINISHED, // SDカード抜き完了
FAIL, // 失敗
FAIL_CHECK, // セーブデータのチェック時エラー
STATE_MAX
} BackupState;
// Backupモード管理
BackupMode s_BackupMode = BACKUP_MODE_CHECK;
// APSettingの書式が無い警告サウンドを鳴らしたかどうか
bool s_ExistAPSettingAnnotation = false;
// SDに書き込みできない警告サウンドを鳴らしたかどうか
bool s_SdWriteProetctAnnotation = false;
BackupState s_BackupState = STARTUP;
bool s_PlayedStartCursor = false;
bool s_PlayedSdPullOutCursor = false;
bool s_PlayedFinishedSound = false;
bool s_PlayedFailSound = false;
} // namespace <unnamed>
void PutAliveMessage(::std::vector<std::string>& operationMessage, const char* str)
{
std::string message = std::string(str);
static u8 i = 0;
if (i < 0xff / 4)
{
operationMessage.push_back(message + std::string(" /"));
}
else if (i < 0xff * 2 / 4)
{
operationMessage.push_back(message + std::string(" |"));
}
else if (i < 0xff * 3 / 4)
{
operationMessage.push_back(message + std::string(" \\"));
}
else
{
operationMessage.push_back(message + std::string(" -"));
}
i += 4;
}
bool NeedsAcAdapter(common::HardwareStateManager& manager)
{
return manager.IsBatteryLower() && !manager.IsAdapterConnected();
}
void ControlState(common::HardwareStateManager& manager, ::std::vector<std::string>& operationMessage, bool& nextStep,
bool& continueBackup, bool forceDelete)
{
// 状態遷移Controller
switch (s_BackupState)
{
// 起動時
case STARTUP:
{
bool error = false;
// 完全性検証SEEDを読めるか
if (manager.CanReadIvs())
{
// SDカードが挿入されているか
if (nn::fs::IsSdmcInserted())
{
// SDカードに書き込みできるか
if (!nn::fs::IsSdmcWritable())
{
if (!s_SdWriteProetctAnnotation)
{
s_SdWriteProetctAnnotation = true;
common::PlaySound(common::SOUND_ANNOTATION);
}
operationMessage.push_back(::std::string("Can*t Write SD Card!!\n"));
break;
}
// 無線設定ファイルがあるか?
if (common::ExistsAPSetting())
{
// 書き込み中に抜かないように
if (nextStep)
{
// シリアルナンバーを読み取れるか?
if (!manager.CanReadSerialNumber())
{
common::PlaySound(common::SOUND_ANNOTATION);
COMMON_LOGGER("Can't Read Serial Number\n");
}
}
}
else
{
error = true;
if (!s_ExistAPSettingAnnotation)
{
s_ExistAPSettingAnnotation = true;
common::PlaySound(common::SOUND_ANNOTATION);
}
operationMessage.push_back(::std::string("Accsess_Point_Setting does not exist!"));
}
}
else
{
error = true;
operationMessage.push_back(::std::string("Insert SD Card!!"));
}
}
else
{
error = true;
operationMessage.push_back(::std::string("Can't Read SDCI!!"));
}
// ACアダプタが必要か
if (NeedsAcAdapter(manager))
{
error = true;
operationMessage.push_back(::std::string("Connect AC Adapter!!"));
}
// エラーが無ければ進行用メッセージ表示
if (!error)
{
operationMessage.push_back(::std::string("Push A or START Button"));
if (!s_PlayedStartCursor)
{
common::PlaySound(common::SOUND_CURSOR);
s_PlayedStartCursor = true;
}
}
if (nextStep && !error)
{
COMMON_LOGGER("Checking SaveData\n");
if(forceDelete)
{
s_BackupMode = BACKUP_MODE_DELETE_IF_FAILED;
}
s_BackupState = CHECK_SAVEDATA;
}
}
break;
case CHECK_SAVEDATA:
{
static bool init = true;
if (init)
{
StartSaveDataCheck(s_BackupMode == BACKUP_MODE_DELETE_IF_FAILED);
init = false;
}
PutAliveMessage(operationMessage, "Checking SaveData");
if (IsCheckSaveDataFinished())
{
FinalizeSaveDataCheck();
// 削除モードでなければエラーにする
if (CheckSaveDataErrorOccured() && !forceDelete)
{
s_BackupState = FAIL_CHECK;
}
else
{
if (CheckSaveDataSucceeded())
{
COMMON_LOGGER("Start Export Data\n");
s_BackupState = EXPORT_TWL_NAND;
}
else
{
s_BackupState = FAIL;
}
}
}
}
break;
// TWLセーブデータ領域の吸出し中
case EXPORT_TWL_NAND:
{
static bool init = true;
if (init)
{
// コンテキストを初期化する
InitializeFileListContext();
// データを書き込む
if (ExportTwlSaveData().IsFailure())
{
s_BackupState = FAIL;
break;
}
init = false;
}
PutAliveMessage(operationMessage, "Exporting TWL SaveData");
// 処理が完了した
if (IsExportThreadFinished())
{
FinalizeExportThread();
if (IsExportSucceeded())
{
s_BackupState = EXPORT_TWL_SOUND;
}
else
{
s_BackupState = FAIL;
}
}
}
break;
// TWLサウンド領域の吸出し中
case EXPORT_TWL_SOUND:
{
static bool init = true;
if (init)
{
// データを書き込む
ExportTwlSoundData();
init = false;
}
PutAliveMessage(operationMessage, "Exporting TWL Sound Data");
// 処理が完了した
if (IsExportThreadFinished())
{
FinalizeExportThread();
if (IsExportSucceeded())
{
s_BackupState = EXPORT_TWL_PHOTO;
}
else
{
s_BackupState = FAIL;
}
}
}
break;
// TWL写真領域の吸出し中
case EXPORT_TWL_PHOTO:
{
static bool init = true;
if (init)
{
// データを書き込む
ExportTwlPhotoData();
init = false;
}
PutAliveMessage(operationMessage, "Exporting TWL Photo Data");
// 処理が完了した
if (IsExportThreadFinished())
{
FinalizeExportThread();
if (IsExportSucceeded())
{
s_BackupState = EXPORT_CTR_NAND;
}
else
{
s_BackupState = FAIL;
}
}
}
break;
// 吸出し中
case EXPORT_CTR_NAND:
{
continueBackup = true;
// ACアダプタが必要か
if (NeedsAcAdapter(manager))
{
continueBackup = false;
operationMessage.push_back(::std::string("Connect AC Adapter!!"));
}
PutAliveMessage(operationMessage, "Exporting Nand Data");
// データを書き込む
if (!ExportData(manager))
{
s_BackupState = FAIL;
}
else
{
// 処理が完了した
if (continueBackup && IsExportThreadFinished())
{
FinalizeExportThread();
if (IsExportSucceeded())
{
COMMON_LOGGER("Export NAND Data Finished.\n");
if (GetExportProgress() > 99)
{
s_BackupState = DELETE_NIM;
}
else
{
s_BackupState = FAIL;
}
}
else
{
s_BackupState = FAIL;
}
}
}
}
break;
// nimのシステムセーブデータ削除
case DELETE_NIM:
{
if (DeleteNimSaveData())
{
s_BackupState = DONE;
}
else
{
s_BackupState = FAIL;
}
}
break;
// 吸出し完了
case DONE:
{
operationMessage.push_back(::std::string("Backup Done. Pull Out SD Card."));
if (!s_PlayedSdPullOutCursor)
{
common::PlaySound(common::SOUND_CURSOR);
s_PlayedSdPullOutCursor = true;
}
}
break;
// SDカード抜き完了
case FINISHED:
{
operationMessage.push_back(::std::string("Backup Succeeded!!\n"));
if (!s_PlayedFinishedSound)
{
common::PlaySound(common::SOUND_OK);
s_PlayedFinishedSound = true;
}
}
break;
// 吸出し失敗
case FAIL:
{
operationMessage.push_back(::std::string("Backup Failed."));
if (!s_PlayedFailSound)
{
common::PlaySound(common::SOUND_NG);
s_PlayedFailSound = true;
}
}
break;
case FAIL_CHECK:
{
operationMessage.push_back(::std::string("Check Error."));
if (!s_PlayedFailSound)
{
common::PlaySound(common::SOUND_NG);
s_PlayedFailSound = true;
}
}
break;
}
}
u32 GetProgress()
{
if(s_BackupState == CHECK_SAVEDATA)
{
return GetCheckSaveDataProgress();
}
else if (s_BackupState == EXPORT_TWL_NAND || s_BackupState == EXPORT_TWL_PHOTO|| s_BackupState == EXPORT_TWL_SOUND)
{
return common::GetProgress();
}
else
{
return GetExportProgress();
}
}
// バックアップモードを取得する
BackupMode GetBackupMode()
{
return s_BackupMode;
}
bool InProgress()
{
return s_BackupState == EXPORT_CTR_NAND;
}
bool IsBackupSucceeded()
{
return s_BackupState == FINISHED;
}
bool IsBackupFailed()
{
return s_BackupState == FAIL;
}
bool IsBackupWarning()
{
return s_BackupState == FAIL_CHECK;
}
void OnSdEjected()
{
if(s_BackupState == DONE || s_BackupState == FINISHED)
{
s_BackupState = FINISHED;
}
else if(s_BackupState != FAIL && s_BackupState != FAIL_CHECK)
{
common::InitializeFileCheck();
InitializeState();
}
}
void OnSdInserted()
{
common::Logger::GetLoggerInstance()->ClearSdLog();
}
void InitializeState()
{
s_BackupState = STARTUP;
s_PlayedFailSound = false;
s_PlayedFinishedSound = false;
s_ExistAPSettingAnnotation = false;
s_PlayedStartCursor = false;
s_PlayedSdPullOutCursor = false;
s_SdWriteProetctAnnotation = false;
}
} // namespace ConsoleBackup

View File

@ -0,0 +1,71 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Contoroller.h
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$
*---------------------------------------------------------------------------*/
#ifndef CONTOROLLER_H_
#define CONTOROLLER_H_
#include <vector>
#include <string>
#include "HardwareStateManager.h"
namespace ConsoleBackup
{
typedef enum BackupMode
{
BACKUP_MODE_CHECK, // セーブデータのチェック後エラーが無ければ吸出し
BACKUP_MODE_DELETE_IF_FAILED // 読み取りエラーのセーブデータを削除後吸出し
} BackupMode;
//! @brief 状態遷移を管理する
//! @param[in] manager ハードウェア情報を取得するためのラッパ
//! @param[in] operationMessage 操作情報として表示したい文字列
//! @param[in] nextStep 次の状態に遷移してもよいかどうか
//! @param[in] continueBackup 処理を続けてもよいかどうか
//! @param[in] forceDelete チェックエラー発生時に削除を実行してもよいかどうか
void ControlState(common::HardwareStateManager& manager, ::std::vector<std::string>& operationMessage, bool& nextStep,
bool& continueBackup, bool forceDelete);
// バックアップ処理中かどうか
bool InProgress();
// バックアップが完了したかどうか
bool IsBackupSucceeded();
// バックアップが失敗したかどうか
bool IsBackupFailed();
// バックアップ時に警告があったかどうか
bool IsBackupWarning();
// SDカードが抜き出されたときに実行したい関数
void OnSdEjected();
// SDカードが挿し込まれたときに実行する処理
void OnSdInserted();
// 状態を初期化する
void InitializeState();
// 進捗を取得する
u32 GetProgress();
// バックアップモードを取得する
BackupMode GetBackupMode();
}
#endif /* CONTOROLLER_H_ */

View File

@ -0,0 +1,974 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Exporter.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 <vector>
#include <cstdlib>
#include <cwchar>
#include <string>
#include <cstdlib>
#include <nn/nstd.h>
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/fs/fs_ApiDeviceMove.h>
#include <nn/cfg/CTR/cfg_Api.h>
#include <nn/cfg/CTR/cfg_ApiNor.h> // cfg:norの初期化に必要
#include <nn/cfg/CTR/cfg_NtrSettings.h>
#include <nn/ps/CTR/ps_API.h>
#include <nn/drivers/aes/CTR/ARM946ES/driverAes_Types.h>
#include <nn/crypto/crypto_AesCmac.h>
#include <nn/crypto/crypto_SwAesCtrContext.h>
#include <nn/crypto/crypto_Sha256.h>
#include <nn/crypto/crypto_SwAesCmac.h>
#include <nn/mcu.h>
#include <nn/am.h>
#include <nn/pl/CTR/pl_PlayHistoryApi.h>
#include <nn/pl/CTR/pl_PlayHistoryApiSysmenu.h>
#include "Exporter.h"
#include "CommonLogger.h"
#include "SDMountManager.h"
#include "HeapManager.h"
#include "SdReaderWriter.h"
#include "FileName.h"
#include "FileTransfer.h"
#include "common_Types.h"
#include "Aes_define.h"
#include "VersionDetect.h"
#include "Util.h"
#include "SaveDataMover.h"
namespace ConsoleBackup
{
namespace
{
common::NtrNorData s_NtrNorData;
common::CfgCountryLanguage s_CountryLanguage;
const size_t EXPORT_THREAD_STACK_SIZE = 0x4000;
nn::os::Thread s_ExportThread;
nn::os::StackBuffer<EXPORT_THREAD_STACK_SIZE> s_ExportThreadStack;
bool s_IsExportSucceeded;
wchar_t s_RootName[256];
nn::crypto::Sha256Context s_FileListContext;
u64 s_ExportProgress = 0;
}
bool AddCmac(nn::fs::FileOutputStream* file, nn::crypto::Sha256Context* context);
nn::Result DeleteTrash(std::wstring currentDirectory)
{
// TODO: リードオンリーのファイルが消去できない
COMMON_LOGGER("Delete Trash.\n");
nn::fs::FileInputStream fis;
nn::fs::Directory dir;
nn::Result result;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = dir.TryInitialize(currentDirectory.c_str());
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
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_RETURN_RESULT_IF_FAILED(result);
}
// ファイルならログとAP設定以外は削除する
else
{
if (std::wcscmp(entryIndex->entryName, common::AP_SETTING_FILENAME) != 0
&& std::wcscmp(entryIndex->entryName, common::LOG_FILENAME) != 0)
{
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_RETURN_RESULT_IF_FAILED(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);
}
}
}
result = common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
return nn::ResultSuccess();
}
nn::Result WriteTwlTitleList(std::vector<std::wstring>& programIdList)
{
nn::Result result;
COMMON_LOGGER("Export TwlTitle List.\n");
size_t heapSize = common::GetAllocatableSize();
if(heapSize > common::FILE_COPY_HEAP_SIZE)
{
heapSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager manager(heapSize);
char* titleListBuf = reinterpret_cast<char*> (manager.GetAddr());
size_t writeSize = 0;
if (titleListBuf != NULL)
{
for (std::vector<std::wstring>::iterator it = programIdList.begin(); it != programIdList.end(); it++)
{
nn::nstd::TSNPrintf(titleListBuf + writeSize, heapSize - writeSize, "%s\n", common::GetCharStr(it->c_str()));
NN_LOG("%ls\n", it->c_str());
writeSize += it->size() + sizeof('\n');
}
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::TWL_TITLELIST_PATHNAME, titleListBuf, writeSize);
}
else
{
return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
}
nn::Result WriteRegionData()
{
COMMON_LOGGER("Export Region Data.\n");
nn::cfg::CTR::CfgRegionCode region;
region = nn::cfg::CTR::GetRegion();
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::REGION_DATA_PATHNAME, &region, sizeof(nn::cfg::CTR::CfgRegionCode));
}
nn::Result WriteCountryLanguageData()
{
COMMON_LOGGER("Export Country and Language Data.\n");
nn::Result result;
nn::cfg::nor::CTR::Initialize();
// 国設定
s_CountryLanguage.country = nn::cfg::CTR::GetCountry();
if (s_CountryLanguage.country != nn::cfg::CTR::CFG_COUNTRY_UNKNOWN)
{
// 言語設定
s_CountryLanguage.language = nn::cfg::CTR::GetLanguage();
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::COUNTRY_SETTING_PATHNAME, &s_CountryLanguage, sizeof(s_CountryLanguage));
}
return nn::ResultSuccess();
}
nn::Result WriteNorData()
{
COMMON_LOGGER("Export NOR Data.\n");
nn::Result result;
nn::cfg::nor::CTR::Initialize();
NN_LOG("Get NTR User Setting\n");
// NTR設定
result = nn::cfg::nor::CTR::GetNtrSetting(&s_NtrNorData.ntrConfig.ncd, &s_NtrNorData.ntrConfig.ncd_ex);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// TWL WiFi設定
result = nn::cfg::nor::CTR::ReadTwlWifiSetting(0, s_NtrNorData.TwlWiFiSetting, common::TWL_WIFI_SETTING_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// NTR WiFi設定
result = nn::cfg::nor::CTR::ReadNtrWifiSetting(0, s_NtrNorData.NtrWiFiSetting, common::NTR_WIFI_SETTING_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::NOR_PATHNAME, &s_NtrNorData, sizeof(common::NtrNorData));
}
nn::Result WriteSerialNumber(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export Serial Number.\n");
u8* serial;
size_t size;
manager.GetSerialNumber(&serial, &size);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::SERIAL_PATHNAME, serial, size);
}
nn::Result WriteDeviceId(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export Device ID.\n");
bit32 deviceId = manager.GetDeviceId();
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::DEVICE_ID_PATHNAME, &deviceId, sizeof(deviceId));
}
nn::Result WriteIvs(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export SDCI.\n");
void* ivs;
size_t size;
manager.GetIvs(&ivs, &size);
void* enc;
nn::Result result;
common::HeapManager ivsHeap(size);
enc = ivsHeap.GetAddr();
if(enc != NULL)
{
// AES暗号化する
nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key));
swAesCtrContest.Encrypt(enc, ivs, size);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::IVS_PATHNAME, enc, size);
}
else
{
return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
}
void CreateTwlDirectory(enum common::TWL_PATH_INDEX path)
{
NN_ASSERT(path < common::TWL_PATHNAME_MAX);
common::SdReaderWriter sdWriter;
sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) +
std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str());
}
bool ListTwlSaveData(std::wstring currentDirectory, std::vector<common::SavePathInfo>* list)
{
nn::fs::Directory dir;
nn::fs::DirectoryEntry entry;
s32 numEntry;
nn::Result result = dir.TryInitialize(currentDirectory.c_str());
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (numEntry == 0)
{
break;
}
else
{
common::SavePathInfo pathInfo;
pathInfo.name = currentDirectory + std::wstring(L"/") + std::wstring(entry.entryName);
pathInfo.isDirectory = false;
list->push_back(pathInfo);
}
}
return true;
}
void AddCurrentProgramIdPath(std::vector<std::wstring>* programIdList, std::wstring currentDir)
{
std::wstring currentPath(currentDir);
std::wstring token(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH);
std::wstring::size_type pos;
pos = currentPath.find(token);
if(pos != std::wstring::npos)
{
std::wstring subStr = currentPath.substr(token.size());
std::wstring slash(L"/");
pos = subStr.find(slash);
while(pos != std::wstring::npos)
{
subStr.erase(pos, slash.size());
pos = subStr.find(slash);
}
std::wstring ctrProgramIdHi(L"00048");
subStr.replace(0, ctrProgramIdHi.size(), ctrProgramIdHi);
programIdList->push_back(subStr);
}
else
{
NN_LOG("Can't find %ls\n", common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH);
}
}
void AddCurrentDirectory(std::vector<common::SavePathInfo>* list, std::wstring currentDir, wchar_t* currentEntry)
{
common::SavePathInfo pathInfo;
pathInfo.name = currentDir + std::wstring(L"/") + std::wstring(currentEntry) + std::wstring(L"/");
pathInfo.isDirectory = true;
list->push_back(pathInfo);
}
// TWLセーブデータが存在するディレクトリの一覧をlistに追加する
// return: dataディレクトリが存在するかどうか
bool ListTwlSaveDataDirectory(std::wstring currentDirectory, u32 level, std::vector<common::SavePathInfo>* list,
std::vector<std::wstring>* programIdList)
{
nn::fs::FileInputStream fis;
nn::fs::Directory dir;
nn::Result result;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
// level 0 1 2
// twln:/title/00030005/484e4441/data/
const u8 TWL_SAVEDATA_DIRECTORY_LEVEL = 2; // data ディレクトリまでの階層
const wchar_t* const TWL_SAVEDATA_DIRECTORY_NAME = L"data";
result = dir.TryInitialize(currentDirectory.c_str());
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (numEntry == 0)
{
dir.Finalize();
bool hasDataDirectory = false;
for (entryIndex = entryList.begin(); entryIndex != entryList.end(); entryIndex++)
{
// レベル2未満のディレクトリなら再帰的に開く
if (level < TWL_SAVEDATA_DIRECTORY_LEVEL)
{
if (entryIndex->attributes.isDirectory)
{
if (!ListTwlSaveDataDirectory(
currentDirectory + std::wstring(L"/") + std::wstring(entryIndex->entryName), level + 1,
list, programIdList))
{
hasDataDirectory |= false;
}
else
{
NN_LOG("%ls/%ls has data directory.\n", currentDirectory.c_str(), entryIndex->entryName);
AddCurrentDirectory(list, currentDirectory, entryIndex->entryName);
hasDataDirectory |= true;
}
}
}
// レベル2のディレクトリなら data かどうかチェック
else if (level == TWL_SAVEDATA_DIRECTORY_LEVEL && entryIndex->attributes.isDirectory)
{
if (std::wcscmp(entryIndex->entryName, TWL_SAVEDATA_DIRECTORY_NAME) == 0)
{
// ファイル一覧を取得する
if (!ListTwlSaveData(
currentDirectory + std::wstring(L"/") + std::wstring(entryIndex->entryName), list))
{
hasDataDirectory |= false;
}
NN_LOG("%ls/%ls has data directory.\n", currentDirectory.c_str(), entryIndex->entryName);
AddCurrentDirectory(list, currentDirectory, entryIndex->entryName);
AddCurrentProgramIdPath(programIdList, currentDirectory);
hasDataDirectory |= true;
}
}
else
{
return false;
}
}
return hasDataDirectory;
}
else
{
// vectorに保存する
entryList.push_back(entry);
}
}
}
void WriteTwlData(enum common::TWL_PATH_INDEX path)
{
NN_ASSERT(path < common::TWL_PATHNAME_MAX);
nn::Result result;
s_IsExportSucceeded = true;
result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[path], common::TWL_FS_ARCHIVE_KIND[path]);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
u32 fileNum = 0;
s64 fileSize = 0;
result = common::CalculateFileNum(::std::wstring(common::NAND_TWL_ROOT_PATHNAME_WITH_SLASH_TABLE[path]), fileNum, fileSize);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
NN_LOG("File Number = %d\n", fileNum);
NN_LOG("File Size = %lld\n", fileSize);
// 進捗表示用
common::InitializeTransferProgress(fileSize);
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
NN_LOG("AllocatableSize = %d\n", bufSize);
if(bufSize > common::FILE_COPY_HEAP_SIZE)
{
bufSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager writeHeap(bufSize, AES_BLOCK_SIZE * 2);
void* buf = writeHeap.GetAddr();
if (buf != NULL)
{
nn::fs::FileOutputStream list;
result = list.TryInitialize(common::FILE_LIST_PATHNAME, true);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsSuccess())
{
result = list.TryGetSize(&fileSize);
if (result.IsSuccess())
{
// 末尾に移動
result = list.TrySetPosition(fileSize);
if (result.IsSuccess())
{
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);
if(!common::CopyDirectory(
NULL,
(archiveString + ::std::wstring(L"/")).c_str(),
(common::SDMC_ROOT_DIRECTORY_PATH + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(),
buf, bufSize, true, &list, &s_FileListContext))
{
s_IsExportSucceeded = false;
return;
}
}
list.TryFlush();
list.Finalize();
}
}
else
{
s_IsExportSucceeded = false;
}
}
common::SdMountManager::Unmount();
nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[path]);
}
nn::Result CalculateTwlSaveData(std::vector<common::SavePathInfo>* fileList, s64* fileSize)
{
NN_NULL_ASSERT(fileList);
NN_NULL_ASSERT(fileSize);
*fileSize = 0;
nn::Result result = nn::ResultSuccess();
for (std::vector<common::SavePathInfo>::iterator it = fileList->begin(); it != fileList->end(); it++)
{
if(!it->isDirectory)
{
nn::fs::FileInputStream file;
result = file.TryInitialize(it->name.c_str());
if(result.IsSuccess())
{
s64 size;
result = file.TryGetSize(&size);
if(result.IsSuccess())
{
*fileSize += size;
}
}
}
}
return result;
}
void WriteTwlSaveData()
{
nn::Result result;
s_IsExportSucceeded = true;
std::vector<common::SavePathInfo> fileList;
std::vector<std::wstring> programIdList;
COMMON_LOGGER("Export Twl Save Data.\n");
// ディレクトリ作成
common::SdReaderWriter sdWriter;
result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) +
std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str());
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
// セーブデータを含むディレクトリ一覧を生成
result = nn::fs::MountSpecialArchive(common::NAND_TWL_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_TWL_NAND);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
if(!ListTwlSaveDataDirectory(std::wstring(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH), 0, &fileList, & programIdList))
{
NN_LOG("No Twl Savedata\n");
s_IsExportSucceeded = true;
return;
}
NN_LOG("listup Twl Savedata Directory\n");
for (std::vector<common::SavePathInfo>::reverse_iterator it = fileList.rbegin(); it != fileList.rend(); it++)
{
NN_LOG("%ls\n", it->name.c_str());
}
result = WriteTwlTitleList(programIdList);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
// 合計サイズ取得
s64 fileSize;
result = CalculateTwlSaveData(&fileList, &fileSize);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
common::InitializeTransferProgress(fileSize);
NN_LOG("\n");
// SDに書き出し
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
NN_LOG("AllocatableSize = %d\n", bufSize);
if(bufSize > common::FILE_COPY_HEAP_SIZE)
{
bufSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager writeHeap(bufSize, AES_BLOCK_SIZE * 2);
void* buf = writeHeap.GetAddr();
if (buf != NULL)
{
nn::fs::FileOutputStream list;
result = list.TryInitialize(common::FILE_LIST_PATHNAME, true);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
result = list.TryGetSize(&fileSize);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
// 末尾に移動
result = list.TrySetPosition(fileSize);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
wchar_t archiveName[nn::fs::MAX_FILE_PATH_LENGTH];
::std::mbstowcs(archiveName, common::NAND_TWL_ARCHIVE_NAME, std::strlen(common::NAND_TWL_ARCHIVE_NAME) + 1);
std::wstring archiveString(archiveName);
for (std::vector<common::SavePathInfo>::reverse_iterator it = fileList.rbegin(); it != fileList.rend(); it++)
{
// twln:/title/をsdmc:/CTR_Console_Repair/TWLBackup/に置換
std::wstring toPath(it->name.c_str());
toPath.replace(0, std::wcslen(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH) + 1,
std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME));
if (it->isDirectory)
{
if(!common::ExportTwlSaveDirectory(toPath.c_str(), &list, &s_FileListContext))
{
s_IsExportSucceeded = false;
return;
}
}
else
{
if(!common::ExportTwlSaveFile(it->name.c_str(), toPath.c_str(), buf, bufSize, &list, &s_FileListContext))
{
s_IsExportSucceeded = false;
return;
}
}
}
result = list.TryFlush();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
list.Finalize();
}
result = common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
result = nn::fs::Unmount(common::NAND_TWL_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
}
void WriteTwlPhotoData()
{
COMMON_LOGGER("Export Twl Photo Data.\n");
CreateTwlDirectory(common::TWL_PHOTO);
WriteTwlData(common::TWL_PHOTO);
}
void WriteTwlSoundData()
{
COMMON_LOGGER("Export Twl Sound Data.\n");
CreateTwlDirectory(common::TWL_SOUND);
WriteTwlData(common::TWL_SOUND);
}
void InitializeFileListContext()
{
s_FileListContext.Initialize();
}
nn::Result ExportTwlSaveData()
{
// 不要なデータを削除する
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
DeleteTrash((std::wstring(common::LOG_ROOT_DIRECTORY_PATH) + std::wstring(L"/")).c_str()));
s_ExportThread.Start(WriteTwlSaveData, s_ExportThreadStack);
return nn::ResultSuccess();
}
void ExportTwlPhotoData()
{
s_ExportThread.Start(WriteTwlPhotoData, s_ExportThreadStack);
}
void ExportTwlSoundData()
{
s_ExportThread.Start(WriteTwlSoundData, s_ExportThreadStack);
}
nn::Result WriteMcuRtcData(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export RTC Data.\n");
nn::Result result;
nn::Handle handle = manager.GetMcuHandle();
if(handle.IsValid())
{
nn::mcu::CTR::HwCheck mcu(handle);
nn::mcu::CTR::RtcData rtc;
const u8 RETRY = 10;
for (u8 i = 0; i < RETRY; i++)
{
result = mcu.GetRtcAll(&rtc);
if (result.IsSuccess())
{
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);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::MCU_RTC_PATHNAME, &rtc, sizeof(rtc));
}
nn::os::Thread::Sleep(
nn::fnd::TimeSpan::FromMilliSeconds(
nn::os::Tick::GetSystemCurrent().ToTimeSpan().GetMilliSeconds() % 100));
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
else
{
NN_LOG("invalid handle\n");
return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_INVALID_HANDLE);
}
return nn::ResultSuccess();
}
bool AddCmactoExportFileList()
{
nn::Result result;
nn::fs::FileOutputStream list;
result = list.TryInitialize(common::FILE_LIST_PATHNAME, true);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
s64 fileSize = 0;
result = list.TryGetSize(&fileSize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 末尾に移動
result = list.TrySetPosition(fileSize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return AddCmac(&list, &s_FileListContext);
}
void ExportThreadFunc()
{
nn::Result result;
s_IsExportSucceeded = true;
result = common::SdMountManager::Mount();
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
NN_LOG("AllocatableSize = %d\n", bufSize);
if(bufSize > common::FILE_COPY_HEAP_SIZE)
{
bufSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager writeHeap(bufSize, AES_BLOCK_SIZE * 2);
void* buf = writeHeap.GetAddr();
if (buf != NULL)
{
common::SaveDataMover saveDataMover;
saveDataMover.StartExport(buf, bufSize, &s_ExportProgress);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(
saveDataMover.GetLastResult(), s_IsExportSucceeded
);
}
// FileListにCMACを付加する
if(!AddCmactoExportFileList())
{
s_IsExportSucceeded = false;
}
common::SdMountManager::Unmount();
NN_LOG("Export Thread Finalize\n");
}
nn::Result WriteSaveData()
{
// NANDからSDカードに書き出し
nn::Result result;
// セーブデータディレクトリ以下のデータをSDカードにコピー
// コピー用ディレクトリ作成
common::SdReaderWriter sdWriter;
result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(
common::SD_SAVEDATA_ROOT_NAME)).c_str());
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
COMMON_LOGGER("Export NAND Data Start...\n");
// SDにコピーするためのスレッドの作成
s_ExportThread.Start(ExportThreadFunc, s_ExportThreadStack);
return result;
}
void FinalizeExportThread()
{
s_ExportThread.Join();
s_ExportThread.Finalize();
}
nn::Result WriteVersionData(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export Version Data.\n");
common::VerDef versionData;
manager.GetVersionData(&versionData);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::VERSION_DATA_PATHNAME, &versionData, sizeof(common::VerDef));
}
bool DeleteNimSaveData()
{
nn::Result result;
::std::wstring nimSaveDataPath =
::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) +
::std::wstring(common::SD_SAVEDATA_ROOT_NAME) +
::std::wstring(s_RootName) +
::std::wstring(L"/") +
std::wstring(common::NIM_SAVEDATA_DIRECTORY_NAME);
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
NN_LOG("%ls\n", nimSaveDataPath.c_str());
result = nn::fs::TryDeleteDirectoryRecursively(nimSaveDataPath.c_str());
if (result.IsFailure() && !nn::fs::ResultNotFound::Includes(result))
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return false;
}
result = common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return true;
}
void AddShutDownPtmEvent()
{
nn::pl::CTR::NotifyPlayEvent(nn::pl::CTR::EVENTTYPE_TERMINATE, nn::CTR::INVALID_PROGRAM_ID,
nn::fnd::DateTime::GetNow());
}
bool ExportData(common::HardwareStateManager& manager)
{
static bool init = true;
if (init)
{
nn::Result result;
// 電源断の履歴をptmに追加する
AddShutDownPtmEvent();
// リージョンデータをSDに書き込む
result = WriteRegionData();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 国データと言語データをSDに書き込む
result = WriteCountryLanguageData();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// NORデータをSDカードに書き込む
result = WriteNorData();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// シリアルナンバーをSDカードに書き込む
result = WriteSerialNumber(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// デバイスIDをSDカードに書き込む
result = WriteDeviceId(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 完全性検証SEEDをSDカードに書き込む
result = WriteIvs(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// RTCをSDに書き出す
result = WriteMcuRtcData(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// バージョン情報をSDに書き出す
result = WriteVersionData(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// NANDのセーブデータをSDに書き出す
result = WriteSaveData();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
init = false;
}
return true;
}
u32 GetExportProgress()
{
return s_ExportProgress;
}
bool IsExportThreadFinished()
{
return s_ExportThread.IsValid() && !s_ExportThread.IsAlive();
}
bool IsExportSucceeded()
{
return s_IsExportSucceeded;
}
//!@ brief ファイルにSHA256から計算したAES-CMACを付加します
//!@ param[in] file CMACを付加したいInitialize済みのファイル
//!@ param[in] context CMAC計算元のSHA256コンテキスト
bool AddCmac(nn::fs::FileOutputStream* file, nn::crypto::Sha256Context* context)
{
nn::Result result;
bit8 sha256Hash[nn::crypto::Sha256Context::HASH_SIZE];
context->GetHash(sha256Hash);
bit8 cmac[nn::crypto::AES_CMAC_MAC_SIZE];
result = nn::crypto::CalculateAesCmacSw(cmac, sha256Hash, nn::crypto::Sha256Context::HASH_SIZE, common::cmacKey);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
s32 writeSize;
result = file->TryWrite(&writeSize, cmac, sizeof(cmac), false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = file->TryFlush();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return true;
}
}

View File

@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Exporter.h
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$
*---------------------------------------------------------------------------*/
#ifndef EXPORTER_H_
#define EXPORTER_H_
#include <nn.h>
#include "HardwareStateManager.h"
namespace ConsoleBackup
{
// 出力ファイルリストのコンテキストを初期化する。出力ファイルリストを
// 生成する前に必ず呼び出す必要がある
void InitializeFileListContext();
// 新たにスレッドを起動して、DSiWareのセーブデータをSDカードに出力する
nn::Result ExportTwlSaveData();
// 新たにスレッドを起動して、TWL写真領域のデータをSDカードに出力する
void ExportTwlPhotoData();
// 新たにスレッドを起動して、TWLサウンド領域のデータをSDカードに出力する
void ExportTwlSoundData();
// 本体固有情報をSDカードに出力する
// 新たにスレッドを起動して、CTR領域のセーブデータをSDカードに出力する
bool ExportData(common::HardwareStateManager& manager);
// NIMのセーブデータをSDカードから削除する
bool DeleteNimSaveData();
// 出力スレッドの進捗を返す
u32 GetExportProgress();
// 出力スレッドが終了したかどうか
bool IsExportThreadFinished();
// 出力スレッドを終了する
void FinalizeExportThread();
// 出力が成功したかどうか
bool IsExportSucceeded();
}
#endif /* EXPORTER_H_ */

View File

@ -0,0 +1,75 @@
#!/usr/bin/env omake
#----------------------------------------------------------------------------
# Project: Horizon
# File: OMakefile
#
# Copyright (C)2009 Nintendo Co., Ltd. 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$
#----------------------------------------------------------------------------
SUPPORTED_TARGETS = CTR-T*.Process.MPCore.fast
CTR_APPTYPE = CARD
TARGET_PROGRAM = ConsoleBackup
SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include)
INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \
../common
SOURCES[] =
ConsoleBackup.cpp
Controller.cpp
Exporter.cpp
Checker.cpp
SavedataChecker.cpp
../common/Util.cpp
../common/DrawSystemState.cpp
../common/FileTransfer.cpp
../common/FileChecker.cpp
../common/SdReaderWriter.cpp
../common/HeapManager.cpp
../common/SdLogger.cpp
../common/wave.cpp
../common/SimplePlayer.cpp
../common/LogConsole.cpp
../common/CommonLogger.cpp
../common/SdMountManager.cpp
../common/VersionDetect.cpp
../common/ResFont.cpp
../common/HardwareStateManager.cpp
../common/SaveDataMover.cpp
CTR_BANNER_SPEC = $(TARGET_PROGRAM).bsf
ROMFS_ROOT = ../common/romfiles
SHADER_BIN = nnfont_RectDrawerShader.shbin
SHADER_PATH = $(ROMFS_ROOT)/$(SHADER_BIN)
ROMFS_DEPENDENCIES = $(SHADER_PATH)
LIBS += libnn_cfg \
libnn_crypto \
libnn_mcu \
libnn_i2c \
libnn_ps \
lib_demo \
libnn_nwm \
libnn_friends \
libnn_nim \
libnn_am \
INSTALL_SDK_TOOL = true
ROM_SPEC_FILE = $(TARGET_PROGRAM).rsf
DESCRIPTOR = $(HORIZON_ROOT)/resources/specfiles/private/RepairTool.desc
include $(ROOT_OMAKE)/modulerules
build: $(DEFAULT_TARGETS)

View File

@ -0,0 +1,481 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: NandSavedataChecker.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/fs/fs_ApiSysSaveData.h>
#include <nn/fs/fs_ApiSharedExtSaveData.h>
#include "SavedataChecker.h"
#include "CommonLogger.h"
#include "FileTransfer.h"
#include "FileName.h"
namespace ConsoleBackup
{
SavedataCheckerBase::SavedataCheckerBase(void* buf, size_t size) :
m_Buf(buf), m_Bufsize(size), m_CalculatedFileSize(0), m_TotalReadSize(0), m_CheckErrorOccured(false)
{
}
SavedataCheckerBase::~SavedataCheckerBase()
{
NN_LOG("m_TotalReadSize = %lld\n", m_TotalReadSize);
}
nn::Result SavedataCheckerBase::CleanUpFilesRecursively(bool* metaDataCrashed, bool* modified, std::string baseName,
std::wstring currentDirectory, bool erase)
{
nn::fs::Directory dir;
nn::fs::DirectoryEntry entry;
nn::Result result;
NN_LOG("%s\n", common::GetCharStr(currentDirectory.c_str()));
result = dir.TryInitialize(currentDirectory.c_str());
if (result.IsFailure())
{
COMMON_LOGGER_WARN(
"Error: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(currentDirectory).c_str()));
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
if (erase)
{
*metaDataCrashed = true;
}
return result;
}
for (;;)
{
s32 numRead;
result = dir.TryRead(&numRead, &entry, 1);
if (result.IsFailure())
{
dir.Finalize();
COMMON_LOGGER_WARN(
"Error: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(currentDirectory).c_str()));
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
if (erase)
{
*metaDataCrashed = true;
}
// ディレクトリの読み取りエラーなので再度読み取ってもエラーになる
return result;
}
if(numRead == 0)
{
break;
}
if (std::wcscmp(entry.entryName, L".") == 0 || std::wcscmp(entry.entryName, L"..") == 0)
{
continue;
}
// ディレクトリの場合
if (entry.attributes.isDirectory)
{
result = CleanUpFilesRecursively(metaDataCrashed, modified, baseName,
currentDirectory + std::wstring(entry.entryName) + std::wstring(L"/"), erase);
if(erase && result.IsFailure())
{
return result;
}
}
// ファイルの場合
else
{
nn::fs::FileInputStream file;
std::wstring filePath = (currentDirectory + std::wstring(entry.entryName)).c_str();
const wchar_t* path = filePath.c_str();
NN_LOG("%s\n", common::GetCharStr(path));
result = file.TryInitialize(path);
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED(result);
const bool silent = IsForceDeleteFile(common::GetCharStr(entry.entryName));
if(!silent)
{
COMMON_LOGGER_WARN("Error: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(filePath).c_str()));
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
}
if (erase || silent)
{
if(!silent)
{
COMMON_LOGGER_WARN("Deleting: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(filePath).c_str()));
}
result = nn::fs::TryDeleteFile(path);
*modified = true;
}
continue;
}
for (;;)
{
s32 readSize;
result = file.TryRead(&readSize, m_Buf, m_Bufsize);
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED(result);
const bool silent = IsForceDeleteFile(common::GetCharStr(entry.entryName));
if(!silent)
{
COMMON_LOGGER_WARN("Error: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(filePath).c_str()));
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
}
m_TotalReadSize += file.GetSize();
file.Finalize();
if (erase || silent)
{
if(!silent)
{
COMMON_LOGGER_WARN("Deleting: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(filePath).c_str()));
}
result = nn::fs::TryDeleteFile(path);
COMMON_LOGGER_RESULT_IF_FAILED(result);
*modified = true;
}
break;
}
else
{
m_TotalReadSize += readSize;
}
if(readSize == 0)
{
break;
}
}
}
}
return nn::ResultSuccess();
}
nn::Result SavedataCheckerBase::GetFileSize(std::wstring currentDirectory)
{
return common::CalculateFileSizeRecursively(currentDirectory, m_CalculatedFileSize);
}
s64 SavedataCheckerBase::GetCalculatedSize()
{
return m_CalculatedFileSize;
}
s64 SavedataCheckerBase::GetTotalReadSize()
{
return m_TotalReadSize;
}
bool SavedataCheckerBase::GetCheckErrorOccured()
{
return m_CheckErrorOccured;
}
std::wstring SavedataCheckerBase::GetFilePathWithoutArchive(std::wstring path)
{
std::wstring::size_type pos = path.find(L":/");
if(pos != std::wstring::npos)
{
return path.substr(pos + sizeof(L""));
}
else
{
return path;
}
}
bool SavedataCheckerBase::IsForceDeleteFile(const char* name)
{
return std::strcmp(common::BASHOTORYA_FILE_NAME, name) == 0;
}
NandSavedataChecker::NandSavedataChecker()
{
// TODO 自動生成されたコンストラクター・スタブ
}
NandSavedataChecker::NandSavedataChecker(void* buf, size_t size) : m_Buf(buf), m_Bufsize(size)
{
m_pSharedExtSaveChecker = new SharedExtSavedataChecker(buf, size);
m_pSysSaveChecker = new SystemSavedataChecker(buf, size);
}
NandSavedataChecker::~NandSavedataChecker()
{
delete m_pSharedExtSaveChecker;
delete m_pSysSaveChecker;
}
nn::Result NandSavedataChecker::CleanUp(bool erase)
{
nn::Result result;
m_pSharedExtSaveChecker->CalculateFileSize();
m_pSysSaveChecker->CalculateFileSize();
result = m_pSharedExtSaveChecker->CleanUp(erase);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = m_pSysSaveChecker->CleanUp(erase);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
return nn::ResultSuccess();
}
s64 NandSavedataChecker::GetProgress()
{
if (m_pSharedExtSaveChecker->GetCalculatedSize() == 0 || m_pSysSaveChecker->GetCalculatedSize() == 0)
{
return 0;
}
else
{
return (m_pSharedExtSaveChecker->GetTotalReadSize() + m_pSysSaveChecker->GetTotalReadSize()) * 100
/ (m_pSharedExtSaveChecker->GetCalculatedSize() + m_pSysSaveChecker->GetCalculatedSize());
}
}
bool NandSavedataChecker::GetCheckErrorOccured()
{
return m_pSharedExtSaveChecker->GetCheckErrorOccured() || m_pSysSaveChecker->GetCheckErrorOccured();
}
SystemSavedataChecker::SystemSavedataChecker()
{
}
SystemSavedataChecker::SystemSavedataChecker(void* buf, size_t size) : SavedataCheckerBase(buf, size)
{
}
SystemSavedataChecker::~SystemSavedataChecker()
{
}
nn::Result SystemSavedataChecker::CleanUp(bool erase)
{
nn::Result result;
std::wstring currentDirectory;
for (s32 i = 0; i < SYSTEM_SAVE_DATA_NUM; i++)
{
bool metaDataCrashed = false;
bool modified = false;
// SPIDERのスキップ
if(SYSTEM_SAVEDATA_COUPLE_LIST[i].id == 0x00020088 ||
SYSTEM_SAVEDATA_COUPLE_LIST[i].id == 0x0002009d ||
SYSTEM_SAVEDATA_COUPLE_LIST[i].id == 0x00020094)
{
NN_LOG("Skip SPIDER\n");
continue;
}
result = nn::fs::MountSystemSaveData(SYSTEM_SAVEDATA_ARCHIVE_NAME, SYSTEM_SAVEDATA_COUPLE_LIST[i].id );
if (result.IsFailure())
{
if(result <= nn::fs::ResultVerificationFailed())
{
NN_LOG("Mount Error: %s\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
COMMON_LOGGER_WARN(
"Error: %s/\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
if (erase)
{
COMMON_LOGGER_WARN(
"Deleting: %s/\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
// 削除する
result = nn::fs::DeleteSystemSaveData(SYSTEM_SAVEDATA_COUPLE_LIST[i].id);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
}
else
{
NN_LOG("Mount %s\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
// ファイルを個別にチェックする
result = CleanUpFilesRecursively(&metaDataCrashed, &modified, SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str(), L"ssave:/", erase);
// メタデータエラーの場合は一旦アンマウントしてからアーカイブごと削除
if (erase && metaDataCrashed)
{
// 削除する
COMMON_LOGGER_WARN( "Deleting: %s/\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
result = nn::fs::Unmount(SYSTEM_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::DeleteSystemSaveData(SYSTEM_SAVEDATA_COUPLE_LIST[i].id);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
continue;
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
if(modified)
{
result = nn::fs::CommitSystemSaveData(SYSTEM_SAVEDATA_ARCHIVE_NAME);
}
result = nn::fs::Unmount(SYSTEM_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
return nn::ResultSuccess();
}
nn::Result SystemSavedataChecker::CalculateFileSize()
{
nn::Result result;
for (s32 i = 0; i < SYSTEM_SAVE_DATA_NUM; i++)
{
result = nn::fs::MountSystemSaveData(SYSTEM_SAVEDATA_ARCHIVE_NAME, SYSTEM_SAVEDATA_COUPLE_LIST[i].id );
if (result.IsSuccess())
{
result = GetFileSize(L"ssave:/");
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::Unmount(SYSTEM_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
NN_LOG("CalculatedFileSize = %lld\n", m_CalculatedFileSize);
return result;
}
SharedExtSavedataChecker::SharedExtSavedataChecker()
{
}
SharedExtSavedataChecker::SharedExtSavedataChecker(void* buf, size_t size) : SavedataCheckerBase(buf, size)
{
}
SharedExtSavedataChecker::~SharedExtSavedataChecker()
{
}
nn::Result SharedExtSavedataChecker::CleanUp(bool erase)
{
nn::Result result;
const size_t ARRAY_SIZE = 256;
s32 numId;
bit32 IdArray[ARRAY_SIZE];
result = nn::fs::EnumerateSharedExtSaveData(&numId, IdArray, ARRAY_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
NN_LOG_DEBUG("ExtData num = %d\n", numId);
for (s32 i = 0; i < numId; i++ )
{
bool metaDataCrashed = false;
bool modified = false;
char baseName[10];
nn::nstd::TSNPrintf(baseName, sizeof(baseName), "%X", IdArray[i]);
result = nn::fs::MountSharedExtSaveData(SHARED_EXT_SAVEDATA_ARCHIVE_NAME, IdArray[i]);
if (result.IsSuccess())
{
NN_LOG("Mount %x\n", IdArray[i]);
// アーカイブ内のファイル・ディレクトリをチェックする
result = CleanUpFilesRecursively(&metaDataCrashed, &modified, baseName, L"shext:/", erase);
// メタデータが壊れていた場合はアンマウントしてから削除する
if(erase && metaDataCrashed)
{
COMMON_LOGGER_WARN("Deleting %x/\n", IdArray[i]);
result = nn::fs::Unmount(SHARED_EXT_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::DeleteSharedExtSaveData(IdArray[i]);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
continue;
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::Unmount(SHARED_EXT_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
else
{
// アーカイブごと削除する
if(result <= nn::fs::ResultVerificationFailed())
{
NN_LOG("Mount Error: %x\n", IdArray[i]);
COMMON_LOGGER_WARN("Error: %x/\n", IdArray[i]);
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
if (erase)
{
COMMON_LOGGER_WARN("Deleting %x/\n", IdArray[i]);
result = nn::fs::DeleteSharedExtSaveData(IdArray[i]);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
}
}
return nn::ResultSuccess();
}
nn::Result SharedExtSavedataChecker::CalculateFileSize()
{
nn::Result result;
const size_t ARRAY_SIZE = 256;
s32 numId;
bit32 IdArray[ARRAY_SIZE];
result = nn::fs::EnumerateSharedExtSaveData(&numId, IdArray, ARRAY_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
NN_LOG_DEBUG("ExtData num = %d\n", numId);
for (s32 i = 0; i < numId; i++ )
{
result = nn::fs::MountSharedExtSaveData(SHARED_EXT_SAVEDATA_ARCHIVE_NAME, IdArray[i]);
if (result.IsSuccess())
{
result = GetFileSize(L"shext:/");
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::Unmount(SHARED_EXT_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
NN_LOG("CalculatedFileSize = %lld\n", m_CalculatedFileSize);
return nn::ResultSuccess();
}
} /* namespace ConsoleBackup */

View File

@ -0,0 +1,237 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: NandSavedataChecker.h
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$
*---------------------------------------------------------------------------*/
#ifndef SAVEDATACHECKER_H_
#define SAVEDATACHECKER_H_
#include <string>
#include <nn.h>
#include <nn/fs/fs_ParametersForSystem.h>
namespace ConsoleBackup
{
struct SystemSaveDataCouple
{
std::string name;
nn::fs::SystemSaveDataId id;
};
const SystemSaveDataCouple SYSTEM_SAVEDATA_COUPLE_LIST[] =
{
{"fill_data", 0x00010000 },
{"cfg", 0x00010017 },
{"ptm", 0x00010022 },
{"cecd", 0x00010026 },
{"nim", 0x0001002C },
{"friends", 0x00010032 },
{"boss", 0x00010034 },
{"news", 0x00010035 },
{"ACTIVITY_LOG_JP", 0x00020202 },
{"ACTIVITY_LOG_US", 0x00020212 },
{"ACTIVITY_LOG_EU", 0x00020222 },
{"MII_MAKER_JP", 0x00020207 },
{"MII_MAKER_US", 0x00020217 },
{"MII_MAKER_EU", 0x00020227 },
{"PHOTO_JP", 0x00020204 },
{"PHOTO_US", 0x00020214 },
{"PHOTO_EU", 0x00020224 },
{"SOUND_JP", 0x00020205 },
{"SOUND_US", 0x00020215 },
{"SOUND_EU", 0x00020225 },
{"ESHOP_JP", 0x00020209 },
{"ESHOP_US", 0x00020219 },
{"ESHOP_EU", 0x00020229 },
{"ZONE_JP", 0x0002020b },
{"ZONE_US", 0x0002021b },
{"ZONE_EU", 0x0002022b },
{"MIGRATION_JP", 0x0002020a },
{"MIGRATION_US", 0x0002021a },
{"MIGRATION_EU", 0x0002022a },
{"DIARY_JP", 0x0002020c },
{"DIARY_US", 0x0002021c },
{"DIARY_EU", 0x0002022c },
{"MII_PLAZA_JP", 0x00020208 },
{"MII_PLAZA_US", 0x00020218 },
{"MII_PLAZA_EU", 0x00020228 },
{"ARGAMES_HAL_JP", 0x0002020d },
{"ARGAMES_HAL_US", 0x0002021d },
{"ARGAMES_HAL_EU", 0x0002022d },
{"ARGAMES_NCL_JP", 0x0002020e },
{"ARGAMES_NCL_US", 0x0002021e },
{"ARGAMES_NCL_EU", 0x0002022e },
{"MENU_JP", 0x00020081 },
{"MENU_US", 0x0002008f },
{"MENU_EU", 0x00020098 },
{"friend_JP", 0x0002008d },
{"friend_US", 0x00020096 },
{"friend_EU", 0x0002009f },
{"BROWSER_JP", 0x00020088 },
{"BROWSER_US", 0x0002009d },
{"BROWSER_EU", 0x00020094 },
{"ESPEC_JP", 0x00020086 },
{"ESPEC_US", 0x00020092 },
{"ESPEC_EU", 0x0002009b },
{"MEMO_JP", 0x00020087 },
{"MEMO_US", 0x00020093 },
{"MEMO_EU", 0x0002009c },
{"error", 0x000200c5 }
};
const char* const SYSTEM_SAVEDATA_ARCHIVE_NAME = "ssave:";
const char* const SHARED_EXT_SAVEDATA_ARCHIVE_NAME = "shext:";
const size_t SYSTEM_SAVE_DATA_NUM = sizeof(SYSTEM_SAVEDATA_COUPLE_LIST)/sizeof(SYSTEM_SAVEDATA_COUPLE_LIST[0]);
class SavedataCheckerBase
{
public:
SavedataCheckerBase() {}
SavedataCheckerBase(void* buf, size_t size);
~SavedataCheckerBase();
//! @brief セーブデータを調べて問題があるファイルを削除するインタフェース
//! @param[in] erase 問題があるファイルを削除するかどうか
virtual nn::Result CleanUp(bool erase) = 0;
//! @brief ファイルサイズをチェックするインタフェース
virtual nn::Result CalculateFileSize() = 0;
//! @return 事前に計算したサイズ
s64 GetCalculatedSize();
//! @return 読み取ったサイズ
s64 GetTotalReadSize();
//! @brief チェック時にエラーが起こったかどうか調べる
//! @return エラーが起こったかどうか
bool GetCheckErrorOccured();
protected:
//! @brief ファイルとディレクトリを再帰的にチェックする。エラーがあれば削除する
//! @param[out] metaDataCrashed メタデータが壊れていたかどうか。アーカイブごと削除するかどうかの判断に使用する
//! @param[out] modified ファイルかディレクトリを削除したかどうか。Commitするかどうかの判断に使用する
//! @param[in] baseName 削除するセーブデータの区別に表示するための名前
//! @param[in] currentDirectory チェックを開始するディレクトリ。スラッシュで終端すること
//! @param[in] erase ファイルかディレクトリを削除するかどうか
nn::Result CleanUpFilesRecursively(bool* metaDataCrashed, bool* modified, std::string baseName, std::wstring currentDirectory,
bool erase);
//! @brief ファイルサイズを取得する
//! @param[out] size ファイルサイズ
//! @param[in] currentDirectory チェックを開始するディレクトリ。スラッシュで終端すること。
nn::Result GetFileSize(std::wstring currentDirectory);
//! バッファ
void* m_Buf;
//! バッファサイズ
size_t m_Bufsize;
NN_PADDING4;
//! 事前読み取りサイズ
s64 m_CalculatedFileSize;
//! 累計読み取りサイズ
s64 m_TotalReadSize;
NN_PADDING3;
//! @brief チェック時にエラーが起こったかどうか
bool m_CheckErrorOccured;
NN_PADDING4;
private:
std::wstring GetFilePathWithoutArchive(std::wstring path);
bool IsForceDeleteFile(const char* name);
};
//! @brief システムセーブデータをチェックするためのクラス
class SystemSavedataChecker : public SavedataCheckerBase
{
public:
SystemSavedataChecker();
SystemSavedataChecker(void* buf, size_t size);
~SystemSavedataChecker();
//! @brief システムセーブデータを調べて問題があるファイルを削除する
//! @param[in] erase 問題があるファイルを削除するかどうか
virtual nn::Result CleanUp(bool erase);
//! @brief ファイルサイズをチェックする
virtual nn::Result CalculateFileSize();
};
//! @brief 共有拡張セーブデータをチェックするためのクラス
class SharedExtSavedataChecker : public SavedataCheckerBase
{
public:
SharedExtSavedataChecker();
SharedExtSavedataChecker(void* buf, size_t size);
~SharedExtSavedataChecker();
//! @brief 共有拡張セーブデータを調べて問題があるファイルを削除する
//! @param[in] erase 問題があるファイルを削除するかどうか
virtual nn::Result CleanUp(bool erase);
//! @brief ファイルサイズをチェックする
virtual nn::Result CalculateFileSize();
};
class NandSavedataChecker
{
public:
NandSavedataChecker();
NandSavedataChecker(void* buf, size_t size);
~NandSavedataChecker();
nn::Result CleanUp(bool erase);
s64 GetProgress();
bool GetCheckErrorOccured();
private:
SharedExtSavedataChecker* m_pSharedExtSaveChecker;
SystemSavedataChecker* m_pSysSaveChecker;
//! バッファ
void* m_Buf;
//! バッファサイズ
size_t m_Bufsize;
};
} /* namespace ConsoleBackup */
#endif /* SAVEDATACHECKER_H_ */

View File

@ -0,0 +1 @@
В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫фВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫ф8ф8фШчГГГГГГВВ╫8фВВВВВГГГГшчфГШФВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫фВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫yнВ╫yнВВВВВ╫YнВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВГГГГШчyнYнВ╫шчшчВВфВВ╫шчyнШчВ╫yнГГГГyнШФГГГГГшчВВВВ╫YнГyнГВВВВВ╫yнфшчГШФГYнyнВВВ╫yнВ╫╨жВВВВВ╫yнВ╫yнВВВВВ╫YнВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫yнГYнГВ╫В╫В╫В╫В╫фВ╫В╫ГyнГ8фВВВВфВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫

View File

@ -0,0 +1 @@
ВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫YнВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫8фВВ╫8ф8фВВВ╫╨ж8ф╨жГГшчГГГГГГГГГГГГГГГГГГГГГГГВВВВВВВВВВ╫8ф8фВВфВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫ГГГГГШФГГГГГГГГГГ жфГГВ╫В╫ жВ╫ГГГГГ жГГВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫8фВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫шчВ╫шчВВВВВГВ╫ШчВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫╨жВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫ГГГГГГГГГГГГГГГГГГШФ8фШчшчВВ жВ╫YнВВВВВГГYнyнГГyнфВ╫В╫В╫В╫В╫В╫В╫В╫фВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫шчшчГшчШФВ╫В╫ГГYнГВ╫В╫В╫В╫В╫шчВ╫шчГГГГГГГГГГГГГГГГВВ╫YнШч жГГГГГГГГГГГГГГГГГГГГГГГГшч╨жВ жВ╫шчВВВВВ╫ШФВ╫ШФВВВВВВВВВВВВВВВВВВВВВ╫шчВ╫yнВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫YнВ жГГГГВ╫шчВ╫шчГГГГВВВВВВВВВВВВВВВВВ╫8фВВ╫╨жшчВВВВВ╫YнфyнГГГГГГГГГ жГГГГ╨жВ╫YнВ╫ШФYнВВВВВВВВВВВВВВ╫шч жВВВВВВ╫yнВГШФВ╫В╫фВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫ШФВ╫ГГГГГВ╫ШчВ╫YнГГШФГВВВВВВВВВВВВВВВВВВВВВ╫8фВВВВВВВВВВГГГГ жВ╫шчВ╫ГГГшч жВВВВВВВВВВВВВВВВВВВ╫8фВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ

View File

@ -0,0 +1,354 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: ConsoleRestore.cpp
Copyright (C)2009 Nintendo Co., Ltd. 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/version.h>
#include <nn/ptm/CTR/ptm_ApiSysmenu.h>
#include <nn/mcu.h>
#include <nn/cfg/CTR/cfg_Api.h>
#include <nn/cfg/CTR/cfg_ApiInit.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/ps.h>
#include <nn/nwm.h>
#include <nn/ac.h>
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/fs/fs_ApiSysSaveData.h>
#include <nn/cfg/CTR/cfg_ApiNor.h>
#include <nn/am/am_ApiSystemMenu.h>
#include <nn/os/os_SharedInfo.h>
#include <nn/ndm.h>
#include <nn/nim.h>
#include <nn/am.h>
#include "demo.h"
#include <vector>
#include <string>
#include "DrawSystemState.h"
#include "Controller.h"
#include "SimplePlayer.h"
#include "CommonLogger.h"
#include "SDMountManager.h"
#include "HeapManager.h"
#include "VersionDetect.h"
#include "Util.h"
#include "ResFont.h"
#include "HardwareStateManager.h"
// バージョン表示用
#include "version.h"
namespace {
// グラフィックスに割り当てるメモリ
const size_t s_GxHeapSize = 0x800000;
common::Util s_HwUtility;
demo::RenderSystemDrawing s_RenderSystem;
} // namespace <unnamed>
namespace ConsoleRestore{
void FinalizeAll()
{
common::Logger::GetLoggerInstance()->Finalize();
// アンマウント
nn::fs::Unmount("nand:");
nn::fs::Unmount("sdmc:");
s_RenderSystem.Finalize();
s_HwUtility.FinalizeForRestore();
nn::ps::Finalize();
nn::ptm::CTR::FinalizeForSystemMenu();
nn::cfg::CTR::system::Finalize();
nn::cfg::CTR::init::Finalize();
nn::hid::Finalize();
nn::fs::Finalize();
nn::applet::PrepareToCloseApplication();
nn::applet::CloseApplication();
}
extern "C" void nnMain(void)
{
nn::Result result;
// os の初期化
nn::os::Initialize();
// fs の初期化
nn::fs::Initialize();
// appletの初期化
nn::applet::Enable( false );
// hid の初期化
result = nn::hid::Initialize();
NN_ERR_THROW_FATAL_IF_FATAL_ONLY(result);
// ndmの初期化
result = nn::ndm::Initialize();
NN_ERR_THROW_FATAL_IF_FATAL_ONLY(result);
// デーモンの自律動作を停止
result = nn::ndm::Suspend(nn::ndm::DN_CEC);
NN_ERR_THROW_FATAL_IF_FATAL_ONLY(result);
result = nn::ndm::Suspend(nn::ndm::DN_BOSS);
NN_ERR_THROW_FATAL_IF_FATAL_ONLY(result);
result = nn::ndm::Suspend(nn::ndm::DN_FRIENDS);
NN_ERR_THROW_FATAL_IF_FATAL_ONLY(result);
result = nn::ndm::Suspend(nn::ndm::DN_NIM);
NN_ERR_THROW_FATAL_IF_FATAL_ONLY(result);
// cfg の初期化
nn::cfg::CTR::init::Initialize();
nn::cfg::CTR::system::Initialize();
// 時計設定用ptm初期化
nn::ptm::CTR::InitializeForSystemMenu();
// ps の初期化
nn::ps::Initialize();
// amの初期化
nn::am::InitializeForLocalImporter();
// ヒープの確保
common::InitializeHeap();
// RenderSystem の準備
common::HeapManager gxHeap(s_GxHeapSize);
uptr heapForGx = reinterpret_cast<uptr>(gxHeap.GetAddr());
s_RenderSystem.Initialize(heapForGx, s_GxHeapSize);
// ResFontの初期化
common::InitializeResFont();
// サウンドスレッドの起動
common::InitializeSimplePlayer();
// ログ描画の初期化
common::Logger::GetLoggerInstance()->Initialize(common::CONSOLE_WIDTH, common::CONSOLE_HEIGHT,
common::CONSOLE_MAX_LINE, &s_RenderSystem);
// RenderSystemを作ってからログが出せる
common::Logger::InitializeEjectThread();
common::Logger::SetEjectHandler(OnSdEjected);
common::Logger::SetInsertHandler(OnSdInserted);
COMMON_LOGGER("\n");
COMMON_LOGGER("CTR Console Restore start\n");
// ボタン入力
nn::hid::PadReader s_PadReader;
nn::hid::PadStatus padStatus;
// データの準備
s_HwUtility.InitializeForRestore();
common::HardwareStateManager manager(s_HwUtility);
// 情報出力
COMMON_LOGGER("CTR Console Restore %s-%s\n", CONSOLE_REPAIR_VERSION_MAJOR, CONSOLE_REPAIR_VERSION_MINOR);
COMMON_LOGGER("System Ver. %d.%d.%d-%d\n", s_HwUtility.GetCupMajorVersion(),
s_HwUtility.GetCupMinorVersion(),
s_HwUtility.GetCupMicroVersion(),
s_HwUtility.GetNupVersion());
COMMON_LOGGER("System Region %s\n", s_HwUtility.GetRegionCodeA3());
COMMON_LOGGER("Serial Number %s\n", s_HwUtility.GetSerialNumber());
COMMON_LOGGER("Device ID %llu\n", s_HwUtility.GetInfraDeviceId());
COMMON_LOGGER("MAC Address %s\n", s_HwUtility.GetMacAddress());
COMMON_LOGGER("Friend Code %04u-%04u-%04u\n",
static_cast<u32>(s_HwUtility.GetFriendcode() / 100000000ULL % 10000ULL),
static_cast<u32>(s_HwUtility.GetFriendcode() / 10000ULL % 10000ULL),
static_cast<u32>(s_HwUtility.GetFriendcode() % 10000ULL) );
bool flip = false;
InitializeState();
for(;;)
{
bool nextStep = false;
s_PadReader.ReadLatest(&padStatus);
// AまたはSTARTボタンで進行
if(padStatus.trigger & nn::hid::BUTTON_A ||
padStatus.trigger & nn::hid::BUTTON_START)
{
nextStep = true;
}
// LまたはRボタンで上下画面フリップ
if(padStatus.trigger & nn::hid::BUTTON_R ||
padStatus.trigger & nn::hid::BUTTON_L)
{
flip = !flip;
}
// コンソールスクロール
if(padStatus.hold & nn::hid::BUTTON_UP)
{
common::Logger::GetLoggerInstance()->ScrollUp();
}
// コンソールスクロール
if(padStatus.hold & nn::hid::BUTTON_DOWN)
{
common::Logger::GetLoggerInstance()->ScrollDown();
}
if(padStatus.hold & nn::hid::BUTTON_LEFT)
{
common::Logger::GetLoggerInstance()->ScrollToBegin();
}
if(padStatus.hold & nn::hid::BUTTON_RIGHT)
{
common::Logger::GetLoggerInstance()->ScrollToEnd();
}
// 情報更新
// ACアダプタ
std::string adapterState;
if(manager.IsAdapterConnected())
{
adapterState += ::std::string("Connected");
}
else
{
adapterState += ::std::string("Not Connected");
}
// 操作用メッセージ
// 進捗確認メッセージを兼ねる?
::std::vector<std::string> operationMessage;
ControlState(manager, operationMessage, nextStep);
nn::util::FloatColor titleColor;
if(GetRestoreMode() == RESTORE_MODE_RESTORE)
{
titleColor.r = 0.1f;
titleColor.g = 0.25f;
titleColor.b = 0.1f;
}
else if(GetRestoreMode() == RESTORE_MODE_NUP_ONLY)
{
titleColor.r = 0.35f;
titleColor.g = 0.35f;
titleColor.b = 0.f;
}
else if(GetRestoreMode() == RESTORE_MODE_GET_IVS)
{
titleColor.r = 1.0f;
titleColor.g = 0.2f;
titleColor.b = 0.2f;
}
else if(GetRestoreMode() == RESTORE_MODE_CHECK_SD)
{
titleColor.r = 0.2f;
titleColor.g = 0.2f;
titleColor.b = 1.2f;
}
// 上画面表示
common::DrawSystemState("CTR Console Restore",
s_RenderSystem,
titleColor,
flip,
adapterState,
s_HwUtility.GetCupMajorVersion(),
s_HwUtility.GetCupMinorVersion(),
s_HwUtility.GetCupMicroVersion(),
s_HwUtility.GetNupVersion(),
s_HwUtility.GetBatteryRemain(),
s_HwUtility.GetInfraDeviceId(),
s_HwUtility.GetFriendcode(),
GetProgress(),
IsRestoreFailed(),
IsRestoreSucceeded(),
false,
s_HwUtility.GetMacAddress(),
operationMessage,
s_HwUtility.GetRegion(),
s_HwUtility.GetSerialNumber(),
s_HwUtility.HasReadFriendCode()
);
if (GetRestoreMode() != RESTORE_MODE_RESTORE)
{
const u8 spaceSize = 10;
const u8 lineBottom = 23;
const u32 screenWidth = 400;
s_RenderSystem.SetColor(1.f, 1.f, 1.f);
if (GetRestoreMode() == RESTORE_MODE_NUP_ONLY)
{
s_RenderSystem.DrawText(0, lineBottom * spaceSize, "NUP-Only Mode");
}
else if (GetRestoreMode() == RESTORE_MODE_GET_IVS)
{
s_RenderSystem.DrawText(0, lineBottom * spaceSize, "GET-SDCI Mode");
}
else if (GetRestoreMode() == RESTORE_MODE_CHECK_SD)
{
s_RenderSystem.DrawText(0, lineBottom * spaceSize, "CHECK-SD Mode");
}
s_RenderSystem.SetColor(titleColor.r, titleColor.g, titleColor.b);
s_RenderSystem.FillRectangle(0, lineBottom * spaceSize, screenWidth, spaceSize);
s_RenderSystem.SetColor(1.f, 1.f, 1.f);
}
s_RenderSystem.SwapBuffers();
// デフォルトで下画面に描画するもの
s_RenderSystem.SetRenderTarget(common::GetRenderTarget(NN_GX_DISPLAY1, flip));
if(IsRestoreSucceeded())
{
s_RenderSystem.SetClearColor(common::GetRenderTarget(NN_GX_DISPLAY1, flip), SUCCESS_COLOR);
}
else if(IsRestoreFailed())
{
s_RenderSystem.SetClearColor(common::GetRenderTarget(NN_GX_DISPLAY1, flip), FAIL_COLOR);
}
else
{
s_RenderSystem.SetClearColor(common::GetRenderTarget(NN_GX_DISPLAY1, flip), NORMAL_COLOR);
}
s_RenderSystem.Clear();
s_RenderSystem.SetColor(1.f, 1.f, 1.f);
common::Logger::GetLoggerInstance()->DrawConsole();
s_RenderSystem.SwapBuffers();
s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
// 電源長押しで終了
if ( nn::applet::IsExpectedToCloseApplication())
{
FinalizeAll();
}
}
}
}

View File

@ -0,0 +1,48 @@
BasicInfo:
Title : ConsoleRestore
ProductCode: CTR-P-22UA
BackupMemoryType: None
TitleInfo:
Use: Evaluation
Category: Application
UniqueId: 0xf8022
Version: 0
SystemControlInfo:
AppType : Application
StackSize : 0x4000
Dependency :
- codec
- hid
- gsp
- friends
- nim
- ac
- ndm
AccessControlInfo:
Priority : 16
DisableDebug : true
FileSystemAccess:
- DirectSdmc
- Debug
- Core
- CategoryFileSystemTool
- ExportImportIvs
IoAccessControl:
- FsMountCardSpi
- FsMountNand
- FsMountTwln
Option:
FreeProductCode: true
CardInfo:
CardDevice: None
Rom:
# ROM に含めるファイルシステムのルートパスを指定します。
HostRoot: "$(ROMFS_ROOT)"

View File

@ -0,0 +1,73 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Contoroller.h
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$
*---------------------------------------------------------------------------*/
#ifndef CONTOROLLER_H_
#define CONTOROLLER_H_
#include <nn.h>
#include <vector>
#include <string>
#include "HardwareStateManager.h"
namespace ConsoleRestore
{
typedef enum RestoreMode
{
RESTORE_MODE_RESTORE,
RESTORE_MODE_NUP_ONLY,
RESTORE_MODE_GET_IVS,
RESTORE_MODE_CHECK_SD
} RestoreMode;
// ネットワーク処理のリトライ回数の最大値
const u32 RETRY_MAX = 3;
// 状態遷移を管理する
// manager ハードウェア情報を取得するためのラッパ
// operationMessage 操作情報として表示したい文字列
// nextStep 次の状態に遷移してもよいかどうか
// continueBackup 処理を続けてもよいかどうか
void ControlState(common::HardwareStateManager& manager, ::std::vector<std::string>& operationMessage, bool& nextStep);
// リストア処理中かどうか
bool InProgress();
// リストアが完了したかどうか
bool IsRestoreSucceeded();
// リストアが失敗したかどうか
bool IsRestoreFailed();
// 書き込みスレッドの進捗を返す
u32 GetProgress();
// SDカードが抜き出されたときに実行したい関数
void OnSdEjected();
// SDカードが挿入されたときに実行したい関数
void OnSdInserted();
// 状態を初期化する
void InitializeState();
// リストア状態を取得する
RestoreMode GetRestoreMode();
}
#endif /* CONTOROLLER_H_ */

View File

@ -0,0 +1,167 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Importer.h
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$
*---------------------------------------------------------------------------*/
#ifndef IMPORTER_H_
#define IMPORTER_H_
#include <nn.h>
#include "FileName.h"
#include <nn/ac/CTR/private/ac_NetworkSetting.h>
#include <string>
#include "HardwareStateManager.h"
namespace ConsoleRestore
{
// SDカードのデバイスIDファイルと本体のデバイスIDが一致しているかどうか
nn::Result EqualsDeviceIdFileandDeviceId(common::HardwareStateManager& manager);
// SDカードのリージョンと本体のリージョンが一致しているかどうか
nn::Result EqualsRegionDataandRegion();
// シリアルナンバーを取得する
nn::Result ReadSerialNumber(u8* serial);
// 出力ファイル一覧を読み込む
nn::Result SetupVersionAndFileList();
// インポート用のスレッドを終了する
void FinalizeImportThread();
// インポート用のスレッドが終了したかどうか
bool IsImportThreadFinished();
// 新たにスレッドを立て、TWLサウンド領域をインポートする
void ImportTwlSoundData();
// 新たにスレッドを立て、TWL-NAND領域をインポートする
void ImportTwlSaveData();
// 新たにスレッドを立て、TWL写真領域をインポートする
void ImportTwlPhotoData();
// 本体固有データを読み込む
// 新たにスレッドを立て、CTRセーブデータ領域をインポートする
nn::Result ImportData();
// インポート完了ファイルを作る
void CreateWriteFinishedFile();
// ネットワークアップデート完了ファイルを作る
void CreateUpdateFinishedFile();
// 本体初期化完了ファイルを作る
void CreateConsoleInitializedFile();
// RTC書き込み完了ファイルを作る
void CreateRtcSyncFinishedFile();
// IVSダウンロード完了ファイルを作る
void CreateDownloadIvsFinishedFile();
// アカウント削除完了ファイルを作る
void CreateDeleteAccountFinishedFile();
// アカウント移行完了ファイルを作る
void CreateTransferAccountFinishedFile();
// インポートスレッドの進捗を取得する
u32 GetImportProgress();
// NANDのごみを削除する
nn::Result Cleanup();
// ファイルが存在するかどうか確認するためのテーブル
const wchar_t* const CHECK_FILENAME_TABLE[] =
{
common::UPDATE_CHECK_PATHNAME,
common::INITIALIZED_CHECK_PATHNAME,
common::WRITE_FINISHED_CHECK_PATHNAME,
common::RTC_SYNC_CHECK_PATHNAME,
common::DOWNLOAD_IVS_CHECK_PATHNAME,
common::DELETE_ACCOUNT_CHECK_PATHNAME,
common::TRANSFER_ACCOUNT_CHECK_PATHNAME
};
// ファイル存在確認をクリアする
void DeleteAllCheckFiles();
struct TimeZone
{
u32 hour;
u32 minutes;
bool isMinus;
NN_PADDING3;
};
// ネットワーク設定ファイルを読み込む
bool ReadSetting(bool* nupOnly, bool* getIvs, bool* checkSd, bool* skipNup);
// ネットワーク設定ファイルからNTPサーバの名前を取得する
// 先にReadSettingが成功している必要がある
char* GetNtpServerName();
// ネットワーク設定ファイルからタイムゾーンを取得する
// 先にReadSettingが成功している必要がある
TimeZone GetTimeZone();
struct CheckedNetworkSetting
{
nn::ac::CTR::NetworkSetting setting;
bool isValid;
NN_PADDING3;
};
// SDカードから読み込んだネットワーク設定ファイルから生成した
// インターネット設定へのポインタを取得する
// インターネット設定は内部のバッファに読み込む
CheckedNetworkSetting* GetTempNetworkSetting();
// 国設定を読み込む
nn::Result ImportCountryLanguageData();
// RTCを読み込む
nn::Result ImportMcuRtc(common::HardwareStateManager& manager);
// TWL写真領域を初期化してから本体初期化を行う
bool InitializeFileSystem();
// SDカードのファイルと本体情報の比較結果をクリアする
void ClearFileReadResult();
// プレイ履歴を読み込みます。ptmのセーブデータ移行後に呼び出す必要があります
void ImportPlayHistory();
// cfgのハードウェア固有領域をcal値で初期化します
nn::Result InitializeHardwareDependentSetting();
// SDカード上のバージョン情報を読みます
nn::Result ReadVersionData();
// SDカードのNintendo 3DS以下ににIVSと一致するディレクトリがあるかどうか
bool ExistsIvsDirectory(std::string& ivsRoot);
// SDカードのIVSデータを書き込む
bool ImportIvsData();
// 書き込みが成功したかどうか
bool IsImportSucceeded();
void RepairSimpleAddress();
}
#endif /* IMPORTER_H_ */

View File

@ -0,0 +1,376 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: NtpClient.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/socket.h>
#include <nn/ac.h>
#include <nn/ptm.h>
#include <nn/ptm/CTR/ptm_ApiSysmenu.h>
#include <nn/ac/private/ac.h>
#include <nn/ac/CTR/private/ac_InternalApi.h>
#include <nn/ac/CTR/private/ac_NetworkSetting.h>
#include <nn/math.h>
#include "Importer.h"
#include "CommonLogger.h"
namespace ConsoleRestore
{
namespace {
const size_t NTP_THREAD_STACK_SIZE = 0x1000;
nn::os::Thread s_NtpThread;
nn::os::StackBuffer<NTP_THREAD_STACK_SIZE> s_NtpThreadStack;
bool s_NtpSyncSuccessed = false;
struct NTP_Packet{ // NTPパケット
u32 controlWord;
u32 rootDelay;
u32 rootDispersion;
u32 referenceId;
s64 referenceTimestamp;
s64 startTimestamp;
s64 receiveTimestamp;
u32 transmitTimestampSeconds;
u32 transmitTimestampFractions;
};
const size_t TIMEOUT_MILLISECOND = 5000; // タイムアウト ミリ秒数
NTP_Packet s_NTPSendPacket; // 送信するNTPパケット
NTP_Packet s_NTPRecvPacket; // 受信するNTPパケット
const u32 NTP_PORT_NUM = 123;
nn::Result InitializeNetwork(void)
{
nn::Result result;
nn::ac::Config config;
result = nn::ac::Initialize();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
// 接続要求用のパラメータを作成
result = nn::ac::CreateDefaultConfig(&config);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return result;
}
// デバッグ用に接続テストを無効化
nn::ac::DebugSetNetworkArea(&config, nn::ac::NETWORK_AREA_LAN);
// 接続要求を発行
result = nn::ac::ConnectWithoutEula(config);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return result;
}
return nn::ResultSuccess();
}
nn::Result FinalizeNetwork(void)
{
nn::Result result;
// 接続要求用のパラメータを作成
result = nn::ac::Close();
NN_UTIL_RETURN_IF_FAILED(result);
result = nn::ac::Finalize();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return nn::ResultSuccess();
}
bool GetNtpTime(u32* ntpTime)
{
nn::Result result;
bool retval = true;
NN_LOG("Initializing network.\n");
// 本体に書き込まれているネットワーク設定を使ってネットワーク接続を初期化
result = InitializeNetwork();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
{
NN_LOG("Initializing socket..\n");
// 一つのスレッドからソケット API を利用する
const s32 sessionCount = 1;
// ソケットの送受信バッファとして 64 KB を割り当て
const size_t bufferSizeForSockets = 65536;
// ソケットライブラリに必要なワークサイズを求める
const size_t workSizeForLibrary = nn::socket::GetRequiredMemorySize(bufferSizeForSockets, sessionCount);
// ワークメモリを確保して 4KB にアラインにする
u8* pWorkMemory = new u8[workSizeForLibrary + 4096];
uptr workMemoryAddress = nn::math::RoundUp<uptr>(reinterpret_cast<uptr> (pWorkMemory), 4096);
// ソケットライブラリの初期化
result = nn::socket::Initialize(workMemoryAddress, workSizeForLibrary, bufferSizeForSockets, sessionCount);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
{
s32 ret;
nn::socket::InAddr addr, netmask;
ret = nn::socket::GetPrimaryAddress(reinterpret_cast<u8*> (&addr), reinterpret_cast<u8*> (&netmask));
NN_ASSERT(ret == 0);
COMMON_LOGGER("host : %s\n", nn::socket::InetNtoA(addr));
COMMON_LOGGER("netmask : %s\n", nn::socket::InetNtoA(netmask));
nn::socket::InAddr dns1, dns2;
ret = nn::socket::GetResolver(reinterpret_cast<u8*> (&dns1), reinterpret_cast<u8*> (&dns2));
if (ret == 0)
{
COMMON_LOGGER("dns1 : %s\n", nn::socket::InetNtoA(dns1));
COMMON_LOGGER("dns2 : %s\n", nn::socket::InetNtoA(dns2));
}
nn::socket::InAddr gateway;
ret = nn::socket::GetDefaultGateway(reinterpret_cast<u8*> (&gateway));
if (ret == 0)
{
COMMON_LOGGER("gateway : %s\n", nn::socket::InetNtoA(gateway));
}
COMMON_LOGGER("\n");
#ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
nn::socket::DumpRoutingTable();
#endif
}
{
s32 socket = nn::socket::Socket(nn::socket::PF_INET, nn::socket::SOCK_DGRAM, 0);
NN_LOG("socket = %d\n", socket);
// クライアントアドレスの設定
nn::socket::SockAddrIn host_addr;
host_addr.len = sizeof(nn::socket::SockAddrIn);
host_addr.family = nn::socket::AF_INET;
host_addr.addr.addr = 0;
host_addr.port = nn::socket::HtoNs(NTP_PORT_NUM);
// ローカルアドレスをバインド
s32 ret = nn::socket::Bind(socket, &host_addr);
NN_LOG("bind = %d\n", ret);
// ********************************************************************************
// NTPパケットを生成して送る
// ********************************************************************************
// サーバアドレスの設定
nn::socket::SockAddrIn serverSockAddrIn;
serverSockAddrIn.len = sizeof(nn::socket::SockAddrIn);
serverSockAddrIn.family = nn::socket::AF_INET;
// GetHostByNameを使う場合
nn::socket::HostEnt* serverHostent;
u64 serveraddr = 0;
serverHostent = nn::socket::GetHostByName(GetNtpServerName());
if (serverHostent == NULL)
{
COMMON_LOGGER("Error: GetHostByName %s\n", GetNtpServerName());
retval = false;
}
else
{
// サーバのホスト情報からIPアドレスをコピー
serveraddr = *(reinterpret_cast<u64 *> (serverHostent->addrList[0]));
}
serverSockAddrIn.addr.addr = serveraddr;
COMMON_LOGGER("Destination address: %s\n", nn::socket::InetNtoA(serverSockAddrIn.addr));
serverSockAddrIn.port = nn::socket::HtoNs(NTP_PORT_NUM); // ポート番号
// NTPパケットをSNTP用に初期化する
s_NTPSendPacket.controlWord = nn::socket::HtoNl(0x0B000000);
s_NTPSendPacket.rootDelay = 0;
s_NTPSendPacket.rootDispersion = 0;
s_NTPSendPacket.referenceId = 0;
s_NTPSendPacket.referenceTimestamp = 0;
s_NTPSendPacket.startTimestamp = 0;
s_NTPSendPacket.receiveTimestamp = 0;
s_NTPSendPacket.transmitTimestampSeconds = 0;
s_NTPSendPacket.transmitTimestampFractions = 0;
// サーバを指定してNTPパケットを送信する
if ((ret = nn::socket::SendTo(socket, reinterpret_cast<const void*> (&s_NTPSendPacket), sizeof(s_NTPSendPacket), 0,
&serverSockAddrIn)) < 0)
{
COMMON_LOGGER("Error: Failed Send to Server, %d\n", ret);
retval = false;
}
NN_LOG("SendTo finished\n");
// 受信待ち
nn::socket::PollFd pollFd;
pollFd.fd = socket;
pollFd.events = nn::socket::POLLRDNORM;
if ((ret = nn::socket::Poll(&pollFd, 1, TIMEOUT_MILLISECOND)) < 0)
{
COMMON_LOGGER("Error: recv error, %d\n", ret);
retval = false;
}
NN_LOG("Poll Finished\n");
switch (pollFd.revents)
{
case nn::socket::POLLERR: // ソケットにエラーが発生しました。
COMMON_LOGGER("Error: POLLERR %s %d\n", __func__, __LINE__);
retval = false;
break;
case nn::socket::POLLHUP: // ストリーム・ソケットが未接続です。
COMMON_LOGGER("Error: POLLHUP %s %d\n", __func__, __LINE__);
retval = false;
break;
case nn::socket::POLLNVAL: // 不正なソケット記述子です。
COMMON_LOGGER("Error: POLLNVAL %s %d\n", __func__, __LINE__);
retval = false;
break;
default:
break;
}
// サーバから時刻情報を受信する
// サーバを指定して受信を行う
// 受信するまで待たされる
if ((ret = nn::socket::RecvFrom(socket, reinterpret_cast<void*> (&s_NTPRecvPacket), sizeof(s_NTPRecvPacket), nn::socket::MSG_DONTWAIT,
&serverSockAddrIn)) < 0)
{
COMMON_LOGGER("Error: RecvFrom, %d\n", ret);
retval = false;
}
NN_LOG("RecvFrom finished\n");
// NTPサーバから取得した時刻を現地時間に変換する
*ntpTime = nn::socket::NtoHl(s_NTPRecvPacket.transmitTimestampSeconds) - 2208988800; /* 1970/01/01 からの秒数に変換 */
NN_LOG("ntp_time = %d\n", ntpTime);
nn::socket::Close(socket);
NN_UNUSED_VAR(ret);
}
NN_LOG("Finalizing socket..\n");
// ソケットライブラリの終了
result = nn::socket::Finalize();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
}
NN_LOG("Finalizing network.\n");
result = FinalizeNetwork();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return retval;
}
void RestoreCurrentInternetSetting()
{
COMMON_LOGGER("Restore Current Internet Setting\n");
nn::Result result;
if (GetTempNetworkSetting()->isValid)
{
result = nn::ac::CTR::UpdateNetworkSetting(0, GetTempNetworkSetting()->setting);
COMMON_LOGGER_RESULT_IF_FAILED(result);
}
else
{
// 無効の場合は消去しておく
result = nn::ac::CTR::RemoveNetworkSetting(0);
COMMON_LOGGER_RESULT_IF_FAILED(result);
}
result = nn::ac::FlushNetworkSetting();
COMMON_LOGGER_RESULT_IF_FAILED(result);
result = nn::ac::FinalizeInternal();
COMMON_LOGGER_RESULT_IF_FAILED(result);
}
}
void NtpThreadFunc()
{
// NTP時間を取得する
u32 ntpTime;
if (GetNtpTime(&ntpTime))
{
// タイムゾーンを考慮してDateTimeに変換する
TimeZone timeZone = GetTimeZone();
// 1970/01/01
nn::fnd::DateTime utc = nn::fnd::DateTime(1970, 1, 1, 0, 0, 0, 0);
nn::fnd::DateTime current = utc + nn::fnd::TimeSpan::FromSeconds(ntpTime);
if (timeZone.isMinus)
{
current -= (nn::fnd::TimeSpan::FromHours(timeZone.hour) + nn::fnd::TimeSpan::FromMinutes(timeZone.minutes));
}
else
{
current += nn::fnd::TimeSpan::FromHours(timeZone.hour) + nn::fnd::TimeSpan::FromMinutes(timeZone.minutes);
}
// SWCを書き込む
nn::ptm::CTR::SetUserTime(current);
COMMON_LOGGER("Set User Time %04d/%02d/%02d %02d:%02d:%02d\n",
current.GetYear(), current.GetMonth(), current.GetDay(), current.GetHour(), current.GetMinute(), current.GetSecond());
s_NtpSyncSuccessed = true;
}
else
{
COMMON_LOGGER("Failed Get Ntp Time\n");
s_NtpSyncSuccessed = false;
}
// インターネット設定を元に戻す
RestoreCurrentInternetSetting();
}
bool IsTimeAdjustFinished()
{
// Initialize済みかつ終了
return s_NtpThread.IsValid() && !s_NtpThread.IsAlive();
}
bool IsTimeAdjustSuccessed()
{
return s_NtpSyncSuccessed;
}
void AdjustTime()
{
nn::Result result;
result = nn::ac::CTR::InitializeInternal();
COMMON_LOGGER_RESULT_IF_FAILED(result);
if(IsTimeAdjustFinished())
{
s_NtpThread.Join();
s_NtpThread.Finalize();
}
s_NtpThread.Start( NtpThreadFunc, s_NtpThreadStack);
}
}

View File

@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: NtpClient.h
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$
*---------------------------------------------------------------------------*/
#ifndef NTPCLIENT_H_
#define NTPCLIENT_H_
namespace ConsoleRestore
{
// 新たにスレッドを立て、NTPサーバと同期する
u32 AdjustTime();
// NTPサーバとの同期が終了したかどうか
bool IsTimeAdjustFinished();
// NTPサーバとの同期が完了したかどうか
bool IsTimeAdjustSuccessed();
}
#endif /* NTPCLIENT_H_ */

View File

@ -0,0 +1,79 @@
#!/usr/bin/env omake
#----------------------------------------------------------------------------
# Project: Horizon
# File: OMakefile
#
# Copyright (C)2009 Nintendo Co., Ltd. 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$
#----------------------------------------------------------------------------
SUPPORTED_TARGETS = CTR-T*.Process.MPCore.fast
CTR_APPTYPE = CARD
TARGET_PROGRAM = ConsoleRestore
SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include)
INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \
../common
SOURCES[] =
ConsoleRestore.cpp
Controller.cpp
Importer.cpp
Updater.cpp
Ntpclient.cpp
TitleDownloader.cpp
Shop.cpp
RegionIdModifier.cpp
../common/Util.cpp
../common/DrawSystemState.cpp
../common/FileTransfer.cpp
../common/FileChecker.cpp
../common/SdReaderWriter.cpp
../common/HeapManager.cpp
../common/SdLogger.cpp
../common/wave.cpp
../common/SimplePlayer.cpp
../common/LogConsole.cpp
../common/CommonLogger.cpp
../common/SdMountManager.cpp
../common/configLoader.cpp
../common/VersionDetect.cpp
../common/ResFont.cpp
../common/HardwareStateManager.cpp
../common/SaveDataMover.cpp
CTR_BANNER_SPEC = $(TARGET_PROGRAM).bsf
ROMFS_ROOT = ../common/romfiles
SHADER_BIN = nnfont_RectDrawerShader.shbin
SHADER_PATH = $(ROMFS_ROOT)/$(SHADER_BIN)
ROMFS_DEPENDENCIES = $(SHADER_PATH)
LIBS += libnn_cfg \
libnn_crypto \
libnn_mcu \
libnn_ps \
lib_demo \
libnn_nwm \
libnn_friends \
libnn_ns \
libnn_am \
libnn_nim \
INSTALL_SDK_TOOL = true
ROM_SPEC_FILE = $(TARGET_PROGRAM).rsf
DESCRIPTOR = $(HORIZON_ROOT)/resources/specfiles/private/RepairTool.desc
include $(ROOT_OMAKE)/modulerules
build: $(DEFAULT_TARGETS)

View File

@ -0,0 +1,152 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: RegionIdModifier.cpp
Copyright (C)2011 Nintendo Co., Ltd. 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 "RegionIdModifier.h"
#include <cwchar>
#include <cstring>
struct CountryData
{
u32 id; // 上記定数にあるように、国IDと地域IDを組み合わせたID
u16 regionName[16][64]; // NULL終端込み
u8 order[16]; // 言語ごとの地域名並び順「未設定」が0になるので、最初の地域は1
u16 latitude; // リストの値を 65536/360 倍して格納して下さい
u16 longitude; // リストの値を 65536/360 倍して格納して下さい
};
const size_t NUP_VERSION_TO_REGIONNUM[] =
{
1, // ローンチ(0)
1, // 0thNUP(1)
2, // 1stNUP(2)
2, // 1.05NUP(3)
2, // 1.1NUP(4)
3, // 2ndNUP(5)
3, // 2.1NUP(6)
};
const wchar_t* DIR_PATH[] =
{
L"0/JP/",
L"0/US/",
L"0/EU/",
L"2/JP/",
L"2/US/",
L"2/EU/",
L"5/JP/",
L"5/US/",
L"5/EU/"
};
RegionIdModifier::RegionIdModifier(u16 id, u8 nupVersion, u8 regionCode, const wchar_t* regionName)
{
m_Id = id;
m_NupVersion = nupVersion;
m_RegionCode = regionCode;
if (regionName != NULL)
{
std::wcsncpy(m_RegionName, regionName, sizeof(m_RegionName) / sizeof(wchar_t));
}
}
bool RegionIdModifier::IsValid()
{
return (m_Id & 0x00ff) != 0x01;
}
const PathList* RegionIdModifier::GetDirectoryPath()
{
// 範囲外のリージョン
if (2 < m_RegionCode)
{
return NULL;
}
for (u8 i = 0; i < 3; i++)
{
std::wcsncpy(m_DirectoryPathBuf[i].path, DIR_PATH[m_RegionCode + i * 3], 32);
}
return m_DirectoryPathBuf;
}
size_t RegionIdModifier::GetDirectoryPathNum()
{
// 範囲外のリージョン
if (2 < m_RegionCode)
{
return 0;
}
const size_t countryNum = sizeof(NUP_VERSION_TO_REGIONNUM) / sizeof(NUP_VERSION_TO_REGIONNUM[0]);
if (m_NupVersion > countryNum - 1)
{
return NUP_VERSION_TO_REGIONNUM[countryNum - 1];
}
else
{
return NUP_VERSION_TO_REGIONNUM[m_NupVersion];
}
}
const wchar_t* RegionIdModifier::GetFileName()
{
std::swprintf(m_FileNameBuf, sizeof(m_FileNameBuf), L"%d_LZ.bin", m_Id >> 8);
return m_FileNameBuf;
}
const PathList* RegionIdModifier::GetFilePath()
{
std::memset(m_FilePathBuf, 0, sizeof(m_FilePathBuf));
GetDirectoryPath();
for (u8 i = 0; i < GetDirectoryPathNum(); i++)
{
size_t writeSize = std::wcslen(m_DirectoryPathBuf[i].path);
std::wcsncpy(m_FilePathBuf[i].path, m_DirectoryPathBuf[i].path, writeSize);
std::wcsncat(m_FilePathBuf[i].path, GetFileName(), 32 - writeSize);
}
return m_FilePathBuf;
}
size_t RegionIdModifier::GetFilePathNum()
{
return GetDirectoryPathNum();
}
bool RegionIdModifier::GetValidRegionId(void* buf, size_t size, u8* id)
{
if (buf == NULL || size == 0)
{
return false;
}
u32 numRegion; // その国に含まれる地域の数
numRegion = *reinterpret_cast<u32*>(buf);
CountryData* pCountry;
pCountry = reinterpret_cast<CountryData*>(&reinterpret_cast<u32*>(buf)[1]);
for (u32 i = 0; i < numRegion + 1; i++)
{
if (std::wcscmp(m_RegionName, reinterpret_cast<wchar_t*>(pCountry->regionName[0])) == 0)
{
*id = (pCountry->id >> 16) & 0x00ff;
return true;
}
pCountry++;
}
return false;
}

View File

@ -0,0 +1,88 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: RegionIdModifier.h
Copyright (C)2011 Nintendo Co., Ltd. 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:$
*---------------------------------------------------------------------------*/
#ifndef _REGION_ID_MODIFIER_H_
#define _REGION_ID_MODIFIER_H_
#if defined(__ARMCC_VERSION)
#include <nn.h>
#else
#include <cstddef>
#include "types.h"
#endif
struct PathList
{
wchar_t path[32];
};
//! @brief データ移行ツールで破壊した地域idを修正するためのクラスです
class RegionIdModifier
{
public:
//! @brief パラメータを与えて初期化します。
//! @param[in] id SimpleAddressの上位16ビット
//! @param[in] nupVersion NUPバージョン
//! @param[in] regionCode リージョン
//! @param[in] regionName 地域名
RegionIdModifier(u16 id, u8 nupVersion, u8 regionCode, const wchar_t* regionName);
~RegionIdModifier() {};
//! @brief 正しいIDかどうか
bool IsValid();
//! @brief バージョン、リージョンに応じたディレクトリパスの配列を取得します
//! @return パス名。バージョン・リージョンが正しくない場合はNULL
const PathList* GetDirectoryPath();
//! @brief バージョン、リージョンに応じたディレクトリパス数を取得します
size_t GetDirectoryPathNum();
//! @brief 国idに応じたファイル名を取得します
const wchar_t* GetFileName();
//! @brief バージョン、リージョン、国idに応じたファイルパスの配列を取得します
const PathList* GetFilePath();
//! @brief バージョン、リージョン、国idに応じたファイルパス数を取得します
size_t GetFilePathNum();
//! @brief 与えられたバッファから正しい地域idを取得します
//! @param[in] buf 展開済みの地域データの入ったバッファ
//! @param[in] size バッファサイズ
//! @param[out] id 正しいid
//! @return 正しいidが見つかったかどうか
bool GetValidRegionId(void* buf , size_t size, u8* id);
private:
//! @brief SimpleAddressの上位16ビット
// 上位8ビットが国id,下位8ビットが地域
u16 m_Id;
//! @brief NUPバージョン番号
u8 m_NupVersion;
//! @brief リージョンコード
u8 m_RegionCode;
//! @brief 地域名
wchar_t m_RegionName[64];
//! @brief ファイル名を保存するバッファ
wchar_t m_FileNameBuf[32];
//! @brief ディレクトリパスを保存するバッファ
PathList m_DirectoryPathBuf[3];
//! @brief ファイルパスを保存するバッファ
PathList m_FilePathBuf[3];
};
#endif // _REGION_ID_MODIFIER_H_

View File

@ -0,0 +1,560 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Shop.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/os.h>
#include <nn/Handle.h>
#include <nn/dbg.h>
#include <nn/nim.h>
#include <nn/ac/private/ac.h>
#include <nn/ac/CTR/private/ac_InternalApi.h>
#include <nn/nim/CTR/private/nim_ShopPrivateApi.h>
#include <nn/CTR/CTR_ProgramId.h>
#include <nn/am.h>
#include "Shop.h"
#include "CommonLogger.h"
using namespace ES_NAMESPACE;
using namespace EC_NAMESPACE;
#define NIM_SHOP_RESULT_CHECK(result) \
do { \
if (result.IsFailure()) \
{ \
ECCustomerSupportCode csc; \
nn::nim::Shop::GetCustomerSupportCode(&csc); \
COMMON_LOGGER("CSCode: %d\n", csc); \
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); \
NN_DBG_PRINT_RESULT(result); \
COMMON_LOGGER_DETAIL("Result = %08X\n", result.GetPrintableBits()); \
s_ShopResult = result; \
return; \
} \
} while(0)
namespace
{
nn::Result s_ShopResult = nn::ResultSuccess();
const size_t SHOP_OPERATION_THREAD_STACK_SIZE = 0x1000;
nn::os::Thread s_ShopOperationThread;
nn::os::StackBuffer<SHOP_OPERATION_THREAD_STACK_SIZE> s_ShopOperationThreadStack;
const size_t EC_BUFFER_SIZE = 128 * 1024;
u8 s_EcBufffer[EC_BUFFER_SIZE];
bool s_IsNimShopInitialized = false;
struct ShopThreadParam
{
ConsoleRestore::ShopOperation op;
nn::nim::TitleConfig config;
};
// TitleProgress の ==, != を定義
bool operator==(
nn::nim::TitleProgress& lhs,
nn::nim::TitleProgress& rhs)
{
return (lhs.state == rhs.state &&
lhs.lastResult == rhs.lastResult &&
lhs.downloadedSize == rhs.downloadedSize &&
lhs.totalSize == rhs.totalSize);
}
bool operator!=(
nn::nim::TitleProgress& lhs,
nn::nim::TitleProgress& rhs)
{
return (! (lhs == rhs));
}
// TitleState の文字列を取得
#ifdef COMMON_LOGGER_DETAIL_ENABLE
const char* GetTitleStateString(nn::nim::TitleState state)
{
switch (state)
{
case nn::nim::TITLE_STATE_NOT_INITIALIZED:
return "NOT_INITIALIZED";
case nn::nim::TITLE_STATE_INITIALIZED:
return "INITIALIZED";
case nn::nim::TITLE_STATE_DOWNLOAD_TMD:
return "DOWNLOAD_TMD";
case nn::nim::TITLE_STATE_PREPARE_SAVE_DATA:
return "PREPARE_SAVE_DATA";
case nn::nim::TITLE_STATE_DOWNLOAD_CONTENTS:
return "DOWNLOAD_CONTENTS";
case nn::nim::TITLE_STATE_WAIT_COMMIT:
return "WAIT_COMMIT";
case nn::nim::TITLE_STATE_COMMITTING:
return "COMMITTING";
case nn::nim::TITLE_STATE_FINISHED:
return "FINISHED";
case nn::nim::TITLE_STATE_VERSION_MISMATCH:
return "VERSION_MISMATCH";
default:
return "UNKNOWN";
}
}
#endif
// 空文字列と NULL ポインタをそれぞれ <empty> と NULL として返す
#ifdef COMMON_LOGGER_DETAIL_ENABLE
const char* Cstr(const char* p)
{
return p ? (p[0] ? p : "<empty>") : "NULL";
}
#endif
// ECTicketVersions を出力
void PrintECTicketVersions(const ECTicketVersions& ticketVersions)
{
if (ticketVersions.nTicketVersions == 0)
{
COMMON_LOGGER_DETAIL("No TicketVersions\n");
return;
}
COMMON_LOGGER_DETAIL("----- ECTicketVersions -----\n");
for (u32 i = 0; i < ticketVersions.nTicketVersions; i++)
{
#ifdef COMMON_LOGGER_DETAIL_ENABLE
ECTicketVersion version = ticketVersions.ticketVersions[i];
#endif
COMMON_LOGGER_DETAIL("%03d: 0x%016llx v%d\n", i, version.ticketId, version.version);
}
COMMON_LOGGER_DETAIL("---------------------------\n");
}
// ECAccountInfo の情報を出力
void PrintECAccountInfo(const ECAccountInfo& accountInfo)
{
COMMON_LOGGER_DETAIL("========== ECAccountInfo ==========\n");
COMMON_LOGGER_DETAIL("accountId\n %s\n", Cstr(accountInfo.accountId));
COMMON_LOGGER_DETAIL("accountStatus\n %s\n", Cstr(accountInfo.accountStatus));
if (accountInfo.accountBalance == NULL)
{
COMMON_LOGGER_DETAIL("accountBalance\n NULL\n");
}
else
{
COMMON_LOGGER_DETAIL("accountBalance->amount\n %s\n",
Cstr(accountInfo.accountBalance->amount));
COMMON_LOGGER_DETAIL("accountBalance->currency\n %s\n",
Cstr(accountInfo.accountBalance->currency));
}
if (accountInfo.agreedEULAVersion == NULL)
{
COMMON_LOGGER_DETAIL("agreedEULAVersion\n NULL\n");
}
else
{
COMMON_LOGGER_DETAIL("agreedEULAVersion\n %lld\n",
*accountInfo.agreedEULAVersion);
}
if (accountInfo.latestEULAVersion == NULL)
{
COMMON_LOGGER_DETAIL("latestEULAVersion\n NULL\n");
}
else
{
COMMON_LOGGER_DETAIL("latestEULAVersion\n %lld\n",
*accountInfo.latestEULAVersion);
}
COMMON_LOGGER_DETAIL("country\n %s\n", Cstr(accountInfo.country));
COMMON_LOGGER_DETAIL("extAccountId\n %s\n", Cstr(accountInfo.extAccountId));
COMMON_LOGGER_DETAIL("deviceToken\n %s\n", Cstr(accountInfo.deviceToken));
COMMON_LOGGER_DETAIL("weakToken\n %s\n", Cstr(accountInfo.weakToken));
COMMON_LOGGER_DETAIL("isStandbyMode\n %d\n", accountInfo.isStandbyMode);
if (accountInfo.owned == NULL)
{
COMMON_LOGGER_DETAIL("owned\n NULL\n");
}
else
{
PrintECTicketVersions(*(accountInfo.owned));
}
}
nn::Result PrintNetworkSetting()
{
nn::Result result;
nn::ac::NetworkSetting networkSetting;
result = nn::ac::LoadNetworkSetting(0, networkSetting);
COMMON_LOGGER("SSID: %s\n", networkSetting.wireless.essidSecurity.ssid);
COMMON_LOGGER("DNS : %d.%d.%d.%d\n",
networkSetting.ip.dns[0][0], networkSetting.ip.dns[0][1],
networkSetting.ip.dns[0][2], networkSetting.ip.dns[0][3]);
return result;
}
nn::Result ConnectNetwork()
{
nn::Result result;
nn::ac::Config config;
result = nn::ac::CreateDefaultConfig(&config);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
result = nn::ac::ConnectWithoutEula(config);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
COMMON_LOGGER_DETAIL("Success nn::ac::ConnectWithoutEula\n");
result = PrintNetworkSetting();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result InitializeInternal()
{
nn::Result result;
result = nn::ac::InitializeInternal();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
result = ConnectNetwork();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result FinalizeInternal()
{
nn::Result result = nn::ResultSuccess();
nn::ac::CloseAll();
result = nn::ac::FinalizeInternal();
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
}
namespace ConsoleRestore{
nn::Result ShopOperationConnect();
nn::Result ShopOperationFinalize();
nn::Result CheckStandbyMode(s32 isStandbyMode)
{
if(isStandbyMode)
{
COMMON_LOGGER("Shop is Standby Mode\n");
return nn::MakePermanentResult(nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_NOT_AUTHORIZED);
}
else
{
return nn::ResultSuccess();
}
}
nn::Result ShopOperationConnect(ECAccountInfo** pAccountInfo)
{
nn::Result result = nn::ResultSuccess();
/* -------------------------------------------------------------------
Connect
-------------------------------------------------------------------- */
COMMON_LOGGER_DETAIL("nim::Shop::Connect\n");
result = nn::nim::Shop::Connect(pAccountInfo, s_EcBufffer, EC_BUFFER_SIZE);
NN_UTIL_RETURN_IF_FAILED(result);
result = CheckStandbyMode((*pAccountInfo)->isStandbyMode);
NN_UTIL_RETURN_IF_FAILED(result);
PrintECAccountInfo(**pAccountInfo);
COMMON_LOGGER_DETAIL("\n");
return result;
}
nn::Result ShopOperationInitialize()
{
nn::Result result = nn::ResultSuccess();
/* -------------------------------------------------------------------
Initialize
-------------------------------------------------------------------- */
if (!s_IsNimShopInitialized)
{
COMMON_LOGGER_DETAIL("nim::InitializeForShop\n");
result = nn::nim::InitializeForShop();
NN_UTIL_RETURN_IF_FAILED(result);
s_IsNimShopInitialized = true;
}
/* -------------------------------------------------------------------
SetParameter
-------------------------------------------------------------------- */
COMMON_LOGGER_DETAIL("nim::Shop::SetApplication Id\n");
nn::nim::Shop::SetApplicationId();
NN_UTIL_RETURN_IF_FAILED(result);
COMMON_LOGGER_DETAIL("nim::Shop::SetTIN\n");
result = nn::nim::Shop::SetTin(CONSOLE_RESTORE_TIN);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result ShopOperationConnect()
{
nn::Result result;
result = ShopOperationInitialize();
NN_UTIL_RETURN_IF_FAILED(result);
/* -------------------------------------------------------------------
Connect
-------------------------------------------------------------------- */
ECAccountInfo* pAccountInfo;
result = ShopOperationConnect(&pAccountInfo);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result ShopOperationFinalize()
{
nn::Result result = nn::ResultSuccess();
/* -------------------------------------------------------------------
Finalize
-------------------------------------------------------------------- */
COMMON_LOGGER_DETAIL("nim::FinalizeForShop\n");
result = nn::nim::FinalizeForShop();
NN_UTIL_RETURN_IF_FAILED(result);
s_IsNimShopInitialized = false;
COMMON_LOGGER_DETAIL("util::ac::Finalize\n");
result = FinalizeInternal();
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
namespace
{
void ShopOperationUnregisterCore(bool force)
{
nn::Result result;
result = ShopOperationInitialize();
NIM_SHOP_RESULT_CHECK(result);
ECAccountInfo* pAccountInfo;
result = ShopOperationConnect(&pAccountInfo);
NIM_SHOP_RESULT_CHECK(result);
if (force)
{
if (pAccountInfo->accountStatus && (pAccountInfo->accountStatus[0] == 'R' || pAccountInfo->accountStatus[0]
== 'T'))
{
COMMON_LOGGER_DETAIL("nim::Shop::Unregister\n");
result = nn::nim::Shop::Unregister();
NIM_SHOP_RESULT_CHECK(result);
}
}
else
{
if (pAccountInfo->accountStatus && (pAccountInfo->accountStatus[0] == 'R'))
{
COMMON_LOGGER_DETAIL("nim::Shop::Unregister\n");
result = nn::nim::Shop::Unregister();
NIM_SHOP_RESULT_CHECK(result);
}
else
{
COMMON_LOGGER_DETAIL("Not registered.\n");
}
}
}
// メイン関数
void ShopOperationSingleThreadFunc(ShopThreadParam param)
{
nn::Result result;
s_ShopResult = nn::ResultSuccess();
COMMON_LOGGER_DETAIL("util::ac::Initialize\n");
result = InitializeInternal();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NIM_SHOP_RESULT_CHECK(result);
switch(param.op)
{
case SHOP_OPERATION_CONNECT:
{
result = ShopOperationConnect();
NIM_SHOP_RESULT_CHECK(result);
}
break;
case SHOP_OPERATION_GET_IVS:
{
result = ShopOperationInitialize();
NIM_SHOP_RESULT_CHECK(result);
// IVSを取得する
result = nn::nim::Shop::ImportIvsFromInfrastructure();
NIM_SHOP_RESULT_CHECK(result);
}
break;
case SHOP_OPERATION_UNREGISTER:
{
ShopOperationUnregisterCore(false);
}
break;
case SHOP_OPERATION_FORCE_UNREGISTER:
{
ShopOperationUnregisterCore(true);
}
break;
case SHOP_OPERATION_CONNECT_WITHOUT_CLOSE:
{
result = ShopOperationConnect();
NIM_SHOP_RESULT_CHECK(result);
return;
}
{
case SHOP_OPERATION_DOWNLOAD_TITLE:
COMMON_LOGGER_DETAIL("Try Download %016llx\n", param.config.titleId);
result = nn::nim::Shop::StartDownload(param.config);
if (result == nn::nim::ResultBusy() || result == nn::nim::ResultAlreadyDone())
{
COMMON_LOGGER("Download Content -> Nim is busy\n");
}
else if (result == nn::nim::ResultInvalidTitle())
{
COMMON_LOGGER("Download Content -> Invalid Title\n");
}
else if (result.IsFailure())
{
COMMON_LOGGER("Download Content -> Failure %x\n", result.GetPrintableBits());
}
/* -------------------------------------------------------------------
GetProgress
-------------------------------------------------------------------- */
COMMON_LOGGER_DETAIL("nim::Shop::GetProgress()\n");
nn::nim::TitleProgress before;
nn::nim::TitleProgress latest;
while (true)
{
result = nn::nim::Shop::GetProgress(&latest);
NIM_SHOP_RESULT_CHECK(result);
NIM_SHOP_RESULT_CHECK(latest.lastResult);
// Print progress
if (latest != before)
{
COMMON_LOGGER_DETAIL("%8lld / %8lld (%d:%s)\n",
latest.downloadedSize,
latest.totalSize,
latest.state.Get(),
GetTitleStateString(latest.state));
if (latest.state == nn::nim::TITLE_STATE_FINISHED)
{
COMMON_LOGGER_DETAIL("Finished Download\n");
break;
}
before = latest;
}
// あまりにも頻繁に GetProgress を呼ぶと、ダウンロード処理の速度に
// 影響が出てしまいます。少なくとも数フレーム以上の間隔をあけて
// GetProgress することを推奨します。
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
}
}
break;
}
result = ShopOperationFinalize();
NIM_SHOP_RESULT_CHECK(result);
}
}
void StartShopOperationSingle(ShopOperation op, nn::nim::TitleConfig config)
{
COMMON_LOGGER_DETAIL("Start ShopOperationSingle, %s\n", SHOP_OPERATION_STR[op]);
ShopThreadParam param;
param.op = op;
param.config = config;
s_ShopOperationThread.Start(ShopOperationSingleThreadFunc, param, s_ShopOperationThreadStack);
}
void StartShopOperationSingle(ShopOperation op)
{
ShopThreadParam param;
param.op = op;
COMMON_LOGGER_DETAIL("Start ShopOperationSingle, %s\n", SHOP_OPERATION_STR[op]);
s_ShopOperationThread.Start(ShopOperationSingleThreadFunc, param, s_ShopOperationThreadStack);
}
void FinalizeShopOperationSingle()
{
COMMON_LOGGER_DETAIL("Finalize ShopOperationSingle\n");
s_ShopOperationThread.Join();
s_ShopOperationThread.Finalize();
}
bool IsShopOperationSingleFinished()
{
return s_ShopOperationThread.IsValid() && !s_ShopOperationThread.IsAlive();
}
nn::Result GetShopOperationSingleResult()
{
return s_ShopResult;
}
}

View File

@ -0,0 +1,68 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Shop.h
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$
*---------------------------------------------------------------------------*/
#ifndef SHOP_H_
#define SHOP_H_
#include <nn.h>
#include <nn/nim.h>
namespace ConsoleRestore
{
// ショップサーバにConsoleResotoreが接続するためのTINコード
const char* const CONSOLE_RESTORE_TIN = "987654321";
typedef enum SHOP_OPERATION
{
SHOP_OPERATION_CONNECT, // Shop::ConnectしてCloseするだけ
SHOP_OPERATION_GET_IVS, // Shop::ImportIvsFromInfrastructureを実行
SHOP_OPERATION_UNREGISTER, // Shop::Unregisterを実行
SHOP_OPERATION_FORCE_UNREGISTER, // アカウント移行後でもUnregisterを実行
SHOP_OPERATION_CONNECT_WITHOUT_CLOSE, // Shop::ConnectしてCloseしない
SHOP_OPERATION_DOWNLOAD_TITLE, // Titleをダウンロードする
SHOP_OPERATION_NUM_MAX
} ShopOperation;
// ショップ操作のモード表示用文字列(デバッグ用)
const char* const SHOP_OPERATION_STR[] =
{
"Connect",
"Get SDCI",
"Unregister",
"Force Unregister",
"Connect Without Close",
"Download Title"
};
// 新たにスレッドを立て、ショップ操作を開始する
void StartShopOperationSingle(ShopOperation op, nn::nim::TitleConfig config);
// 新たにスレッドを立て、ショップ操作を開始する
void StartShopOperationSingle(ShopOperation op);
// ショップ操作スレッドを終了する
void FinalizeShopOperationSingle();
// ショップ操作スレッドが終了したかどうか
bool IsShopOperationSingleFinished();
// ショップ操作のResultを取得する
nn::Result GetShopOperationSingleResult();
}
#endif /* SHOP_H_ */

View File

@ -0,0 +1,266 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: TitleDownloader.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/am.h>
#include <nn/nim.h>
#include <nn/CTR/CTR_ProgramId.h>
#include "common_Types.h"
#include "FileName.h"
#include "CommonLogger.h"
#include "HeapManager.h"
#include "TitleDownloader.h"
#include "Shop.h"
#include "SdReaderWriter.h"
namespace
{
bit8 s_buffer1[400 * 1024];
const size_t TITLE_DOWNLOADER_STACK_SIZE = 0x1000;
nn::os::Thread s_TitleDownloaderThread;
nn::os::StackBuffer<TITLE_DOWNLOADER_STACK_SIZE> s_TitleDownloaderThreadStack;
u64 s_Progress;
nn::fs::MediaType GetMediaType(const ES_NAMESPACE::ESTitleId titleId)
{
return (nn::CTR::IsTwlApp(titleId)) ?
nn::fs::MEDIA_TYPE_NAND : nn::fs::MEDIA_TYPE_SDMC;
}
const char *GetAttribute(EC_NAMESPACE::ECNameValuePair *attributes, u32 nAttributes, const char *attributeName)
{
for(int i=0; i<nAttributes; i++)
{
if(std::strcmp(attributes[i].name, attributeName)==0)
{
return attributes[i].value;
}
}
return NULL;
}
nn::Result GetEntry(ES_NAMESPACE::ESTitleId titleId, EC_NAMESPACE::ECTitleCatalogEntry **entry)
{
nn::nim::AttributeName returnAttribute[] =
{"Version", "TitleName", "TitleType", "TitleDescription", "Category", "Publisher", "MaxUserFileSize", "ReleaseDate"};
nn::nim::AttributeFilter attributeFilter[] = {
{"==", "string", "PricingSelection", "RELEASED"}
};
COMMON_LOGGER_DETAIL("ID: %016llx\n", titleId);
EC_NAMESPACE::ECTitleCatalog *titleCatalog;
nn::Result result = nn::nim::Shop::ListTitles(0, 1,
returnAttribute, sizeof(returnAttribute)/sizeof(returnAttribute[0]),
attributeFilter, sizeof(attributeFilter)/sizeof(attributeFilter[0]),
&(titleId), 1,
NULL, 0,
&titleCatalog, s_buffer1, sizeof(s_buffer1));
if(result.IsSuccess())
{
if(titleCatalog->nEntries == 1)
{
*entry = &(titleCatalog->entries[0]);
}
else
{
return nn::MakeStatusResult(nn::Result::SUMMARY_NOT_FOUND, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_NOT_FOUND);
}
}
return result;
}
nn::Result GetTitleConfig(const ES_NAMESPACE::ESTitleId titleId, nn::nim::TitleConfig *titleConfig)
{
EC_NAMESPACE::ECTitleCatalogEntry *entry;
NN_UTIL_RETURN_IF_FAILED(GetEntry(titleId, &entry));
titleConfig->titleId=titleId;
titleConfig->version=std::strtoull(GetAttribute(entry->attributes, entry->nAttributes, "Version"), NULL, 10);
titleConfig->ratingAge=0;
titleConfig->media=GetMediaType(titleId);
COMMON_LOGGER_DETAIL("titleId : 0x%016llx\n", titleConfig->titleId);
COMMON_LOGGER_DETAIL("version : %lld\n" , titleConfig->version);
COMMON_LOGGER_DETAIL("ratingAge : %d\n" , titleConfig->ratingAge);
COMMON_LOGGER_DETAIL("media : %d\n" , titleConfig->media);
return nn::ResultSuccess();
}
} // namespace <unnamed>
namespace ConsoleRestore
{
nn::Result TitleDownloader::m_Result = nn::ResultSuccess();
void TitleDownloaderThreadFunc()
{
TitleDownloader TwlTitleDownloader;
s_Progress = 0;
TwlTitleDownloader.Start();
}
void StartTitleDownload()
{
s_TitleDownloaderThread.Start(TitleDownloaderThreadFunc, s_TitleDownloaderThreadStack);
}
bool IsDownloadTitleFinished()
{
return s_TitleDownloaderThread.IsValid() && !s_TitleDownloaderThread.IsAlive();
}
void FinalizeTitleDownload()
{
s_TitleDownloaderThread.Join();
s_TitleDownloaderThread.Finalize();
}
bool DownloadTitleSucceeded()
{
return TitleDownloader::m_Result.IsSuccess() && GetShopOperationSingleResult().IsSuccess();
}
u32 GetTitleDownloadProgress()
{
return s_Progress;
}
TitleDownloader::TitleDownloader() : m_TwlTiteNum(0)
{
for(u32 i = 0; i < TWL_IMPORTABLE_TITLE_MAX; i++)
{
m_ProgramIdList[i] = 0;
}
}
TitleDownloader::~TitleDownloader()
{
}
nn::Result WaitCancelled()
{
nn::nim::TitleProgress progress;
while(true)
{
// キャンセルがResultとして返ってくる / ダウンロード終了まで待つ
NN_UTIL_RETURN_IF_FAILED(nn::nim::Shop::GetProgress(&progress));
if(progress.lastResult==nn::nim::ResultCancelRequested() || progress.state==nn::nim::TITLE_STATE_FINISHED)
{
break;
}
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
}
return nn::ResultSuccess();
}
void WaitShopOperationAndFinalize()
{
while (!IsShopOperationSingleFinished())
{
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
}
FinalizeShopOperationSingle();
}
void TitleDownloader::Start()
{
m_Result = ListUp();
if(m_Result.IsFailure())
{
return;
}
for(u8 i = 0; i < m_TwlTiteNum; i++)
{
s_Progress = i * 100 / m_TwlTiteNum;
StartShopOperationSingle(SHOP_OPERATION_CONNECT_WITHOUT_CLOSE);
WaitShopOperationAndFinalize();
nn::nim::TitleConfig config;
m_Result = GetTitleConfig(m_ProgramIdList[i], &config);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
if (m_Result.IsSuccess())
{
StartShopOperationSingle(SHOP_OPERATION_DOWNLOAD_TITLE, config);
WaitShopOperationAndFinalize();
}
}
}
nn::Result TitleDownloader::ListUp()
{
COMMON_LOGGER("Read TwlTitle List.\n");
size_t heapSize = common::GetAllocatableSize();
if(heapSize > common::FILE_COPY_HEAP_SIZE)
{
heapSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager heap(heapSize);
char* titleListBuf = reinterpret_cast<char*> (heap.GetAddr());
size_t readSize = 0;
if (titleListBuf != NULL)
{
common::SdReaderWriter sdReader;
m_Result = sdReader.ReadBufWithCmac(common::TWL_TITLELIST_PATHNAME, titleListBuf, heapSize, &readSize);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
if (m_Result.IsSuccess())
{
u32 listHead = 0;
for (u32 i = 0; i < readSize; i++)
{
if (titleListBuf[i] == '\n')
{
char ProgramIdStr[32];
char *error;
std::memcpy(ProgramIdStr, &titleListBuf[listHead], i - listHead);
m_ProgramIdList[m_TwlTiteNum] = std::strtoull(ProgramIdStr, &error, 16);
m_TwlTiteNum++;
COMMON_LOGGER_DETAIL("%016llx\n", m_ProgramIdList[m_TwlTiteNum - 1]);
listHead = i + 1;
}
}
}
COMMON_LOGGER("%d Title(s) found.\n", m_TwlTiteNum);
}
else
{
m_Result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
return m_Result;
}
}

View File

@ -0,0 +1,65 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: TitleDownloader.h
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$
*---------------------------------------------------------------------------*/
#ifndef TITLEDOWNLOADER_H_
#define TITLEDOWNLOADER_H_
#include <nn.h>
namespace ConsoleRestore
{
// 新たにスレッドを立て、タイトルのダウンロードを開始する
void StartTitleDownload();
// タイトルのダウンロードスレッドが終了したかどうか
bool IsDownloadTitleFinished();
// タイトルのダウンロードスレッドが成功したかどうか
bool DownloadTitleSucceeded();
// タイトルのダウンロードスレッドを終了する
void FinalizeTitleDownload();
// タイトルダウンロードの進捗を取得する
u32 GetTitleDownloadProgress();
// ショップからタイトルをダウンロードするためのクラス
class TitleDownloader
{
public:
TitleDownloader();
virtual ~TitleDownloader();
// タイトルのダウンロードを開始する
void Start();
NN_PADDING4;
static nn::Result m_Result;
private:
nn::Result ListUp();
static const size_t TWL_IMPORTABLE_TITLE_MAX = 40;
nn::ProgramID m_ProgramIdList[TWL_IMPORTABLE_TITLE_MAX];
u32 m_TwlTiteNum;
};
}
#endif /* TITLEDOWNLOADER_H_ */

View File

@ -0,0 +1,251 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Updater.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/os.h>
#include <nn/Handle.h>
#include <nn/dbg.h>
#include <nn/nim.h>
#include <nn/cfg.h>
#include <nn/cfg/CTR/cfg_ApiInit.h>
#include <nn/ac/private/ac.h>
#include <nn/ac/CTR/private/ac_InternalApi.h>
#include "CommonLogger.h"
namespace ConsoleRestore
{
using namespace ES_NAMESPACE;
using namespace EC_NAMESPACE;
/* -------------------------------------------------------------------
GetCustomerSupportCode
-------------------------------------------------------------------- */
#define NIM_UPDATER_RESULT_CHECK(result) \
do { \
if (result.IsFailure()) \
{ \
ECCustomerSupportCode csc; \
NN_UTIL_PANIC_IF_FAILED( \
nn::nim::Updater::GetCustomerSupportCode(&csc)); \
COMMON_LOGGER("CSCode: %d\n", csc); \
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); \
NN_DBG_PRINT_RESULT(result); \
COMMON_LOGGER_DETAIL("Result = %08X\n", result.GetPrintableBits()); \
s_Result = result; \
goto LABEL_FINALIZE; \
} \
} while(0)
namespace
{
nn::Result s_Result = nn::ResultSuccess();
const size_t UPDATER_THREAD_STACK_SIZE = 0x1000;
nn::os::Thread s_UpdaterThread;
nn::os::StackBuffer<UPDATER_THREAD_STACK_SIZE> s_UpdaterThreadStack;
u64 s_Progress = 0;
nn::Result PrintNetworkSetting()
{
nn::ac::NetworkSetting networkSetting;
NN_UTIL_RETURN_IF_FAILED(nn::ac::LoadNetworkSetting(0, networkSetting));
COMMON_LOGGER("SSID: %s\n", networkSetting.wireless.essidSecurity.ssid);
COMMON_LOGGER("DNS : %d.%d.%d.%d\n",
networkSetting.ip.dns[0][0], networkSetting.ip.dns[0][1],
networkSetting.ip.dns[0][2], networkSetting.ip.dns[0][3]);
return nn::ResultSuccess();
}
nn::Result ConnectNetwork()
{
nn::Result result = nn::ResultSuccess();
nn::ac::Config config;
result = nn::ac::CreateDefaultConfig(&config);
NN_UTIL_RETURN_IF_FAILED(result);
result = nn::ac::ConnectWithoutEula(config);
NN_UTIL_RETURN_IF_FAILED(result);
COMMON_LOGGER_DETAIL("Success nn::ac::ConnectWithoutEula\n");
NN_UTIL_RETURN_IF_FAILED(PrintNetworkSetting());
return result;
}
nn::Result InitializeInternal()
{
nn::Result result = nn::ResultSuccess();
result = nn::ac::InitializeInternal();
NN_UTIL_RETURN_IF_FAILED(result);
result = ConnectNetwork();
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result FinalizeInternal()
{
nn::Result result = nn::ResultSuccess();
nn::ac::CloseAll();
result = nn::ac::FinalizeInternal();
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
}
void UpdateThreadFunc()
{
nn::Result result;
COMMON_LOGGER_DETAIL("********************UpdateThreadFunc Start********************\n");
nn::cfg::CTR::init::Initialize();
nn::cfg::CfgCountryCode country;
nn::cfg::CfgRegionCode region;
const char *regionStr;
const char *countryStr;
NN_UNUSED_VAR(regionStr);
NN_UNUSED_VAR(countryStr);
country = nn::cfg::GetCountry();
region = nn::cfg::GetRegion();
countryStr = nn::cfg::GetCountryCodeA2(country);
regionStr = nn::cfg::GetRegionCodeA3(region);
COMMON_LOGGER("[Updater] country:%2d:%s\n", country, countryStr);
COMMON_LOGGER("[Updater] region :%2d:%s\n", region, regionStr);
/* -------------------------------------------------------------------
Initialize
-------------------------------------------------------------------- */
COMMON_LOGGER_DETAIL("[Updater] nn::nim::InitializeForUpdater\n");
result = nn::nim::InitializeForUpdater();
NIM_UPDATER_RESULT_CHECK(result);
COMMON_LOGGER_DETAIL("[Updater] InitializeInternal\n");
result = InitializeInternal();
NIM_UPDATER_RESULT_CHECK(result);
/* -------------------------------------------------------------------
StartNetworkUpdate
-------------------------------------------------------------------- */
COMMON_LOGGER_DETAIL("[Updater] nn::nim::Updater::StartNetworkUpdate()\n");
result = nn::nim::Updater::StartNetworkUpdate();
NIM_UPDATER_RESULT_CHECK(result);
/* -------------------------------------------------------------------
GetProgress
-------------------------------------------------------------------- */
COMMON_LOGGER_DETAIL("[Updater] nn::nim::Updater::GetProgress()\n");
while(true)
{
nn::nim::NetworkUpdateProgress progress;
NIM_UPDATER_RESULT_CHECK(nn::nim::Updater::GetProgress(&progress));
NIM_UPDATER_RESULT_CHECK(progress.lastResult);
COMMON_LOGGER_DETAIL("\x1b[1A\x1b[K");
COMMON_LOGGER_DETAIL("Downloading %2lld/%2lld %8lld/%8lld (%d)\n",
progress.downloadedTitleNum,
progress.totalTitleNum,
progress.currentDownloadedSize,
progress.currentTotalSize,
static_cast<s32>(progress.state));
// ゼロ除算を防ぐ
if(progress.totalTitleNum == 0)
{
progress.totalTitleNum++;
progress.downloadedTitleNum++;
}
if(progress.state > nn::nim::CTR::NUP_STATE_CHECKING)
{
s_Progress = progress.downloadedTitleNum * 100 / progress.totalTitleNum;
}
if (progress.state == nn::nim::NUP_STATE_NO_NEED)
{
COMMON_LOGGER("[Updater] No need to NetworkUpdate\n");
s_Progress = 100;
break;
}
if (progress.state == nn::nim::NUP_STATE_FINISHED)
{
COMMON_LOGGER("[Updater] Finished NetworkUpdate\n");
s_Progress = 100;
break;
}
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(300));
}
LABEL_FINALIZE:
/* -------------------------------------------------------------------
Finalize
-------------------------------------------------------------------- */
COMMON_LOGGER_DETAIL("[Updater] nn::nim::FinalizeForUpdater\n");
result = nn::nim::FinalizeForUpdater();
NIM_UPDATER_RESULT_CHECK(result);
result = FinalizeInternal();
NIM_UPDATER_RESULT_CHECK(result);
COMMON_LOGGER_DETAIL("[Updater] Finish nim Updater demo.\n");
}
void StartFGNetworkUpdate()
{
COMMON_LOGGER_DETAIL("Start FGNetworkUpdate\n");
s_Result = nn::ResultSuccess();
s_UpdaterThread.Start(UpdateThreadFunc, s_UpdaterThreadStack);
}
void FinishFGNetworkUpdate()
{
COMMON_LOGGER_DETAIL("Finalize FGNetworkUpdate\n");
s_UpdaterThread.Join();
s_UpdaterThread.Finalize();
}
bool IsNetworkUpdateFinished()
{
return s_UpdaterThread.IsValid() && !s_UpdaterThread.IsAlive();
}
u32 GetUpdateProgress()
{
return s_Progress;
}
nn::Result GetUpdateResult()
{
return s_Result;
}
}

View File

@ -0,0 +1,41 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Updater.h
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$
*---------------------------------------------------------------------------*/
#ifndef UPDATER_H_
#define UPDATER_H_
#include <nn.h>
namespace ConsoleRestore
{
// 新たにスレッドを立て、ネットワークアップデートを開始する
void StartFGNetworkUpdate();
// ネットワークアップデートスレッドを終了する
void FinishFGNetworkUpdate();
// ネットワークアップデートスレッドが終了したかどうか
bool IsNetworkUpdateFinished();
// ネットワークアップデートの進捗を取得する
u32 GetUpdateProgress();
// ネットワークアップデートのResultを取得する
nn::Result GetUpdateResult();
}
#endif /* UPDATER_H_ */

View File

@ -0,0 +1 @@
В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫фВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫ф8ф8фШчГГГГГГВВ╫8фВВВВВГГГГшчфГШФВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫фВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫yнВ╫yнВВВВВ╫YнВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВГГГГШчyнYнВ╫шчшчВВфВВ╫шчyнШчВ╫yнГГГГyнШФГГГГГшчВВВВ╫YнГyнГВВВВВ╫yнфшчГШФГYнyнВВВ╫yнВ╫╨жВВВВВ╫yнВ╫yнВВВВВ╫YнВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫yнГYнГВ╫В╫В╫В╫В╫фВ╫В╫ГyнГ8фВВВВфВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫

View File

@ -0,0 +1 @@
ВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫YнВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫8фВВ╫8ф8фВВВ╫╨ж8ф╨жГГшчГГГГГГГГГГГГГГГГГГГГГГГВВВВВВВВВВ╫8ф8фВВфВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫ГГГГГШФГГГГГГГГГГ жфГГВ╫В╫ жВ╫ГГГГГ жГГВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫8фВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫шчВ╫шчВВВВВГВ╫ШчВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫╨жВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫ГГГГГГГГГГГГГГГГГГШФ8фШчшчВВ жВ╫YнВВВВВГГYнyнГГyнфВ╫В╫В╫В╫В╫В╫В╫В╫фВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫шчшчГшчШФВ╫В╫ГГYнГВ╫В╫В╫В╫В╫шчВ╫шчГГГГГГГГГГГГГГГГВВ╫YнШч жГГГГГГГГГГГГГГГГГГГГГГГГшч╨жВ жВ╫шчВВВВВ╫ШФВ╫ШФВВВВВВВВВВВВВВВВВВВВВ╫шчВ╫yнВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ╫YнВ жГГГГВ╫шчВ╫шчГГГГВВВВВВВВВВВВВВВВВ╫8фВВ╫╨жшчВВВВВ╫YнфyнГГГГГГГГГ жГГГГ╨жВ╫YнВ╫ШФYнВВВВВВВВВВВВВВ╫шч жВВВВВВ╫yнВГШФВ╫В╫фВ╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫В╫ШФВ╫ГГГГГВ╫ШчВ╫YнГГШФГВВВВВВВВВВВВВВВВВВВВВ╫8фВВВВВВВВВВГГГГ жВ╫шчВ╫ГГГшч жВВВВВВВВВВВВВВВВВВВ╫8фВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВВ

View File

@ -0,0 +1,27 @@
#!/usr/bin/env omake
#----------------------------------------------------------------------------
# Project: Horizon
# File: OMakefile
#
# Copyright (C)2009 Nintendo Co., Ltd. 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$
#----------------------------------------------------------------------------
.SUBDIRS: $(exist-dirs \
common \
ConsoleBackup \
ConsoleRestore \
tools \
)
if $(IsTestBuild)
.SUBDIRS: $(exist-dirs tests)
DefineDefaultRules()

View File

@ -0,0 +1,73 @@
#!/usr/bin/env omake
#----------------------------------------------------------------------------
# Project: Horizon
# File: OMakeroot
#
# Copyright (C)2009 Nintendo Co., Ltd. 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:$
#----------------------------------------------------------------------------
# ディレクトリレイアウトについての説明
#
# a) ソースコードがルートディレクトリ直下に配置される場合
# 例:
# /OMakeroot
# /foo/bar/OMakefile
#
# 結果:
# OMakefile と同じディレクトリ以下に objects や images が生成されます。
#
# /foo/bar/objects/...
# /foo/bar/images/..
#
#
# b) ソースコードが sources 以下に配置される場合
# 例:
# /OMakeroot
# /sources/foo/bar/OMakefile
#
# 結果:
# ルートディレクトリ以下に objects や images が生成されます。
#
# /objects/foo/bar/...
# /images/foo/bar/...
#
#
# ルート環境変数の取得
public.HORIZON_ROOT =
if $(defined-env HORIZON_ROOT)
HORIZON_ROOT = $(absname $(getenv HORIZON_ROOT))
export
if $(defined-env CTRSDK_ROOT)
CTRSDK_ROOT = $(absname $(getenv CTRSDK_ROOT))
if $(and $(defined-env HORIZON_ROOT), $(not $(equal $(HORIZON_ROOT), $(CTRSDK_ROOT))))
eprintln(HORIZON_ROOT と CTRSDK_ROOT が一致しません。同じパスを設定するか、どちらか一方だけを定義して下さい。)
exit(1)
HORIZON_ROOT = $(CTRSDK_ROOT)
export
if $(not $(HORIZON_ROOT))
eprintln($"$$CTRSDK_ROOT が定義されていません")
exit(1)
include $(HORIZON_ROOT)/build/omake/commondefs
DefineCommandVars()
.PHONY: all build clean clobber
.PHONY: run run-scripts run-emumem
#
# OMakefile の読み込み
#
.SUBDIRS: .

View File

@ -0,0 +1,76 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Aes_define.h
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$
*---------------------------------------------------------------------------*/
#ifndef AES_DEFINE_H_
#define AES_DEFINE_H_
//マスタリング用ビルド時に有効にする
//#define USE_PROD_KEY
#ifdef NN_BUILD_RELEASE
#ifndef USE_PROD_KEY
#warning !! Using Development Key on Release Build !!
#endif
#endif
#include <nn/drivers/aes/CTR/ARM946ES/driverAes_Types.h>
namespace common
{
#ifndef USE_PROD_KEY
const bit8 key[AES_KEY_SIZE] NN_ATTRIBUTE_ALIGN(4) =
{
0x81, 0x35, 0xc6, 0x54, 0x19, 0x1a, 0x47, 0x2a,
0x6b, 0x78, 0xbe, 0x25, 0x90, 0xf6, 0xee, 0x74
};
const bit8 cmacKey[AES_KEY_SIZE] =
{
0x87, 0xdd, 0xc6, 0xd6, 0xf2, 0xe0, 0x2c, 0xa6,
0x04, 0x21, 0x9c, 0x5e, 0x33, 0x8c, 0x3d, 0xaa
};
const bit8 iv[AES_BLOCK_SIZE] NN_ATTRIBUTE_ALIGN(4) =
{
0xdf, 0x0f, 0xf9, 0x1b, 0x34, 0x47, 0x70, 0x7f,
0x7d, 0x06, 0x85, 0xe6, 0xe7, 0xb6, 0x4e, 0xe9
};
#else
const bit8 key[AES_KEY_SIZE] NN_ATTRIBUTE_ALIGN(4) =
{
0x64, 0x02, 0x6d, 0xbd, 0x9f, 0xb6, 0x62, 0x39,
0x86, 0x90, 0x67, 0x8a, 0xe2, 0xfa, 0xe1, 0x6e
};
const bit8 cmacKey[AES_KEY_SIZE] =
{
0xdf, 0x3c, 0x58, 0xeb, 0xeb, 0xbf, 0x45, 0x6d,
0xc9, 0xbe, 0xe3, 0x10, 0xe2, 0x23, 0xfc, 0x30
};
const bit8 iv[AES_BLOCK_SIZE] NN_ATTRIBUTE_ALIGN(4) =
{
0xe4, 0xcf, 0x58, 0xe5, 0xc9, 0xd6, 0xac, 0x7d,
0xf1, 0xb9, 0x82, 0xf9, 0xa2, 0xd8, 0xda, 0x7b
};
#endif
}
#endif /* AES_DEFINE_H_ */

View File

@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: CommonLogger.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 "CommonLogger.h"
#include "LogConsole_Private.h"
namespace common
{
namespace Logger
{
namespace
{
static CommonLogger s_CommonLogger;
}
CommonLogger::CommonLogger()
{
}
CommonLogger::~CommonLogger()
{
}
void CommonLogger::Initialize(u32 width, u32 height, u32 maxLine, demo::RenderSystemDrawing* renderSystem)
{
m_CriticalSection.Initialize();
GetConsoleInstance()->Initialize(width, height, maxLine, renderSystem);
}
void CommonLogger::Finalize()
{
}
void CommonLogger::Print(const char* fmt, ...)
{
nn::os::CriticalSection::ScopedLock sdLock(m_CriticalSection);
va_list vlist;
va_start(vlist, fmt);
NN_LOGV(fmt, vlist);
GetSdInstance()->Print(fmt, vlist);
GetConsoleInstance()->AddText(fmt, vlist);
va_end(vlist);
}
void CommonLogger::PrintResultSdLog(const char* fmt, ...)
{
nn::os::CriticalSection::ScopedLock sdLock(m_CriticalSection);
va_list vlist;
va_start(vlist, fmt);
GetSdInstance()->Print(fmt, vlist);
va_end(vlist);
}
void CommonLogger::ClearSdLog()
{
nn::os::CriticalSection::ScopedLock sdLock(m_CriticalSection);
GetSdInstance()->Clear();
}
void CommonLogger::SetTextColor(f32 red, f32 green, f32 blue, f32 alpha)
{
GetConsoleInstance()->SetTextColor(red, green, blue, alpha);
}
void CommonLogger::ScrollUp()
{
GetConsoleInstance()->ScrollUp();
}
void CommonLogger::ScrollDown()
{
GetConsoleInstance()->ScrollDown();
}
void CommonLogger::ScrollToBegin()
{
GetConsoleInstance()->ScrollToBegin();
}
void CommonLogger::ScrollToEnd()
{
GetConsoleInstance()->ScrollToEnd();
}
void CommonLogger::DrawConsole()
{
GetConsoleInstance()->Print();
}
CommonLogger* GetLoggerInstance()
{
return &s_CommonLogger;
}
}
}

View File

@ -0,0 +1,164 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: CommonLogger.h
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$
*---------------------------------------------------------------------------*/
#ifndef COMMONLOGGER_H_
#define COMMONLOGGER_H_
#include <nn.h>
#include "demo.h"
#include "SdLogger.h"
#define COMMON_LOGGER( ... ) (void)common::Logger::GetLoggerInstance()->Print(__VA_ARGS__)
#define COMMON_LOGGER_WARN( ... ) \
(void)common::Logger::GetLoggerInstance()->SetTextColor(1.0f, 0.f, 0.f, 1.f); \
(void)common::Logger::GetLoggerInstance()->Print(__VA_ARGS__); \
(void)common::Logger::GetLoggerInstance()->SetTextColor(1.0f, 1.0f, 1.f, 1.f); \
#define COMMON_LOGGER_ERROR( ... ) \
(void)common::Logger::GetLoggerInstance()->SetTextColor(1.0f, 0.2f, 0.2f, 1.f); \
(void)common::Logger::GetLoggerInstance()->Print(__VA_ARGS__); \
(void)common::Logger::GetLoggerInstance()->SetTextColor(1.0f, 1.0f, 1.f, 1.f); \
#define COMMON_LOGGER_RESULT(result, func) \
NN_DBG_PRINT_RESULT(result); \
(void)common::Logger::GetLoggerInstance()->PrintResultSdLog("Func = %s\n", func); \
(void)common::Logger::GetLoggerInstance()->PrintResultSdLog("Result = %X\n", result.GetPrintableBits()); \
#ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
#define COMMON_LOGGER_DEBUG( ... ) COMMON_LOGGER(__VA_ARGS__)
#else // ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
#define COMMON_LOGGER_DEBUG( ... ) ((void)0)
#endif // ifndef NN_SWITCH_DISABLE_DEBUG_PRINT else
#ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
#ifdef COMMON_LOGGER_DETAIL_ENABLE
#define COMMON_LOGGER_DETAIL(...) COMMON_LOGGER(__VA_ARGS__)
#else
#define COMMON_LOGGER_DETAIL( ... ) ((void)0)
#endif
#else
#define COMMON_LOGGER_DETAIL( ... ) ((void)0)
#endif
#define COMMON_LOGGER_RESULT_WITH_LINE(result, line, func) \
NN_LOG("%s\n", func); \
NN_LOG("%d\n", line); \
NN_DBG_PRINT_RESULT(result); \
(void)common::Logger::GetLoggerInstance()->PrintResultSdLog("Func = %s\n", func); \
(void)common::Logger::GetLoggerInstance()->PrintResultSdLog("line = %d\n", line); \
(void)common::Logger::GetLoggerInstance()->PrintResultSdLog("Result = %X\n", result.GetPrintableBits()); \
#define COMMON_LOGGER_RESULT_IF_FAILED(result) \
if(result.IsFailure()) \
{ \
COMMON_LOGGER_RESULT(result, __func__); \
} \
#define COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result) \
if(result.IsFailure()) \
{ \
COMMON_LOGGER_RESULT_WITH_LINE(result, __LINE__, __func__); \
} \
#define COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result) \
if(result.IsFailure()) \
{ \
COMMON_LOGGER_RESULT_WITH_LINE(result, __LINE__, __func__); \
return result; \
} \
#define COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result) \
if(result.IsFailure()) \
{ \
COMMON_LOGGER_RESULT_WITH_LINE(result, __LINE__, __func__); \
return false; \
} \
#define COMMON_LOGGER_RETURN_VOID_IF_FAILED(result) \
if(result.IsFailure()) \
{ \
COMMON_LOGGER_RESULT_WITH_LINE(result, __LINE__, __func__); \
return; \
} \
#define COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, setbool) \
if(result.IsFailure()) \
{ \
COMMON_LOGGER_RESULT_WITH_LINE(result, __LINE__, __func__); \
setbool = false; \
return; \
} \
#define COMMON_LOGGER_RETURN_FALSE(result) \
COMMON_LOGGER_RESULT_WITH_LINE(result, __LINE__, __func__); \
return false; \
namespace common
{
namespace Logger
{
// SDカードのログと下画面ログを同時に扱うためのクラス
class CommonLogger
{
public:
CommonLogger();
~CommonLogger();
void Initialize(u32 width, u32 height, u32 maxLine, demo::RenderSystemDrawing* renderSystem);
void Finalize();
// SDログに書き込み、下画面ログ出力のためのバッファに溜め込む
void Print(const char* fmt, ...);
// SDログのみにResult値を出力する
void PrintResultSdLog(const char* fmt, ...);
// SDカードのログファイルを消去する
void ClearSdLog();
// 下画面ログのフォントカラーを設定する
void SetTextColor(f32 red, f32 green, f32 blue, f32 alpha);
// 下画面ログを上スクロールする
void ScrollUp();
// 下画面ログを下スクロールする
void ScrollDown();
// 下画面ログの先頭にスクロールする
void ScrollToBegin();
// 下画面ログの末尾にスクロールする
void ScrollToEnd();
// バッファに溜め込まれた文字列を下画面ログに書き込む
void DrawConsole();
private:
nn::os::CriticalSection m_CriticalSection;
};
CommonLogger* GetLoggerInstance();
}
}
#endif /* COMMONLOGGER_H_ */

View File

@ -0,0 +1,208 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: DrawSystemState.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 "DrawSystemState.h"
#include "ResFont.h"
#include "version.h"
#include <nn/nwm.h>
const u16 PROGRESS_MAX_LINES = 129;
namespace common
{
namespace
{
u8 s_CupMajor;
u8 s_CupMinor;
u8 s_CupMicro;
u8 s_NupMajor;
nn::cfg::CTR::CfgRegionCode s_Region;
u8 s_SerialNo[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN + 1];
bit64 s_DeviceId;
char8 s_MacAddress[nn::nwm::Mac::MAC_STRING_SIZE];
u64 s_FriendCode;
u8 s_BatteryRemain;
std::string s_AdapterState;
u8 s_Progress;
::std::vector<std::string>* s_OperationMessage;
bool s_ReadFriendCode;
}
u32 GetRenderTarget(u32 target, bool flip)
{
if(flip)
{
if(target == NN_GX_DISPLAY0)
{
return NN_GX_DISPLAY1;
}
else
{
return NN_GX_DISPLAY0;
}
}
else
{
return target;
}
}
void SetTextWriterCore()
{
GetTextWriter()->Print("\n");
GetTextWriter()->Printf("System Ver. %d.%d.%d-%d\n", s_CupMajor, s_CupMinor, s_CupMicro, s_NupMajor);
GetTextWriter()->Printf("System Region %s\n", nn::cfg::CTR::GetRegionCodeA3(s_Region));
GetTextWriter()->Printf("Serial No. %s\n", s_SerialNo);
GetTextWriter()->Printf("Device ID %llu\n", s_DeviceId);
GetTextWriter()->Printf("MAC Address %s\n", s_MacAddress);
if (s_ReadFriendCode)
{
GetTextWriter()->Printf("Friend Code %04u-%04u-%04u\n",
static_cast<u32>(s_FriendCode / 100000000ULL % 10000ULL), static_cast<u32> (s_FriendCode / 10000ULL % 10000ULL),
static_cast<u32> (s_FriendCode % 10000ULL));
}
GetTextWriter()->Printf("Battery %d%%\n", s_BatteryRemain);
GetTextWriter()->Printf("AC Adapter %s\n", s_AdapterState.c_str());
GetTextWriter()->Printf("Progress %02d%%\n", s_Progress);
GetTextWriter()->Print("\n");
::std::vector<std::string>::iterator it;
for (it = s_OperationMessage->begin(); it != s_OperationMessage->end(); it++)
{
GetTextWriter()->Printf("%s\n", it->c_str());
}
}
void DrawSystemState
(
const char* toolName,
demo::RenderSystemDrawing& renderSystem,
nn::util::FloatColor titleColor,
bool flip,
std::string& adapterState,
u8 cupMajorVersion,
u8 cupMinorVersion,
u8 cupMicroVersion,
u8 nupVersion,
u8 batteryRemain,
u64 deviceId,
u64 friendCode,
u32 progress,
bool isProcessFailed,
bool isProcessSucceeded,
bool isProcessWarning,
char8* macAddress,
::std::vector<std::string>& operationMessage,
nn::cfg::CTR::CfgRegionCode region,
u8* serialNo,
bool readFriendCode
)
{
// パラメータ保存
s_AdapterState = adapterState;
s_CupMajor = cupMajorVersion;
s_CupMinor = cupMinorVersion;
s_CupMicro = cupMicroVersion;
s_NupMajor = nupVersion;
s_BatteryRemain = batteryRemain;
s_DeviceId = deviceId;
s_FriendCode = friendCode;
s_Progress = progress;
std::memcpy(s_MacAddress, macAddress, sizeof(s_MacAddress));
s_Region = region;
std::memcpy(s_SerialNo, serialNo, sizeof(s_SerialNo));
s_SerialNo[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN] = '\0';
s_OperationMessage = &operationMessage;
s_ReadFriendCode = readFriendCode;
// デフォルトで上画面に描画するもの
renderSystem.SetRenderTarget(GetRenderTarget(NN_GX_DISPLAY0, flip));
if (isProcessSucceeded)
{
renderSystem.SetClearColor(GetRenderTarget(NN_GX_DISPLAY0, flip), SUCCESS_COLOR);
}
else if (isProcessWarning)
{
renderSystem.SetClearColor(GetRenderTarget(NN_GX_DISPLAY0, flip), WARN_COLOR);
}
else if (isProcessFailed)
{
renderSystem.SetClearColor(GetRenderTarget(NN_GX_DISPLAY0, flip), FAIL_COLOR);
}
else
{
renderSystem.SetClearColor(GetRenderTarget(NN_GX_DISPLAY0, flip), NORMAL_COLOR);
}
renderSystem.Clear();
renderSystem.SetColor(1.f, 1.f, 1.f);
u32 line = 0;
size_t fontwidth = 8;
size_t fontheight = fontwidth + 2;
SetDrawTextHandler(SetTextWriterCore);
DrawResFont(GetRenderTarget(NN_GX_DISPLAY0, flip));
renderSystem.SetFontSize(fontwidth);
// ツール名、ハイライト
renderSystem.DrawText(0, line++ * fontheight, "%s %s-%s-%s", toolName, CONSOLE_REPAIR_VERSION_MAJOR,
CONSOLE_REPAIR_VERSION_MINOR, CONSOLE_REPAIR_VERSION_MICRO);
renderSystem.SetColor(titleColor.r, titleColor.g, titleColor.b);
renderSystem.FillRectangle(0, (line - 1) * fontheight, 400, fontheight);
renderSystem.SetColor(1.f, 1.f, 1.f);
renderSystem.DrawText(0, line++ * fontheight, "");
// プログレスバー
fontwidth = 8;
fontheight = 14;
if(readFriendCode)
{
line += 9;
}
else
{
line += 8;
}
const u8 offset = 19;
const u8 diff = 4;
renderSystem.SetColor(0.f, 0.2f, 0.f);
renderSystem.DrawLine(offset * fontwidth, (line - 1) * fontheight - diff, offset * fontwidth + PROGRESS_MAX_LINES, (line - 1)
* fontheight - diff);
renderSystem.DrawLine(offset * fontwidth, (line - 1) * fontheight - diff, offset * fontwidth, (line) * fontheight - diff);
renderSystem.DrawLine(offset * fontwidth, (line) * fontheight - diff, offset * fontwidth + PROGRESS_MAX_LINES, (line) * fontheight - diff);
renderSystem.DrawLine(offset * fontwidth + PROGRESS_MAX_LINES, (line - 1) * fontheight - diff, offset * fontwidth
+ PROGRESS_MAX_LINES, (line) * fontheight + 1 - diff);
renderSystem.SetColor(0.f, 0.5f, 0.f);
renderSystem.FillRectangle(offset * fontwidth, (line - 1) * fontheight - diff, progress * PROGRESS_MAX_LINES / 100 + 1,
fontheight);
renderSystem.SetColor(1.f, 1.f, 1.f);
renderSystem.DrawText(0, line++ * fontheight, "");
}
}

View File

@ -0,0 +1,82 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: DrawSystemState.h
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$
*---------------------------------------------------------------------------*/
#ifndef DRAWSYSTEMSTATE_H_
#define DRAWSYSTEMSTATE_H_
#include <nn.h>
#include "demo.h"
#include <nn/cfg/CTR/cfg_RegionCode.h>
#include <nn/os/os_SharedInfo.h>
#include <nn/cfg/CTR/cfg_Api.h>
#include <nn/cfg/CTR/cfg_ApiInit.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/util/util_Color.h>
#include <string>
#include <vector>
#include "common_Types.h"
// 描画色の定義
#define WHITE_COLOR 1.f, 1.f, 1.f, 1.f
#define GRAY_COLOR 0.5, 0.5, 0.5, 1.f
#define RED_COLOR 1.f, 0.f, 0.f, 1.f
#define GREEN_COLOR 0.f, 1.f, 0.f, 1.f
#define BLUE_COLOR 0.f, 0.f, 1.f, 1.f
#define SUCCESS_COLOR 0.f, 0.6f,0.f, 1.f
#define FAIL_COLOR 0.6f, 0.f,0.f, 1.f
#define NORMAL_COLOR 0.f, 0.f, 0.f, 1.f
#define WARN_COLOR 0.43f, 0.43f, 0.f, 1.f
namespace common
{
// 現在の描画先ディスプレイを返す
// target NN_GX_DISPLAY0 または NN_GX_DISPLAY1
// flip 上下画面を入れ替えているかどうか
u32 GetRenderTarget(u32 target, bool flip = false);
// システム状態を描画する
// InitializeResFont()、demo::RenderSystemDrawing.Initializeが呼び出されている必要がある
void DrawSystemState
(
const char* toolName,
demo::RenderSystemDrawing& renderSystem,
nn::util::FloatColor titleColor,
bool flip,
std::string& adapterState,
u8 cupMajorVersion,
u8 cupMinorVersion,
u8 cupMicroVersion,
u8 nupVersion,
u8 batteryRemain,
u64 deviceId,
u64 friendCode,
u32 progress,
bool isProcessFailed,
bool isProcessSucceeded,
bool isProcessWarning,
char8* macAddress,
::std::vector<std::string>& operationMessage,
nn::cfg::CTR::CfgRegionCode region,
u8* s_SerialNo,
bool readFriendCode
);
}
#endif /* DRAWSYSTEMSTATE_H_ */

View File

@ -0,0 +1,158 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: FileChecker.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 "FileChecker.h"
#include "SdMountManager.h"
namespace common
{
bool s_FileExistsChecked[EXISTS_MAX];
bool s_FileExistsCheckeResult[EXISTS_MAX];
bool CheckFileExists(const wchar_t* path)
{
nn::Result result;
bool exist = false;
result = common::SdMountManager::Mount();
if (result.IsSuccess())
{
nn::fs::FileInputStream fis;
result = fis.TryInitialize(path);
if(result.IsSuccess())
{
exist = true;
}
fis.Finalize();
}
common::SdMountManager::Unmount();
return exist;
}
bool ExistsFile(FileExistsCheck index)
{
if(index > EXISTS_MAX)
{
NN_LOG("Invalid File index!!\n");
return false;
}
if(s_FileExistsChecked[index])
{
return s_FileExistsCheckeResult[index];
}
s_FileExistsChecked[index] = true;
s_FileExistsCheckeResult[index] = CheckFileExists(FILENAME_TABLE[index]);
return s_FileExistsCheckeResult[index];
}
void ClearFileCheck(FileExistsCheck index)
{
if(index > EXISTS_MAX)
{
NN_LOG("Invalid File index!!\n");
return;
}
s_FileExistsChecked[index] = false;
}
bool ExistsUpdateCheckedFile()
{
return ExistsFile(EXISTS_UPDATE_FINISHED);
}
bool ExistsSerialNumberFile()
{
return ExistsFile(EXISTS_SERIAL_NUMBER);
}
bool ExistsIVSFile()
{
return ExistsFile(EXISTS_IVS);
}
bool ExistsConsoleInitializedFile()
{
return ExistsFile(EXISTS_CONSOLE_INTIALIZED);
}
bool ExistsWriteFinishedFile()
{
return ExistsFile(EXISTS_WRITE_FINISHED);
}
bool ExistsAPSetting()
{
return ExistsFile(EXISTS_AP_SETTING);
}
bool ExistsRtcSyncFinishedFile()
{
return ExistsFile(EXISTS_RTC_SYNC_FINISHED);
}
bool ExistsCountryLanguageFile()
{
return ExistsFile(EXISTS_COUNTRY_LANGUAGE);
}
bool ExistsRegionData()
{
return ExistsFile(EXISTS_REGION_DATA);
}
bool ExistsDeleteAccountChecked()
{
return ExistsFile(EXISTS_DELETE_ACCOUNT);
}
bool ExistsTransferAccountChecked()
{
return ExistsFile(EXISTS_TRANSFER_ACCOUNT);
}
bool ExistsDownloadIvsCheckedFile()
{
return ExistsFile(EXISTS_DOWNLOAD_IVS);
}
bool ExistsTwlTitleListFile()
{
return ExistsFile(EXISTS_TWL_TITLELIST);
}
bool ExistsFileMoveContextFile()
{
return ExistsFile(EXISTS_MOVE_CONTEXT);
}
void InitializeFileCheck()
{
for(u32 i = 0; i < EXISTS_MAX; i++)
{
s_FileExistsChecked[i] = false;
}
}
}

View File

@ -0,0 +1,92 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: FileChecker.h
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$
*---------------------------------------------------------------------------*/
#ifndef FILECHECKER_H_
#define FILECHECKER_H_
#include "FileName.h"
namespace common
{
// チェックしたいファイルのリスト
typedef enum FILE_EXISTS_CHECK
{
EXISTS_UPDATE_FINISHED, // ネットワークアップデート完了
EXISTS_SERIAL_NUMBER, // シリアルナンバー
EXISTS_IVS, // IVS
EXISTS_CONSOLE_INTIALIZED, // 本体初期化完了
EXISTS_WRITE_FINISHED, // 書き込み完了
EXISTS_AP_SETTING, // 無線設定ファイル
EXISTS_RTC_SYNC_FINISHED, // RTC書き込み完了
EXISTS_COUNTRY_LANGUAGE, // 国設定書き込み完了
EXISTS_REGION_DATA, // リージョン
EXISTS_DELETE_ACCOUNT, // アカウント削除完了
EXISTS_TRANSFER_ACCOUNT, // アカウント移行完了
EXISTS_DOWNLOAD_IVS, // IVSダウロード完了
EXISTS_TWL_TITLELIST, // TWLタイトルリストファイル
EXISTS_MOVE_CONTEXT, // ファイル移動用コンテキスト
EXISTS_MAX
} FileExistsCheck;
// チェックしたいファイルのリストに対応したパス
const wchar_t* const FILENAME_TABLE[EXISTS_MAX] =
{
common::UPDATE_CHECK_PATHNAME,
common::SERIAL_PATHNAME,
common::IVS_PATHNAME,
common::INITIALIZED_CHECK_PATHNAME,
common::WRITE_FINISHED_CHECK_PATHNAME,
common::AP_SETTING_PATHNAME,
common::RTC_SYNC_CHECK_PATHNAME,
common::COUNTRY_SETTING_PATHNAME,
common::REGION_DATA_PATHNAME,
common::DELETE_ACCOUNT_CHECK_PATHNAME,
common::TRANSFER_ACCOUNT_CHECK_PATHNAME,
common::DOWNLOAD_IVS_CHECK_PATHNAME,
common::TWL_TITLELIST_PATHNAME,
common::MOVE_CONTEXT_PATHNAME
};
// ファイルが存在するかどうか
bool CheckFileExists(const wchar_t* path);
bool ExistsUpdateCheckedFile();
bool ExistsSerialNumberFile();
bool ExistsIVSFile();
bool ExistsConsoleInitializedFile();
bool ExistsWriteFinishedFile();
bool ExistsAPSetting();
bool ExistsRtcSyncFinishedFile();
bool ExistsCountryLanguageFile();
bool ExistsRegionData();
bool ExistsDeleteAccountChecked();
bool ExistsTransferAccountChecked();
bool ExistsDownloadIvsCheckedFile();
bool ExistsTwlTitleListFile();
bool ExistsFileMoveContextFile();
// ファイルチェックの結果を初期化する
// 一度チェックするとその結果を保持するため
// ファイルを作成したり削除した時に呼ぶ必要がある
void ClearFileCheck(FileExistsCheck index);
// 全てのファイルチェックの結果を初期化する
void InitializeFileCheck();
}
#endif /* FILECHECKER_H_ */

View File

@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: FileName.h
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$
*---------------------------------------------------------------------------*/
#ifndef FILENAME_H_
#define FILENAME_H_
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
namespace common
{
const char* const NAND_ARCHIVE_NAME = "nand:";
const char* const SDMC_ARCHIVE_NAME = "sdmc:";
const char* const NAND_TWL_PHOTO_ARCHIVE_NAME = "twlp:";
const char* const NAND_TWL_SOUND_ARCHIVE_NAME = "twls:";
const char* const NAND_TWL_ARCHIVE_NAME = "twln:";
const char* const BASHOTORYA_FILE_NAME = "bashotorya.dat";
const char* const SD_SAVEDATA_SYS_ROOT_PATH = "sdmc:/CTR_Console_Repair/CTRBackup/sysdata";
const char* const SD_SAVEDATA_EXT_ROOT_PATH = "sdmc:/CTR_Console_Repair/CTRBackup/extdata";
const wchar_t* const LOG_ROOT_DIRECTORY_PATH = L"sdmc:/CTR_Console_Repair";
const wchar_t* const SD_SAVEDATA_ROOT_NAME = L"CTR_Console_Repair/CTRBackup/";
const wchar_t* const SD_SAVEDATA_TWL_PHOTO_ROOT_NAME = L"CTR_Console_Repair/TWLPhotoBackup/";
const wchar_t* const SD_SAVEDATA_TWL_SOUND_ROOT_NAME = L"CTR_Console_Repair/TWLSoundBackup/";
const wchar_t* const SD_SAVEDATA_TWL_ROOT_NAME = L"CTR_Console_Repair/TWLBackup/";
const wchar_t* const NIM_SAVEDATA_DIRECTORY_NAME = L"sysdata/0001002c";
const wchar_t* const LOG_PATHNAME = L"CTR_Console_Repair/Migration_Log.txt";
const wchar_t* const LOG_FILENAME = L"Migration_Log.txt";
const wchar_t* const COUNTRY_SETTING_PATHNAME = L"sdmc:/CTR_Console_Repair/CountrySetting.bin";
const wchar_t* const AP_SETTING_FILENAME = L"CTR_Repair_Accsess_Point_Setting.txt";
const wchar_t* const AP_SETTING_PATHNAME = L"sdmc:/CTR_Repair_Accsess_Point_Setting.txt";
const wchar_t* const NOR_PATHNAME = L"sdmc:/CTR_Console_Repair/NtrNorSetting.bin";
const wchar_t* const SERIAL_PATHNAME = L"sdmc:/CTR_Console_Repair/serial.bin";
const wchar_t* const MCU_RTC_PATHNAME = L"sdmc:/CTR_Console_Repair/rtc.bin";
const wchar_t* const IVS_NAND_PATHNAME = L"nand:/private/movable.sed";
const wchar_t* const IVS_PATHNAME = L"sdmc:/CTR_Console_Repair/movable.sed";
const wchar_t* const NAND_DATA_ROOT_PATHNAME_WITH_SLASH = L"nand:/data/";
const wchar_t* const NAND_TWL_PHOTO_DATA_ROOT_PATHNAME_WITH_SLASH = L"twlp:/";
const wchar_t* const NAND_TWL_SOUND_DATA_ROOT_PATHNAME_WITH_SLASH = L"twls:/";
const wchar_t* const NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH = L"twln:/title";
const wchar_t* const SDMC_ROOT_DIRECTORY_PATH = L"sdmc:/";
const wchar_t* const WRITE_FINISHED_CHECK_PATHNAME = L"sdmc:/CTR_Console_Repair/WriteFinished";
const wchar_t* const UPDATE_CHECK_PATHNAME = L"sdmc:/CTR_Console_Repair/UpdateFinished";
const wchar_t* const DELETE_ACCOUNT_CHECK_PATHNAME = L"sdmc:/CTR_Console_Repair/AccountDeletedChecked";
const wchar_t* const TRANSFER_ACCOUNT_CHECK_PATHNAME = L"sdmc:/CTR_Console_Repair/AccountTransferedChecked";
const wchar_t* const DOWNLOAD_IVS_CHECK_PATHNAME = L"sdmc:/CTR_Console_Repair/DownloadSDCIFinished";
const wchar_t* const INITIALIZED_CHECK_PATHNAME = L"sdmc:/CTR_Console_Repair/ConsoleInitialized";
const wchar_t* const RTC_SYNC_CHECK_PATHNAME = L"sdmc:/CTR_Console_Repair/RtcSyncFinished";
const wchar_t* const PLAYHISTORY_PATHNAME = L"sdmc:/CTR_Console_Repair/playhistory.bin";
const wchar_t* const PLAYHISTORY_COUNT_PATHNAME = L"sdmc:/CTR_Console_Repair/playhistoryCount.bin";
const wchar_t* const CFG_CALIBRATION_PATHNAME = L"sdmc:/CTR_Console_Repair/cfgCalibration.bin";
const wchar_t* const VERSION_DATA_PATHNAME = L"sdmc:/CTR_Console_Repair/version.bin";
const wchar_t* const REGION_DATA_PATHNAME = L"sdmc:/CTR_Console_Repair/Region.bin";
const wchar_t* const DEVICE_ID_PATHNAME = L"sdmc:/CTR_Console_Repair/deviceId.bin";
const wchar_t* const FILE_LIST_PATHNAME = L"sdmc:/CTR_Console_Repair/FileList.txt";
const wchar_t* const TWL_TITLELIST_PATHNAME = L"sdmc:/CTR_Console_Repair/TwlTitleList.txt";
const wchar_t* const MOVE_CONTEXT_PATHNAME = L"sdmc:/CTR_Console_Repair/MoveContext.bin";
const wchar_t* const SD_NINTENDO_3DS_ROOT_PATH = L"sdmc:/Nintendo 3DS/";
const wchar_t* const SD_SAEVDATA_SYS_NAME = L"sysdata";
const wchar_t* const SD_SAEVDATA_EXT_NAME = L"extdata";
enum TWL_PATH_INDEX
{
TWL_PHOTO = 0,
TWL_SOUND,
TWL_PATHNAME_MAX
};
const char* const TWL_ARCHIVE_NAME_TABLE[TWL_PATHNAME_MAX] =
{
common::NAND_TWL_PHOTO_ARCHIVE_NAME,
common::NAND_TWL_SOUND_ARCHIVE_NAME
};
const wchar_t* const SD_TWL_ROOTNAME_TABLE[TWL_PATHNAME_MAX] =
{
common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME,
common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME
};
const wchar_t* const NAND_TWL_ROOT_PATHNAME_WITH_SLASH_TABLE[TWL_PATHNAME_MAX] =
{
common::NAND_TWL_PHOTO_DATA_ROOT_PATHNAME_WITH_SLASH,
common::NAND_TWL_SOUND_DATA_ROOT_PATHNAME_WITH_SLASH
};
const u32 TWL_FS_ARCHIVE_KIND[TWL_PATHNAME_MAX] =
{
nn::fs::CTR::ARCHIVE_TYPE_TWL_PHOTO,
nn::fs::CTR::ARCHIVE_TYPE_TWL_SOUND
};
}
#endif /* FILENAME_H_ */

View File

@ -0,0 +1,826 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: FileTransfer.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 <vector>
#include <string>
#include <nn/crypto/crypto_AesCmac.h>
#include <nn/crypto/crypto_SwAesCtrContext.h>
#include <nn/crypto/crypto_Sha256.h>
#include <nn/crypto/crypto_SwAesCmac.h>
#include "Aes_define.h"
#include "FileTransfer.h"
#include "CommonLogger.h"
#include "common_Types.h"
#include "FileName.h"
namespace common
{
namespace
{
u64 s_TotalFileSize;
u64 s_FinishedFileSize = 0;
u64 s_Progress = 0;
}
bool VerifyMac(nn::fs::FileInputStream* sdFile, nn::fs::FileStream* nandFile, s64 sdFileSize, s64 nandFileSize,
const wchar_t* nandPath, void* buf, size_t bufSize);
bool ConfirmFile(nn::fs::FileInputStream* from_file, nn::fs::FileStream* to_file, s64 sdFileSize, s64 nandFileSize,
void* buf, size_t bufSize, const wchar_t* sdPath, const wchar_t* tmpPath, const wchar_t* truePath);
void AddPkcsPadding(u8* paddingSize, void* buf, size_t bufSize, s32* readSize);
bool AddPathNameAndUpdateContext(nn::fs::FileOutputStream* file, const wchar_t *str, s64 fileSize,
nn::crypto::Sha256Context* context);
const char* GetCharStr(const wchar_t* path)
{
static char filename[nn::fs::MAX_FILE_PATH_LENGTH];
std::memset(filename, 0, sizeof(filename));
std::wcstombs(filename, path, sizeof(filename));
filename[sizeof(filename) - 1] = '\0';
return filename;
}
nn::Result CalculateFileNum(std::wstring currentDirectory, u32& fileNum, s64& fileSize)
{
nn::fs::Directory dir;
nn::Result result;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
result = dir.TryInitialize(currentDirectory.c_str());
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
if (numEntry == 0)
{
// カレントディレクトリを閉じる
dir.Finalize();
// カレントディレクトリの子を開く
for (entryIndex = entryList.begin(); entryIndex != entryList.end(); entryIndex++)
{
if (entryIndex->attributes.isDirectory)
{
result = CalculateFileNum(currentDirectory + std::wstring(entryIndex->entryName) + std::wstring(L"/"),
fileNum, fileSize);
}
}
return result;
}
entryList.push_back(entry);
fileNum++;
fileSize += entry.entrySize;
}
}
bool ExistsInList(ImportDataList* fileList, const wchar_t* path, bool isDirectory)
{
std::wstring sdPath(path);
if(isDirectory)
{
sdPath += std::wstring(L"/");
}
char str[nn::fs::MAX_FILE_PATH_LENGTH];
std::strlcpy(str, GetCharStr(sdPath.c_str()), sizeof(str));
bool returnValue = false;
for(ImportDataList::iterator it = fileList->begin(); it != fileList->end(); it++)
{
if(std::strcmp(str, it->fileName.c_str()) == 0)
{
returnValue = true;
NN_LOG("%s exists in FileList.txt\n", str);
break;
}
}
return returnValue;
}
bool ExportTwlSaveDirectory(const wchar_t* dirPath, nn::fs::FileOutputStream* list,
nn::crypto::Sha256Context* listContext)
{
NN_LOG("Create Directory %ls\n", dirPath);
nn::Result result = nn::fs::TryCreateDirectory(dirPath);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return AddPathNameAndUpdateContext(list, dirPath, -1, listContext);
}
bool ExportTwlSaveFile(const wchar_t* from_path, const wchar_t* to_path, void* buf, const size_t bufSize,
nn::fs::FileOutputStream* list, nn::crypto::Sha256Context* listContext)
{
NN_LOG("from = %ls\n", from_path);
NN_LOG("to = %ls\n", to_path);
nn::Result result;
// ファイル作成
nn::fs::FileInputStream from_file;
nn::fs::FileStream to_file;
s64 filesize;
s32 readsize;
s32 writesize;
NN_LOG("Copy File %ls\n", from_path);
// 読み込み対象ファイル開く
result = from_file.TryInitialize(from_path);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 読み込み対象ファイルのサイズ取得
result = from_file.TryGetSize(&filesize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (!AddPathNameAndUpdateContext(list, to_path, filesize, listContext))
{
return false;
}
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
size_t totalReadSize = 0;
nn::crypto::Sha256Context context;
context.Initialize();
// ファイルサイズをヘッダに書いておく
// 書き込み対象ファイル作成
result = nn::fs::TryCreateFile(to_path, filesize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = to_file.TryInitialize(to_path,
nn::fs::OPEN_MODE_READ | nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// フルパスをハッシュに含める
context.Update(from_path, std::wcslen(from_path) * sizeof(wchar_t));
BackupDataHeader header;
BackupDataHeader enc;
std::memset(&header, 0, sizeof(header));
std::memset(&enc, 0, sizeof(enc));
header.size = filesize;
result = swAesCtrContext.Encrypt(&enc, &header, sizeof(header));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context.Update(&enc, sizeof(enc));
s32 writeSize;
result = to_file.TryWrite(&writeSize, &enc, sizeof(enc), false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
while (1)
{
// バッファの後半半分を暗号・復号用に使う
result = from_file.TryRead(&readsize, buf, bufSize / 2);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
totalReadSize += readsize;
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (readsize == 0)
{
NN_LOG("Add CMAC %ls\n", from_path);
// SHA256を計算してCMACを付加する
bit8 sha256Hash[nn::crypto::Sha256Context::HASH_SIZE];
context.GetHash(sha256Hash);
bit8 cmac[nn::crypto::AES_CMAC_MAC_SIZE];
result = nn::crypto::CalculateAesCmacSw(cmac, sha256Hash, nn::crypto::Sha256Context::HASH_SIZE,
common::cmacKey);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = to_file.TryWrite(&writesize, cmac, sizeof(cmac));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = to_file.TryFlush();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
break;
}
else
{
NN_LOG("EncryptSize = %d\n", readsize);
u8 paddingSize = 0;
AddPkcsPadding(&paddingSize, reinterpret_cast<bit8*>(buf), bufSize / 2, &readsize);
// 暗号化後SHA256を計算しつつ書き込み
result = swAesCtrContext.Encrypt(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readsize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context.Update(reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize, false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 事前計算したファイルサイズに一致させるためパディング分減算
readsize -= paddingSize;
s_FinishedFileSize += readsize;
s_Progress = s_FinishedFileSize * 100 / s_TotalFileSize;
NN_LOG( "finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress);
}
}
to_file.Finalize();
from_file.Finalize();
return true;
}
bool CopyDirectory(ImportDataList* fileList, const wchar_t * from_path, const wchar_t * to_path, void* buf,
const size_t bufSize, bool encode, nn::fs::FileOutputStream* list, nn::crypto::Sha256Context* listContext)
{
nn::fs::Directory from_dir;
nn::fs::DirectoryEntry entry;
s32 numread = 0;
std::wostringstream target_from;
std::wostringstream target_to;
nn::Result result = from_dir.TryInitialize(from_path);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
while (1)
{
result = from_dir.TryRead(&numread, &entry, 1);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if(numread == 0)
{
break;
}
if (std::wcscmp(entry.entryName, L".") == 0 || std::wcscmp(entry.entryName, L"..") == 0)
{
continue;
}
target_from.str(L"");
target_from.clear(std::stringstream::goodbit);
target_from << from_path << entry.entryName;
target_to.str(L"");
target_to.clear(std::stringstream::goodbit);
target_to << to_path << entry.entryName;
// NAND書き込みの場合はリストに存在するかチェックする
if (!encode)
{
if (!ExistsInList(fileList, target_from.str().c_str(), entry.attributes.isDirectory))
{
NN_LOG("============No such file %ls in FileList.txt. Skip=============\n", target_from.str().c_str());
continue;
}
}
// ディレクトリの場合
if (entry.attributes.isDirectory)
{
// ディレクトリ作成
NN_LOG("Create Directory %ls\n", target_to.str().c_str());
result = nn::fs::TryCreateDirectory(target_to.str().c_str());
if (result.IsSuccess() || result.IsFailure() && result <= nn::fs::ResultAlreadyExists())
{
target_from << L"/";
target_to << L"/";
if(encode)
{
if(!AddPathNameAndUpdateContext(list, target_to.str().c_str(), -1, listContext))
{
return false;
}
}
// 再帰処理
if (!CopyDirectory(fileList, target_from.str().c_str(), target_to.str().c_str(), buf, bufSize, encode, list, listContext))
{
return false;
}
}
else
{
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
}
// ファイルの場合
else
{
std::wostringstream target_tmp;
target_tmp.str(L"");
target_tmp.clear(std::stringstream::goodbit);
if(!encode)
{
target_tmp << to_path << L"_" << entry.entryName;
}
else
{
target_tmp << target_to.str();
}
// ファイル作成
nn::fs::FileInputStream from_file;
nn::fs::FileStream to_file;
s64 filesize;
s64 fileSizeWithoutHeaderAndFooter;
s32 readsize;
s32 writesize;
NN_LOG("Copy File %ls\n", target_from.str().c_str());
// 読み込み対象ファイル開く
result = from_file.TryInitialize(target_from.str().c_str());
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 読み込み対象ファイルのサイズ取得
result = from_file.TryGetSize(&filesize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (encode)
{
if (!AddPathNameAndUpdateContext(list, target_to.str().c_str(), filesize, listContext))
{
return false;
}
}
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
size_t totalReadSize = 0;
nn::crypto::Sha256Context context;
context.Initialize();
// ファイルサイズをヘッダに書いておく
if (encode)
{
// 書き込み対象ファイル作成
result = nn::fs::TryCreateFile(target_tmp.str().c_str(), filesize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = to_file.TryInitialize(target_tmp.str().c_str(),
nn::fs::OPEN_MODE_READ | nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// フルパスをハッシュに含める
context.Update(target_from.str().c_str(), target_from.str().size() * sizeof(wchar_t));
BackupDataHeader header;
BackupDataHeader enc;
std::memset(&header, 0, sizeof(header));
std::memset(&enc, 0, sizeof(enc));
header.size = filesize;
result = swAesCtrContext.Encrypt(&enc, &header, sizeof(header));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context.Update(&enc, sizeof(enc));
s32 writeSize;
result = to_file.TryWrite(&writeSize, &enc, sizeof(enc), false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
else
{
// ヘッダを読む
// ハッシュの計算は終わっているので復号化のみ
BackupDataHeader header;
BackupDataHeader dec;
std::memset(&header, 0, sizeof(header));
std::memset(&dec, 0, sizeof(dec));
s32 readSize;
result = from_file.TryRead(&readSize, &header, sizeof(header));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
swAesCtrContext.Decrypt(&dec, &header, sizeof(header));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
fileSizeWithoutHeaderAndFooter = dec.size;
// 書き込み対象ファイル作成
result = nn::fs::TryCreateFile(target_tmp.str().c_str(), fileSizeWithoutHeaderAndFooter);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = to_file.TryInitialize(target_tmp.str().c_str(),
nn::fs::OPEN_MODE_READ | nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
while (1)
{
// バッファの後半半分を暗号・復号用に使う
result = from_file.TryRead(&readsize, buf, bufSize / 2);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
totalReadSize += readsize;
if (readsize == 0)
{
if (encode)
{
NN_LOG("Add CMAC %ls\n", target_from.str().c_str());
// SHA256を計算してCMACを付加する
bit8 sha256Hash[nn::crypto::Sha256Context::HASH_SIZE];
context.GetHash(sha256Hash);
bit8 cmac[nn::crypto::AES_CMAC_MAC_SIZE];
result = nn::crypto::CalculateAesCmacSw(cmac, sha256Hash, nn::crypto::Sha256Context::HASH_SIZE,
common::cmacKey);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = to_file.TryWrite(&writesize, cmac, sizeof(cmac));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
result = to_file.TryFlush();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 復号済みなら検証する
if (!encode)
{
if (!ConfirmFile(&from_file, &to_file, filesize, fileSizeWithoutHeaderAndFooter, buf, bufSize,
target_from.str().c_str(), target_tmp.str().c_str(), target_to.str().c_str()))
{
return false;
}
}
break;
}
else
{
if (encode)
{
NN_LOG("EncryptSize = %d\n", readsize);
u8 paddingSize = 0;
AddPkcsPadding(&paddingSize, reinterpret_cast<bit8*>(buf), bufSize / 2, &readsize);
// 暗号化後SHA256を計算しつつ書き込み
result = swAesCtrContext.Encrypt(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readsize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context.Update(reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize,
false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 事前計算したファイルサイズに一致させるためパディング分減算
readsize -= paddingSize;
s_FinishedFileSize += readsize;
s_Progress = s_FinishedFileSize * 100 / s_TotalFileSize;
NN_LOG(
"finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress);
}
else
{
// ハッシュ検証は通っているので復号化しつつ書き込み
// パディング以降は書き込まないよう書き込みサイズを変更する
NN_LOG("DecryptSize = %d\n", readsize);
result = swAesCtrContext.Decrypt(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readsize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// パディングまで読んだかどうか
bool readDone = false;
// パディングまで読んでいたら書き込みサイズを減らす
if (fileSizeWithoutHeaderAndFooter < totalReadSize)
{
readsize -= totalReadSize - fileSizeWithoutHeaderAndFooter;
readDone = true;
}
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*>(buf) + bufSize / 2, readsize,
false);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
s_FinishedFileSize += readsize;
s_Progress = s_FinishedFileSize * 100 / s_TotalFileSize;
NN_LOG(
"finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress);
// 読みきったので次のファイルへ
if (readDone)
{
result = to_file.TryFlush();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (!ConfirmFile(&from_file, &to_file, filesize, fileSizeWithoutHeaderAndFooter, buf,
bufSize, target_from.str().c_str(), target_tmp.str().c_str(),
target_to.str().c_str()))
{
return false;
}
break;
}
}
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
}
to_file.Finalize();
from_file.Finalize();
}
}
from_dir.Finalize();
return true;
}
u32 GetProgress()
{
return s_Progress;
}
void InitializeTransferProgress(u64 totalSize)
{
s_TotalFileSize = totalSize;
s_FinishedFileSize = 0;
}
bool CalculateAndCompareCmac(nn::crypto::Sha256Context* context, bit8* sdCmac)
{
nn::Result result;
bit8 sha256Hash[nn::crypto::Sha256Context::HASH_SIZE];
bit8 cmac[nn::crypto::AES_CMAC_MAC_SIZE];
context->GetHash(sha256Hash);
context->Finalize();
result = nn::crypto::CalculateAesCmacSw(cmac, sha256Hash, sizeof(sha256Hash), common::cmacKey);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return std::memcmp(cmac, sdCmac, sizeof(cmac)) == 0;
}
bool VerifyMac(nn::fs::FileInputStream* sdFile, nn::fs::FileStream* nandFile, s64 sdFileSize, s64 nandFileSize,
const wchar_t* nandPath, void* buf, size_t bufSize)
{
nn::Result result;
bit8 sdCmac[nn::crypto::AES_CMAC_MAC_SIZE];
// ハッシュが付加されていないとエラー
if(sdFileSize < nn::crypto::AES_CMAC_MAC_SIZE)
{
return false;
}
s32 readSize;
// ハッシュを取得する
result = sdFile->TrySetPosition(sdFileSize - nn::crypto::AES_CMAC_MAC_SIZE);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
result = sdFile->TryRead(&readSize, sdCmac, sizeof(sdCmac));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
sdFile->Finalize();
nandFile->SetPosition(0);
// ハッシュを計算する
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
nn::crypto::Sha256Context context;
context.Initialize();
// NAND上のフルパスをハッシュに含めている
context.Update(nandPath, std::wcslen(nandPath) * sizeof(wchar_t));
BackupDataHeader header;
BackupDataHeader enc;
std::memset(&header, 0, sizeof(header));
std::memset(&enc, 0, sizeof(enc));
header.size = nandFileSize;
result = swAesCtrContext.Encrypt(&enc, &header, sizeof(header));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context.Update(&enc, sizeof(enc));
bool retValue = false;
size_t totalReadSize = 0;
while (1)
{
result = nandFile->TryRead(&readSize, buf, bufSize / 2);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
retValue = false;
break;
}
else
{
totalReadSize += readSize;
if (readSize == 0)
{
retValue = CalculateAndCompareCmac(&context, sdCmac);
break;
}
else
{
u8 paddingSize = 0;
AddPkcsPadding(&paddingSize, reinterpret_cast<bit8*>(buf), bufSize / 2, &readSize);
result = swAesCtrContext.Encrypt(reinterpret_cast<bit8*>(buf) + bufSize / 2, buf, readSize);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context.Update(reinterpret_cast<bit8*>(buf) + bufSize / 2 , readSize);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
retValue = false;
break;
}
}
}
}
nandFile->Finalize();
return retValue;
}
bool ConfirmFile(nn::fs::FileInputStream* from_file, nn::fs::FileStream* to_file, s64 sdFileSize, s64 nandFileSize,
void* buf, size_t bufSize, const wchar_t* sdPath, const wchar_t* tmpPath, const wchar_t* truePath)
{
nn::Result result;
NN_LOG("Verify CMAC %ls\n", sdPath);
if (!VerifyMac(from_file, to_file, sdFileSize, nandFileSize, truePath, buf, bufSize))
{
// 検証に失敗したので削除する
s_FinishedFileSize -= nandFileSize;
COMMON_LOGGER("**********Verification Failed %s, Delete**********\n", GetCharStr(sdPath));
result = nn::fs::TryDeleteFile(tmpPath);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return false;
}
else
{
NN_LOG("Verification Success %s, Rename\n", GetCharStr(sdPath));
// 書き込み先を削除する
result = nn::fs::TryDeleteFile(truePath);
if (result.IsFailure() && !nn::fs::ResultNotFound::Includes(result))
{
COMMON_LOGGER("**********Verification Failed %s, Delete**********\n", GetCharStr(sdPath));
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
}
// 正しいファイル名にリネームする
result = nn::fs::TryRenameFile(tmpPath, truePath);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsFailure())
{
COMMON_LOGGER("**********Verification Failed %s, Delete**********\n", GetCharStr(sdPath));
s_FinishedFileSize -= nandFileSize;
return false;
}
}
return true;
}
//! @brief 入力データの末尾16バイトをPKCS5で必要バイト数パディングする
//! @param[out] paddingSize パディングしたバイト数
//! @param[in] buf 入力データの入ったバッファ
//! @param[in] bufSize バッファサイズ
//! @param[inout] readSize バッファに読み込んだバイト数。書き込み時に参照するためパディングしたら増加させる
void AddPkcsPadding(u8* paddingSize, void* buf, size_t bufSize, s32* readSize)
{
if (*readSize < bufSize)
{
if ((*readSize % AES_BLOCK_SIZE) != 0)
{
*paddingSize = AES_BLOCK_SIZE - *readSize % AES_BLOCK_SIZE;
std::memset(reinterpret_cast<bit8*>(buf) + *readSize, *paddingSize, *paddingSize);
*readSize += *paddingSize;
}
}
}
//! @brief パスにnimのセーブデータディレクトリが含まれているかどうかを返します
//! @param[in] str パス
//! @return パスにnimのセーブデータディレクトリが含まれているか
bool ContainsNimSaveDataDir(const wchar_t* str)
{
return std::wcsstr(str, common::NIM_SAVEDATA_DIRECTORY_NAME) != NULL;
}
//! @brief ファイルに文字列とサイズをカンマ区切り、改行付きで追加します
//! @param[in] file 文字列を出力したいファイル
//! @param[in] str 入力文字列
//! @param[in] fileSize サイズ
//! @param[in] context SHA-256計算用コンテキスト
bool AddPathNameAndUpdateContext(nn::fs::FileOutputStream* file, const wchar_t *str, s64 fileSize,
nn::crypto::Sha256Context* context)
{
nn::Result result;
s32 writeSize;
if(ContainsNimSaveDataDir(str))
{
return true;
}
std::string output(GetCharStr(str));
result = file->TryWrite(&writeSize, output.c_str(), output.size(), true);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context->Update(output.c_str(), output.size());
char comma = ',';
result = file->TryWrite(&writeSize, &comma, sizeof(comma), true);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context->Update(&comma, sizeof(comma));
char sizeStr[10];
std::memset(sizeStr, 0, sizeof(sizeStr));
s32 sizeStrSize = std::snprintf(sizeStr, sizeof(sizeStr), "%lld", fileSize);
result = file->TryWrite(&writeSize, sizeStr, sizeStrSize, true);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context->Update(sizeStr, sizeStrSize);
char newLine = '\n';
result = file->TryWrite(&writeSize, &newLine, sizeof(newLine), true);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
context->Update(&newLine, sizeof(newLine));
return true;
}
nn::Result CalculateFileSizeRecursively(std::wstring currentDirectory, s64& fileSize)
{
nn::fs::Directory dir;
nn::fs::DirectoryEntry entry;
nn::Result result;
NN_LOG("%s\n", common::GetCharStr(currentDirectory.c_str()));
result = dir.TryInitialize(currentDirectory.c_str());
NN_UTIL_RETURN_IF_FAILED(result);
for (;;)
{
s32 numRead;
result = dir.TryRead(&numRead, &entry, 1);
if(result.IsFailure())
{
continue;
}
if(numRead == 0)
{
break;
}
if (std::wcscmp(entry.entryName, L".") == 0 || std::wcscmp(entry.entryName, L"..") == 0)
{
continue;
}
// ディレクトリの場合
if (entry.attributes.isDirectory)
{
result = CalculateFileSizeRecursively(currentDirectory + std::wstring(entry.entryName) + std::wstring(L"/"), fileSize);
NN_UTIL_RETURN_IF_FAILED(result);
}
// ファイルの場合
else
{
nn::fs::FileInputStream file;
std::wstring filePath = (currentDirectory + std::wstring(entry.entryName)).c_str();
const wchar_t* path = filePath.c_str();
result = file.TryInitialize(path);
if(result.IsFailure())
{
continue;
}
fileSize += file.GetSize();
}
}
return nn::ResultSuccess();
}
}

View File

@ -0,0 +1,67 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: FileTransfer.h
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$
*---------------------------------------------------------------------------*/
#ifndef FILETRANSFER_H_
#define FILETRANSFER_H_
#include <nn.h>
#include <string>
#include <sstream>
#include "common_Types.h"
namespace common
{
// currentDirectory以下のファイル数、ファイルサイズを再帰的に計算する
nn::Result CalculateFileNum(std::wstring currentDirectory, u32& fileNum, s64& fileSize);
// 単一のディレクトリを作成する
// アーカイブはマウント済みにしておく
bool ExportTwlSaveDirectory(const wchar_t* dirPath, nn::fs::FileOutputStream* list,
nn::crypto::Sha256Context* listContext);
// 単一のファイルをコピーする
// アーカイブはマウント済みにしておく
bool ExportTwlSaveFile(const wchar_t* from_path, const wchar_t* to_path, void* buf, const size_t bufSize,
nn::fs::FileOutputStream* list, nn::crypto::Sha256Context* listContext);
// ディレクトリ間のコピー
// アーカイブ越しのコピーが可能
// アーカイブにマウントした状態で呼び出す必要あり
// 書き込み先のディレクトリはあらかじめ消去しておくこと。
// 引数はスラッシュ付き
// TODO:分割して短くする
bool CopyDirectory(ImportDataList* fileList, const wchar_t * from_path, const wchar_t * to_path, void* buf,
const size_t bufSize, bool encode, nn::fs::FileOutputStream* list, nn::crypto::Sha256Context* listContext);
// ファイル転送の進捗を取得する
// InitializeTransferProgress で設定した値を100とする割合が返される
u32 GetProgress();
// ファイル転送の目標値を設定する
void InitializeTransferProgress(u64 totalSize);
// wchar_t* を char* に変換する。
// 内部のバッファを使用するためスレッドアンセーフ
const char* GetCharStr(const wchar_t* path);
void AddPkcsPadding(u8* paddingSize, void* buf, size_t bufSize, s32* readSize);
// ディレクトリ以下のファイルサイズを計算する
nn::Result CalculateFileSizeRecursively(std::wstring currentDirectory, s64& fileSize);
}
#endif /* FILETRANSFER_H_ */

View File

@ -0,0 +1,76 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: HardwareStateManager.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 "HardwareStateManager.h"
namespace common
{
HardwareStateManager::HardwareStateManager(Util& hwUtility)
{
m_pUtil = &hwUtility;
}
HardwareStateManager::~HardwareStateManager()
{
}
bool HardwareStateManager::CanReadIvs()
{
return m_pUtil->CanReadIVS();
}
bool HardwareStateManager::CanReadSerialNumber()
{
return m_pUtil->CanReadSerialNumber();
}
bool HardwareStateManager::IsBatteryLower()
{
return m_pUtil->IsBatteryLower();
}
bool HardwareStateManager::IsAdapterConnected()
{
return m_pUtil->IsAdapterConnected();
}
bit32 HardwareStateManager::GetDeviceId()
{
return m_pUtil->GetDeviceId();
}
void HardwareStateManager::GetIvs(void** ivs, size_t* size)
{
return m_pUtil->GetIvs(ivs, size);
}
nn::Handle HardwareStateManager::GetMcuHandle()
{
return m_pUtil->GetMcuHandle();
}
void HardwareStateManager::GetSerialNumber(u8** serial, size_t* size)
{
return m_pUtil->GetSerialNumber(serial, size);
}
void HardwareStateManager::GetVersionData(common::VerDef* version)
{
return m_pUtil->GetVersionData(version);
}
}

View File

@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: HardwareStateManager.h
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$
*---------------------------------------------------------------------------*/
#ifndef HARDWARESTATEMANAGER_H_
#define HARDWARESTATEMANAGER_H_
#include "Util.h"
namespace common
{
// ハードウェア状態に依存するAPIをクッション
class HardwareStateManager
{
public:
explicit HardwareStateManager(Util& hwUtility);
virtual ~HardwareStateManager();
bool CanReadIvs();
bool CanReadSerialNumber();
bool IsBatteryLower();
bool IsAdapterConnected();
bit32 GetDeviceId();
void GetIvs(void** ivs, size_t* size);
nn::Handle GetMcuHandle();
void GetSerialNumber(u8** serial, size_t* size);
void GetVersionData(common::VerDef* version);
private:
NN_PADDING4;
Util* m_pUtil;
};
}
#endif /* HARDWARESTATEMANAGER_H_ */

View File

@ -0,0 +1,64 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: HeapManager.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 "HeapManager.h"
namespace common
{
nn::fnd::ThreadSafeExpHeap s_AppHeap;
HeapManager::HeapManager(size_t byteSize, s32 alignment, bit8 groupId, nn::fnd::ExpHeapBase::AllocationMode mode, bool reuse)
{
m_Ptr = s_AppHeap.Allocate(byteSize, alignment, groupId, mode, reuse);
}
HeapManager::~HeapManager()
{
if(m_Ptr != NULL)
{
s_AppHeap.Free(m_Ptr);
}
}
void* HeapManager::GetAddr()
{
return m_Ptr;
}
void InitializeHeap()
{
s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize(), nn::os::ALLOCATE_OPTION_LINEAR);
}
size_t GetAllocatableSize(s32 alignment)
{
return s_AppHeap.GetAllocatableSize(alignment);
}
void* ForceAllocate(size_t byteSize, s32 alignment, bit8 groupId, nn::fnd::ExpHeapBase::AllocationMode mode, bool reuse)
{
return s_AppHeap.Allocate(byteSize, alignment, groupId, mode, reuse);
}
void ForceFree(void* ptr)
{
if(ptr != NULL)
{
s_AppHeap.Free(ptr);
}
}
}

View File

@ -0,0 +1,51 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: HeapManager.h
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$
*---------------------------------------------------------------------------*/
#ifndef HEAPMANAGER_H_
#define HEAPMANAGER_H_
#include <nn.h>
#include <nn/fnd.h>
namespace common
{
class HeapManager
{
public:
explicit HeapManager(size_t byteSize, s32 alignment = nn::fnd::ExpHeapBase::DEFAULT_ALIGNMENT, bit8 groupId = 0,
nn::fnd::ExpHeapBase::AllocationMode mode = nn::fnd::ExpHeapBase::ALLOCATION_MODE_FIRST_FIT, bool reuse = false);
virtual ~HeapManager();
void* GetAddr();
private:
void* m_Ptr;
};
void InitializeHeap();
size_t GetAllocatableSize(s32 alignment = nn::fnd::ExpHeapBase::DEFAULT_ALIGNMENT);
// HeapManagerを使わず確保する場合のみ
void* ForceAllocate(size_t byteSize, s32 alignment = nn::fnd::ExpHeapBase::DEFAULT_ALIGNMENT, bit8 groupId = 0,
nn::fnd::ExpHeapBase::AllocationMode mode = nn::fnd::ExpHeapBase::ALLOCATION_MODE_FIRST_FIT, bool reuse = false);
// HeapManagerを使わず解放する場合のみ
void ForceFree(void* ptr);
} // namespace common
#endif /* HEAPMANAGER_H_ */

View File

@ -0,0 +1,185 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: LogConsole.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 "LogConsole.h"
#include <nn/nstd.h>
namespace common
{
const size_t FONT_WIDTH = 8;
const size_t FONT_HEIGHT = 10;
static LogConsole s_LogConsole;
LogConsole* GetConsoleInstance()
{
return &s_LogConsole;
}
LogConsole::LogConsole()
{
}
LogConsole::~LogConsole()
{
}
void LogConsole::Initialize(u32 width, u32 height, u32 maxLine, demo::RenderSystemDrawing* renderSystem)
{
m_Width = width;
m_Height = height;
m_MaxLine = maxLine;
m_pRenderSystem = renderSystem;
m_CurrentViewLine = 0;
m_LineNum = 0;
m_ColorRed = 1.0f;
m_ColorGreen = 1.0f;
m_ColorBlue = 1.0f;
m_ColorAlpha = 1.0f;
}
void LogConsole::AddText(const char* fmt, ::std::va_list arg)
{
s32 stringSize;
const size_t STRING_BUFFER_SIZE = 256;
char formatStr[STRING_BUFFER_SIZE];
stringSize = nn::nstd::TVSNPrintf(formatStr, sizeof(formatStr), fmt, arg);
::std::string str(formatStr);
size_t addedText = 0;
while (addedText < stringSize)
{
if(m_LineNum >= m_MaxLine)
{
// 満杯なので先頭を削除する
::std::vector<LogText>::iterator it;
it = m_Log.begin();
m_Log.erase(it);
m_LineNum--;
}
// 部分文字列を追加
AddWrapedText(str.substr(addedText, m_Width).c_str());
m_LineNum++;
// 画面領域の末尾を描画中 かつ
// 画面領域以上追加したら末尾にスクロールする
if(m_CurrentViewLine == (m_LineNum - m_Height - 1) && m_LineNum > m_Height)
{
ScrollToEnd();
}
if(stringSize - addedText > m_Width)
{
addedText += m_Width;
}
else
{
addedText += stringSize - addedText;
}
}
}
void LogConsole::SetTextColor(f32 red, f32 green, f32 blue, f32 alpha)
{
m_ColorRed = red;
m_ColorGreen = green;
m_ColorBlue = blue;
m_ColorAlpha = alpha;
}
void LogConsole::ScrollUp()
{
if(m_CurrentViewLine > 0)
{
m_CurrentViewLine--;
}
}
void LogConsole::ScrollDown()
{
if (m_LineNum > m_Height)
{
if (m_CurrentViewLine < m_LineNum - m_Height)
{
m_CurrentViewLine++;
}
}
}
void LogConsole::ScrollToBegin()
{
m_CurrentViewLine = 0;
}
void LogConsole::ScrollToEnd()
{
if(m_LineNum > m_Height)
{
m_CurrentViewLine = m_LineNum - m_Height;
}
}
void LogConsole::Print()
{
::std::vector<LogText>::iterator it;
it = m_Log.begin();
it += m_CurrentViewLine;
u32 count = 0;
for(; it != m_Log.end() && count < m_Height && count < m_MaxLine; it++)
{
m_pRenderSystem->SetColor(it->m_Red, it->m_Green, it->m_Blue, it->m_Alpha);
m_pRenderSystem->DrawText(0, count++ * 10, "%s", it->m_Text.c_str());
}
if(m_LineNum > m_Height)
{
DrawScrollBar();
}
}
void LogConsole::AddWrapedText(const char* str)
{
m_Log.push_back(LogText(::std::string(str), m_ColorRed, m_ColorGreen, m_ColorBlue, m_ColorAlpha));
}
void LogConsole::DrawScrollBar()
{
m_pRenderSystem->SetColor(0.4f, 0.4f, 0.4f);
m_pRenderSystem->DrawLine((m_Width + 1) * FONT_WIDTH, 0, (m_Width + 2) * FONT_WIDTH - 1, 0);
m_pRenderSystem->DrawLine((m_Width + 1)* FONT_WIDTH, 0, (m_Width + 1)* FONT_WIDTH, m_Height * FONT_HEIGHT);
m_pRenderSystem->DrawLine((m_Width + 2) * FONT_WIDTH - 1, 0, (m_Width + 2) * FONT_WIDTH - 1, m_Height * FONT_HEIGHT);
m_pRenderSystem->DrawLine((m_Width + 1)* FONT_WIDTH, m_Height * FONT_HEIGHT - 1, (m_Width + 2) * FONT_WIDTH - 1, m_Height * FONT_HEIGHT - 1);
u32 y = (m_Height * FONT_HEIGHT - 2) * m_CurrentViewLine / m_MaxLine;
m_pRenderSystem->SetColor(0.7f, 0.7f, 0.7f);
m_pRenderSystem->FillRectangle((m_Width + 1) * FONT_WIDTH, y + 1, FONT_WIDTH - 1, FONT_HEIGHT - 4);
m_pRenderSystem->SetColor(1.f, 1.f, 1.f);
}
} //namespace ConsoleBackup

View File

@ -0,0 +1,101 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: LogConsole.h
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$
*---------------------------------------------------------------------------*/
#ifndef LOGCONSOLE_H_
#define LOGCONSOLE_H_
#include <vector>
#include <string>
#include <nn/fnd.h>
#include "demo.h"
namespace common
{
struct LogText
{
LogText(std::string text, f32 red, f32 green, f32 blue, f32 alpha) :
m_Text(text), m_Red(red), m_Green(green), m_Blue(blue), m_Alpha(alpha)
{
}
std::string m_Text;
f32 m_Red;
f32 m_Green;
f32 m_Blue;
f32 m_Alpha;
};
//! @brief 画面にテキストコンソールを描画します
class LogConsole
{
public:
LogConsole();
~LogConsole();
void Initialize(u32 width, u32 height, u32 maxLine, demo::RenderSystemDrawing* renderSystem);
// コンソールに描画する文字列を追加する
void AddText(const char* fmt, ::std::va_list arg);
// コンソールに描画する文字を変更する
void SetTextColor(f32 red, f32 green, f32 blue, f32 alpha);
// 上スクロールする
void ScrollUp();
// 下スクロールする
void ScrollDown();
// 先頭にスクロールする
void ScrollToBegin();
// 末尾にスクロールする
void ScrollToEnd();
// AddTextで追加された文字列を描画する
void Print();
private:
void AddWrapedText(const char* str);
void DrawScrollBar();
::std::vector<LogText> m_Log;
//! @brief コンソールの列数
u32 m_Width;
//! @brief コンソールの行数
u32 m_Height;
//! @brief コンソールのログの最大行数
u32 m_MaxLine;
//! @brief 描画のためのRenderSystemDrawingへのポインタ
demo::RenderSystemDrawing* m_pRenderSystem;
//! @brief 追加したログの行数
u32 m_LineNum;
//! @brief 表示を開始するログの行数
u32 m_CurrentViewLine;
//! @描画フォントの色
f32 m_ColorRed;
f32 m_ColorGreen;
f32 m_ColorBlue;
f32 m_ColorAlpha;
};
}
#endif /* LOGCONSOLE_H_ */

View File

@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: LogConsole_Private.h
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$
*---------------------------------------------------------------------------*/
#ifndef LOGCONSOLE_PRIVATE_H_
#define LOGCONSOLE_PRIVATE_H_
#include "LogConsole.h"
namespace common
{
LogConsole* GetConsoleInstance();
}
#endif /* LOGCONSOLE_PRIVATE_H_ */

View File

@ -0,0 +1,18 @@
#!/usr/bin/env omake
#----------------------------------------------------------------------------
# Project: Horizon
# File: OMakefile
#
# Copyright (C)2009 Nintendo Co., Ltd. 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 $(ROOT_OMAKE)/modulerules
DefineDefaultRules()

View File

@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: ProgramId.h
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$
*---------------------------------------------------------------------------*/
#ifndef PROGRAMID_H_
#define PROGRAMID_H_
namespace common
{
const u64 CONSOLE_BACKUP_PROGRAM_ID = 0x000400000f802200L;
const u64 CONSOLE_RESTORE_PROGRAM_ID = 0x000400000f802300L;
const u64 WITHOUT_VALIATION_MASK = 0xffffffffffffff00L;
}
#endif /* PROGRAMID_H_ */

View File

@ -0,0 +1,415 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: ResFont.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$
*---------------------------------------------------------------------------*/
//------------------------------------------------------------------
// デモ: ResFont
//
// 概要
// nn::font::ResFont の構築と破棄のサンプルです。
//
// 操作
// なし。
//
//------------------------------------------------------------------
#include <nn.h>
#include <nn/fs.h>
#include <nn/font.h>
#include <nn/math.h>
#include <nn/util.h>
#include "ResFont.h"
#include "demo.h"
#include "HeapManager.h"
namespace common
{
namespace
{
const char s_ShaderBinaryFilePath[] = "rom:/nnfont_RectDrawerShader.shbin";
const char s_FontFilePath[] = "rom:/lc.bcfnt";
const u8 s_Color = 255;
nn::font::RectDrawer s_Drawer;
void* s_DrawerBuf;
nn::font::ResFont s_Font;
nn::font::DispStringBuffer *s_pDrawStringBuf0;
nn::font::TextWriter s_TextWriter;
void (*s_DrawTextFunc)() = NULL;
//---------------------------------------------------------------------------
//! @brief シェーダの初期化を行います。
//!
//! @param[in,out] pResource 描画用リソースを管理するオブジェクトへのポインタ。
//---------------------------------------------------------------------------
void*
InitShaders(nn::font::RectDrawer* pDrawer)
{
nn::fs::FileReader shaderReader(s_ShaderBinaryFilePath);
const u32 fileSize = (u32)shaderReader.GetSize();
void* shaderBinary = ForceAllocate(fileSize);
NN_NULL_ASSERT(shaderBinary);
#ifndef NN_BUILD_RELEASE
s32 read =
#endif // NN_BUILD_RELEASE
shaderReader.Read(shaderBinary, fileSize);
NN_ASSERT(read == fileSize);
const u32 vtxBufCmdBufSize =
nn::font::RectDrawer::GetVertexBufferCommandBufferSize(shaderBinary, fileSize);
void *const vtxBufCmdBuf = ForceAllocate(vtxBufCmdBufSize);
NN_NULL_ASSERT(vtxBufCmdBuf);
pDrawer->Initialize(vtxBufCmdBuf, shaderBinary, fileSize);
return vtxBufCmdBuf;
}
//---------------------------------------------------------------------------
//! @brief 描画の初期設定を行います。
//!
//! @param[in] width 画面の幅。
//! @param[in] height 画面の高さ。
//---------------------------------------------------------------------------
void
InitDraw(
s32 width,
s32 height
)
{
// カラーバッファ情報
// LCDの向きに合わせて、幅と高さを入れ替えています。
const nn::font::ColorBufferInfo colBufInfo = { width, height, PICA_DATA_DEPTH24_STENCIL8_EXT };
const u32 screenSettingCommands[] =
{
// ビューポートの設定
NN_FONT_CMD_SET_VIEWPORT( 0, 0, colBufInfo.width, colBufInfo.height ),
// シザー処理を無効
NN_FONT_CMD_SET_DISABLE_SCISSOR( colBufInfo ),
// wバッファの無効化
// デプスレンジの設定
// ポリゴンオフセットの無効化
NN_FONT_CMD_SET_WBUFFER_DEPTHRANGE_POLYGONOFFSET(
0.0f, // wScale : 0.0 でWバッファが無効
0.0f, // depth range near
1.0f, // depth range far
0, // polygon offset units : 0.0 で ポリゴンオフセットが無効
colBufInfo),
};
nngxAdd3DCommand(screenSettingCommands, sizeof(screenSettingCommands), true);
static const u32 s_InitCommands[] =
{
// カリングを無効
NN_FONT_CMD_SET_CULL_FACE( NN_FONT_CMD_CULL_FACE_DISABLE ),
// ステンシルテストを無効
NN_FONT_CMD_SET_DISABLE_STENCIL_TEST(),
// デプステストを無効
// カラーバッファの全ての成分を書き込み可
NN_FONT_CMD_SET_DEPTH_FUNC_COLOR_MASK(
false, // isDepthTestEnabled
0, // depthFunc
true, // depthMask
true, // red
true, // green
true, // blue
true), // alpha
// アーリーデプステストを無効
NN_FONT_CMD_SET_ENABLE_EARLY_DEPTH_TEST( false ),
// フレームバッファアクセス制御
NN_FONT_CMD_SET_FBACCESS(
true, // colorRead
true, // colorWrite
false, // depthRead
false, // depthWrite
false, // stencilRead
false), // stencilWrite
};
nngxAdd3DCommand(s_InitCommands, sizeof(s_InitCommands), true);
}
//---------------------------------------------------------------------------
//! @brief ResFontを構築します。
//!
//! @param[out] pFont 構築するフォントへのポインタ。
//! @param[in] filePath ロードするフォントリソースファイル名。
//!
//! @return ResFont構築の成否を返します。
//---------------------------------------------------------------------------
bool
InitFont(
nn::font::ResFont* pFont,
const char* filePath
)
{
// フォントリソースをロードします
nn::fs::FileReader fontReader(filePath);
s32 fileSize = (s32)fontReader.GetSize();
if ( fileSize <= 0 )
{
return false;
}
void* buffer = common::ForceAllocate(fileSize, nn::font::GlyphDataAlignment);
if (buffer == NULL)
{
return false;
}
s32 readSize = fontReader.Read(buffer, fileSize);
if (readSize != fileSize)
{
common::ForceFree(buffer);
return false;
}
// フォントリソースをセットします
bool bSuccess = pFont->SetResource(buffer);
NN_ASSERT(bSuccess);
//--- 既にリソースをセット済みであるか,ロード済みであるか、リソースが不正な場合に失敗します。
if (! bSuccess)
{
common::ForceFree(buffer);
}
// 描画用バッファを設定します。
const u32 drawBufferSize = nn::font::ResFont::GetDrawBufferSize(buffer);
void* drawBuffer = common::ForceAllocate(drawBufferSize, 4);
NN_NULL_ASSERT(drawBuffer);
pFont->SetDrawBuffer(drawBuffer);
return bSuccess;
}
//---------------------------------------------------------------------------
//! @brief ResFontを破棄します。
//!
//! @param[in] pFont 破棄するフォントへのポインタ。
//---------------------------------------------------------------------------
void
CleanupFont(nn::font::ResFont* pFont)
{
// 描画用バッファの無効化
// 描画用バッファがセットされているなら 構築時に SetDrawBuffer に渡したバッファへの
// ポインタが返ってきます。
void *const drawBuffer = pFont->SetDrawBuffer(NULL);
if (drawBuffer != NULL)
{
ForceFree(drawBuffer);
}
// フォントがセットされているなら SetResource 時に渡したリソースへの
// ポインタが返ってきます。
void *const resource = pFont->RemoveResource();
if (resource != NULL)
{
ForceFree(resource);
}
// RemoveResource 後は再度 SetResource するまでフォントとして使用できません。
}
//---------------------------------------------------------------------------
//! @brief 表示文字列用バッファを確保します。
//!
//! @param[in] charMax 表示する文字列の最大文字数。
//!
//! @return 確保した表示文字列用バッファへのポインタを返します。
//---------------------------------------------------------------------------
nn::font::DispStringBuffer*
AllocDispStringBuffer(s32 charMax)
{
const u32 DrawBufferSize = nn::font::CharWriter::GetDispStringBufferSize(charMax);
void *const bufMem = ForceAllocate(DrawBufferSize);
NN_NULL_ASSERT(bufMem);
return nn::font::CharWriter::InitDispStringBuffer(bufMem, charMax);
}
//---------------------------------------------------------------------------
//! @brief 文字列表示用にモデルビュー行列と射影行列を設定します。
//!
//! @param[in] pDrawer RectDrawerオブジェクトへのポインタ。
//! @param[in] width 画面の幅。
//! @param[in] height 画面の高さ。
//---------------------------------------------------------------------------
void
SetupTextCamera(
nn::font::RectDrawer* pDrawer,
s32 width,
s32 height
)
{
// 射影行列を正射影に設定
{
// 左上原点とし、Y軸とZ軸の向きが逆になるように設定します。
nn::math::MTX44 proj;
f32 znear = 0.0f;
f32 zfar = -1.0f;
f32 t = 0;
f32 b = static_cast<f32>(width);
f32 l = 0;
f32 r = static_cast<f32>(height);
nn::math::MTX44OrthoPivot(&proj, l, r, b, t, znear, zfar, nn::math::PIVOT_UPSIDE_TO_TOP);
pDrawer->SetProjectionMtx(proj);
}
// モデルビュー行列を単位行列に設定
{
nn::math::MTX34 mv;
nn::math::MTX34Identity(&mv);
pDrawer->SetViewMtxForText(mv);
}
}
//---------------------------------------------------------------------------
//! @brief ASCII文字列を描画します。
//!
//! @param[in] pDrawer RectDrawerオブジェクトへのポインタ。
//! @param[in] pDrawStringBuf DispStringBufferオブジェクトへのポインタ。
//! @param[in] pFont フォントへのポインタ。
//! @param[in] width 画面の幅。
//! @param[in] height 画面の高さ。
//---------------------------------------------------------------------------
void
DrawAscii(
nn::font::RectDrawer* pDrawer,
nn::font::DispStringBuffer* pDrawStringBuf,
nn::font::ResFont* pFont,
s32 width,
s32 height
)
{
s_TextWriter.SetDispStringBuffer(pDrawStringBuf);
s_TextWriter.SetFont(pFont);
s_TextWriter.SetCursor(0, 0, 1.f);
s_TextWriter.StartPrint();
if(s_DrawTextFunc != NULL)
{
s_DrawTextFunc();
}
s_TextWriter.EndPrint();
pDrawer->BuildTextCommand(&s_TextWriter);
// 文字の色は、文字列の描画コマンドを再作成しなくても変更できます。
s_TextWriter.SetTextColor(nn::util::Color8(s_Color, s_Color, s_Color, s_Color));
pDrawer->DrawBegin();
SetupTextCamera(pDrawer, width, height);
s_TextWriter.UseCommandBuffer();
pDrawer->DrawEnd();
}
} // namespace <unnnamed>
void SetDrawTextHandler(void (*func)())
{
s_DrawTextFunc = func;
}
//---------------------------------------------------------------------------
//! @brief サンプルのメイン関数です。
//---------------------------------------------------------------------------
void
InitializeResFont()
{
const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
static char buffer[ROMFS_BUFFER_SIZE];
NN_UTIL_PANIC_IF_FAILED(
nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
// フォントの構築
{
#ifndef NN_BUILD_RELEASE
bool bSuccess =
#endif // NN_BUILD_RELEASE
InitFont(&s_Font, s_FontFilePath);
NN_ASSERTMSG(bSuccess, "Fail to load ResFont.");
}
// 描画リソースの構築
s_DrawerBuf = InitShaders(&s_Drawer);
// 描画文字列用バッファの確保
s_pDrawStringBuf0 = AllocDispStringBuffer(512);
nn::fs::Unmount("rom:");
}
void DrawResFont(s32 display)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if(display == NN_GX_DISPLAY0)
{
InitDraw(NN_GX_DISPLAY0_WIDTH, NN_GX_DISPLAY0_HEIGHT);
DrawAscii(&s_Drawer, s_pDrawStringBuf0, &s_Font, NN_GX_DISPLAY0_WIDTH, NN_GX_DISPLAY0_HEIGHT);
}
else if(display == NN_GX_DISPLAY1)
{
InitDraw(NN_GX_DISPLAY1_WIDTH, NN_GX_DISPLAY1_HEIGHT);
DrawAscii(&s_Drawer, s_pDrawStringBuf0, &s_Font, NN_GX_DISPLAY1_WIDTH, NN_GX_DISPLAY1_HEIGHT);
}
nngxUpdateState(NN_GX_STATE_ALL);
}
void FinalizeResFont()
{
s_Drawer.Finalize();
// 描画リソースの破棄
ForceFree(s_DrawerBuf);
// フォントの破棄
CleanupFont(&s_Font);
// 描画文字列用バッファの解放
ForceFree(s_pDrawStringBuf0);
}
nn::font::TextWriter* GetTextWriter()
{
return &s_TextWriter;
}
}

View File

@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: ResFont.h
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$
*---------------------------------------------------------------------------*/
#ifndef RESFONT_H_
#define RESFONT_H_
#include <nn/font.h>
namespace common
{
// ResFontを初期化する。
void InitializeResFont();
// 文字列の描画時に実行したいハンドラを設定する
void SetDrawTextHandler(void (*func)());
// SetDrawTextHandler で設定した関数を使って文字列を描画する
void DrawResFont(s32 display);
// 内部で保持しているTextWriterへのポインタを返す
nn::font::TextWriter* GetTextWriter();
}
#endif /* RESFONT_H_ */

View File

@ -0,0 +1,570 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SaveDataMover.cpp
Copyright 2009-2011 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 <string>
#include <nn/fs/fs_ApiSysSaveData.h>
#include <nn/fs/fs_ApiSharedExtSaveData.h>
#include <nn/fs/fs_ApiDeviceMove.h>
#include <nn/fs/fs_ResultPrivate.h>
#include <nn/crypto/crypto_SwAesCtrContext.h>
#include <nn/ndm.h>
#include "Aes_define.h"
#include "SaveDataMover.h"
#include "CommonLogger.h"
#include "FileName.h"
#include "SdReaderWriter.h"
#include "FileTransfer.h"
#include "HeapManager.h"
namespace common
{
namespace
{
const char* ARC_NAME = "sext:";
const s32 MAX_SYSTEM_SAVE_DATA_ID_NUM = 256;
nn::fs::SystemSaveDataId s_SystemSaveDataIdList[MAX_SYSTEM_SAVE_DATA_ID_NUM * sizeof(bit32)];
const s32 MAX_SHARED_EXT_SAVE_DATA_ID_NUM = 10;
nn::fs::SharedExtSaveDataId s_SharedExtSaveDataIdList[MAX_SHARED_EXT_SAVE_DATA_ID_NUM * sizeof(bit32)];
bool IsNotMovedId(bit32 id)
{
return id == 0x0001002c; // nim
}
bit32 HexStringToBit32(const char* hex, int maxLen)
{
bit32 val = 0;
for(int i = 0; i < maxLen; ++i)
{
val *= 16;
if(hex[i] >= '0' && hex[i] <= '9')
{
val += (hex[i] - '0');
}
else if(hex[i] >= 'a' && hex[i] <= 'f')
{
val += (hex[i] - 'a' + 10);
}
else if(hex[i] >= 'A' && hex[i] <= 'F')
{
val += (hex[i] - 'A' + 10);
}
else
{
break;
}
}
return val;
}
}
SaveDataMover::SaveDataMover() :
m_Progress(0), m_FinishedSize(0), m_TotalSize(0), m_Result(nn::ResultSuccess())
{
}
SaveDataMover::~SaveDataMover()
{
}
void SaveDataMover::StartExport(void* buf, size_t bufSize, u64* progress)
{
SetupExport();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(GetLastResult());
CalculateExportFileSize();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(GetLastResult());
ExportSystemSaveData(buf, bufSize, progress);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(GetLastResult());
ExportSharedExtSaveData(buf, bufSize, progress);
}
void SaveDataMover::StartImport(void* buf, size_t bufSize, u64* progress)
{
SetupImport(buf, bufSize);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(GetLastResult());
CalculateImportFileSize();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(GetLastResult());
ImportSystemSaveData(buf, bufSize, progress);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(GetLastResult());
ImportSharedExtSaveData(buf, bufSize, progress);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(GetLastResult());
}
nn::Result SaveDataMover::GetLastResult()
{
return m_Result;
}
void SaveDataMover::SetupExport()
{
// 1. デーモンの停止
m_Result = nn::ndm::Initialize();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
m_Result = nn::ndm::SuspendScheduler();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// 2. StartDeviceMoveAsSource
nn::fs::DeviceMoveContext moveContext;
m_Result = nn::fs::StartDeviceMoveAsSource(&moveContext);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// コンテキストのSDへの出力
common::HeapManager contextHeap(sizeof(moveContext));
void* enc;
enc = contextHeap.GetAddr();
if(!enc)
{
m_Result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_APPLICATION,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
return;
}
// AES暗号化する
nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key));
m_Result = swAesCtrContest.Encrypt(enc, &moveContext, sizeof(moveContext));
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
common::SdReaderWriter sdWriter;
m_Result = sdWriter.WriteBufWithCmac(common::MOVE_CONTEXT_PATHNAME, enc, sizeof(moveContext));
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// 3. 出力用ディレクトリの作成
// 3.1 システムセーブデータ用ディレクトリ
m_Result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(
common::SD_SAVEDATA_ROOT_NAME) + std::wstring(common::SD_SAEVDATA_SYS_NAME)).c_str());
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// 3.2 共有拡張セーブデータ用ディレクトリ
m_Result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(
common::SD_SAVEDATA_ROOT_NAME) + std::wstring(common::SD_SAEVDATA_EXT_NAME)).c_str());
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
}
void SaveDataMover::CalculateExportFileSize()
{
CalculateExportSystemSaveDataSize();
CalculateExportSharedExtSaveDataSize();
}
void SaveDataMover::CalculateExportSystemSaveDataSize()
{
s32 systemSaveDataIdNum;
m_Result = nn::fs::EnumerateSystemSaveData(&systemSaveDataIdNum, s_SystemSaveDataIdList, MAX_SYSTEM_SAVE_DATA_ID_NUM);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// システムセーブデータのサイズを確認する
for(s32 i = 0; i < systemSaveDataIdNum; ++i)
{
nn::fs::FileInputStream input;
bit32 id = s_SystemSaveDataIdList[i];
if(IsNotMovedId(id))
{
continue;
}
m_Result = nn::fs::OpenSystemSaveDataRawStorageFile(&input, id);
if(m_Result.IsFailure())
{
COMMON_LOGGER_WARN("Can't Export: %08x\n", id);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
continue;
}
m_TotalSize += input.GetSize();
}
}
void SaveDataMover::CalculateExportSharedExtSaveDataSize()
{
// 共有拡張セーブデータのサイズを確認する
// 0. ID の列挙を行う。
s32 sharedExtSaveDataIdNum;
m_Result = nn::fs::EnumerateSharedExtSaveData(&sharedExtSaveDataIdNum, s_SharedExtSaveDataIdList,
MAX_SHARED_EXT_SAVE_DATA_ID_NUM);
for(s32 i = 0; i < sharedExtSaveDataIdNum; ++i)
{
bit32 id = s_SharedExtSaveDataIdList[i];
// 1. fs::MountSharedExtSaveDataRawStorage を呼び
// ID に対応するアーカイブをマウントする。
// 既存の共有拡張セーブデータ領域へのアーカイブをマウントします。
m_Result = nn::fs::MountSharedExtSaveDataRawStorage(ARC_NAME, id);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// 2. アーカイブ内を走査して、含まれるファイルサイズを計算する
m_Result = common::CalculateFileSizeRecursively(L"sext:/", m_TotalSize);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// 3. アンマウントする
m_Result = nn::fs::Unmount(ARC_NAME);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
}
NN_LOG("calculatedSize = %lld\n", m_TotalSize);
}
void SaveDataMover::ExportSystemSaveData(void* buf, size_t bufSize, u64* progress)
{
s64 totalFileSize = 0;
// 0. ID の列挙を行う。
s32 systemSaveDataIdNum;
m_Result = nn::fs::EnumerateSystemSaveData(&systemSaveDataIdNum, s_SystemSaveDataIdList, MAX_SYSTEM_SAVE_DATA_ID_NUM);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
for(s32 i = 0; i < systemSaveDataIdNum; ++i)
{
nn::fs::FileInputStream input;
bit32 id = s_SystemSaveDataIdList[i];
if(IsNotMovedId(id))
{
continue;
}
NN_LOG("id: %08x\n", id);
// 1. fs::OpenSystemSaveDataRawStorageFile を呼び
// ID に対するセーブデータの FileInputStream を得る。
m_Result = nn::fs::OpenSystemSaveDataRawStorageFile(&input, id);
if(m_Result.IsFailure())
{
COMMON_LOGGER_WARN("Can't Export: %08x\n", id);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
continue;
}
NN_LOG("fileSize = %lld\n", input.GetSize());
totalFileSize += input.GetSize();
// SD へコピー
{
char outPath[64];
nn::nstd::TSNPrintf(outPath, 64, "%s/%08x", SD_SAVEDATA_SYS_ROOT_PATH, id);
NN_LOG("outPath = %s\n", outPath);
nn::fs::FileOutputStream output;
m_Result = output.TryInitialize(outPath, true);
if(m_Result.IsFailure())
{
COMMON_LOGGER_WARN("Can't Export: %08x\n", id);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
continue;
}
// 2. 1 で得たストリームからデータを読み込む。
// 本来はここで読み込んだデータを引っ越し先に転送するが
// ここでは SD カードにエクスポートする。
m_Result = CopyFile(input, output, buf, bufSize, progress);
if(m_Result.IsFailure())
{
COMMON_LOGGER_WARN("Can't Export: %08x\n", id);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
continue;
}
}
}
NN_LOG("\n");
NN_LOG("totalFileSize = %lld\n", totalFileSize);
}
void SaveDataMover::ExportSharedExtSaveData(void* buf, size_t bufSize, u64* progress)
{
// 0. ID の列挙を行う。
s32 sharedExtSaveDataIdNum;
m_Result = nn::fs::EnumerateSharedExtSaveData(&sharedExtSaveDataIdNum, s_SharedExtSaveDataIdList,
MAX_SHARED_EXT_SAVE_DATA_ID_NUM);
for(s32 i = 0; i < sharedExtSaveDataIdNum; ++i)
{
bit32 id = s_SharedExtSaveDataIdList[i];
NN_LOG("Export: %08x\n", id);
// 1. fs::MountSharedExtSaveDataRawStorage を呼び
// ID に対応するアーカイブをマウントする。
// 既存の共有拡張セーブデータ領域へのアーカイブをマウントします。
m_Result = nn::fs::MountSharedExtSaveDataRawStorage(ARC_NAME, id);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
m_Result = Export(buf, bufSize, id, progress);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// 3. アンマウントする
m_Result = nn::fs::Unmount(ARC_NAME);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
}
}
nn::Result SaveDataMover::Export(void* buf, size_t bufSize, bit32 id, u64* progress)
{
const s32 MAX_PATH_LEN = 127;
char destRoot[MAX_PATH_LEN + 1];
nn::nstd::TSNPrintf(destRoot, MAX_PATH_LEN, "%s/%08x", SD_SAVEDATA_EXT_ROOT_PATH, id);
NN_LOG("destRoot = %s\n", destRoot);;
// 出力先ディレクトリを作成
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(nn::fs::TryCreateDirectory(destRoot));
// 2. アーカイブ内を走査して、含まれるファイルと
// ディレクトリを、その構造を保ったまま
// エクスポートする。
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(CopyRecursivly(buf, bufSize, ARC_NAME, destRoot, progress));
return nn::ResultSuccess();
}
void SaveDataMover::SetupImport(void* buf, size_t bufSize)
{
// 引っ越しコンテクストを取得
nn::fs::DeviceMoveContext moveContext;
// コンテキストのSDからの入力
size_t readSize;
common::SdReaderWriter sdReader;
m_Result = sdReader.ReadBufWithCmac(common::MOVE_CONTEXT_PATHNAME, buf, bufSize, &readSize);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// AES復号化する
nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key));
m_Result = swAesCtrContest.Decrypt(&moveContext, buf, readSize);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
// 1. StartDeviceMoveAsDestination
m_Result = StartDeviceMoveAsDestination(moveContext);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
}
void SaveDataMover::ImportSystemSaveData(void* buf, size_t bufSize, u64* progress)
{
// セーブデータが格納されているディレクトリを開く
nn::fs::Directory root;
m_Result = root.TryInitialize(SD_SAVEDATA_SYS_ROOT_PATH);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
nn::fs::DirectoryEntry entry;
s32 numOut = 0;
// ディレクトリ内を見てセーブデータをインポートする。
while(1)
{
m_Result = root.TryRead(&numOut, &entry, 1);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
if(numOut == 0)
{
break;
}
bit32 id = HexStringToBit32(entry.shortName.body, 8);
if(id == 0)
{
break;
}
NN_LOG("id: %08x\n", id);
nn::fs::FileInputStream input;
char name[64];
nn::nstd::TSNPrintf(name, 64, "%s/%s", SD_SAVEDATA_SYS_ROOT_PATH, entry.shortName.body);
m_Result = input.TryInitialize(name);
if(m_Result.IsFailure())
{
COMMON_LOGGER_WARN("Can't Import: %08x\n", id);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
continue;
}
// 1. fs::CreateAndOpenNewSystemSaveDataRawStorageFile を呼び
// ID に対する FileOutputStream を得る。
nn::fs::FileOutputStream output;
m_Result = nn::fs::CreateAndOpenNewSystemSaveDataRawStorageFile(&output, id, input.GetSize());
if(m_Result.IsFailure())
{
COMMON_LOGGER_WARN("Can't Import: %08x\n", id);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
continue;
}
// 2. 1 で得たストリームに対して書き込みを行う。
// 本来は引っ越し元からデータを受け取り、書き込むが
// ここでは SD から読み込んだデータを書き込む。
m_Result = CopyFile(input, output, buf, bufSize, progress);
if(m_Result.IsFailure())
{
COMMON_LOGGER_WARN("Can't Import: %08x\n", id);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
continue;
}
}
NN_LOG("\n");
}
void SaveDataMover::ImportSharedExtSaveData(void* buf, size_t bufSize, u64* progress)
{
nn::fs::Directory srcRoot;
m_Result = srcRoot.TryInitialize(SD_SAVEDATA_EXT_ROOT_PATH);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
nn::fs::DirectoryEntry entry;
s32 numEntry;
while(1)
{
m_Result = srcRoot.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
if(numEntry == 0)
{
break;
}
bit32 id = HexStringToBit32(entry.shortName.body, 8);
NN_LOG("Import: %08x\n", id);
m_Result = Import(buf, bufSize, id, progress);
if(m_Result.IsFailure())
{
NN_LOG("Failed to import. result = %08x\n", m_Result.GetPrintableBits());
}
}
NN_LOG("\n");
}
nn::Result SaveDataMover::Import(void* buf, size_t bufSize, bit32 id, u64* progress)
{
const char* ARC_NAME = "sext:";
const int MAX_PATH_LEN = 127;
char srcRoot[MAX_PATH_LEN + 1];
NN_UTIL_RETURN_IF_FAILED(nn::fs::CreateNewSharedExtSaveDataRawStorage(id));
// 2. fs::CreateNewSharedExtSaveDataRawStorage を呼び
// 書き込み用の領域を作成します。
nn::nstd::TSNPrintf(srcRoot, MAX_PATH_LEN, "%s/%08x", SD_SAVEDATA_EXT_ROOT_PATH, id);
m_Result = nn::fs::MountNewSharedExtSaveDataRawStorage(ARC_NAME, id);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(m_Result);
// 4. 3 でマウントした領域に、引っ越し元のアーカイブと
// 同じ構造でファイルとディレクトリを置く。
m_Result = CopyRecursivly(buf, bufSize, srcRoot, ARC_NAME, progress);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(m_Result);
m_Result = nn::fs::Unmount(ARC_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(m_Result);
return nn::ResultSuccess();
}
void SaveDataMover::CalculateImportFileSize()
{
m_Result = common::CalculateFileSizeRecursively(
(::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(),
m_TotalSize);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
}
// ファイルの読み書き
nn::Result SaveDataMover::CopyFile(nn::fs::FileInputStream& is, nn::fs::FileOutputStream& os, void* pBuffer,
const s32 bufferSize, u64* progress)
{
s64 restSize;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(is.TryGetSize(&restSize));
while (restSize > 0)
{
s32 readSize = restSize > bufferSize ? bufferSize : restSize;
s32 read = 0;
s32 write = 0;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(is.TryRead(&read, pBuffer, readSize));
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(os.TryWrite(&write, pBuffer, read));
restSize -= read;
m_FinishedSize += read;
*progress = m_FinishedSize * 100 / m_TotalSize;
NN_LOG("FinishedSize = %lld\n", m_FinishedSize);
NN_LOG("progress = %lld\n", *progress);
}
return nn::ResultSuccess();
}
// ディレクトリ内を再帰的にコピー
// INFO: 本当は再帰を使わないで書く
nn::Result SaveDataMover::CopyRecursivly(void* buf, size_t bufSize, const char* src, const char* dest, u64* progress)
{
char srcPath[128];
char destPath[128];
char entryName[128];
nn::nstd::TSNPrintf(srcPath, sizeof(srcPath), "%s/", src);
nn::fs::Directory srcDir;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(srcDir.TryInitialize(srcPath));
while (1)
{
nn::fs::DirectoryEntry entry;
s32 numRead;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(srcDir.TryRead(&numRead, &entry, 1));
if (numRead == 0)
{
break;
}
std::wcstombs(entryName, entry.entryName, sizeof(entryName) - 1);
entryName[sizeof(entryName) - 1] = '\0';
nn::nstd::TSNPrintf(srcPath, sizeof(srcPath), "%s/%s", src, entryName);
nn::nstd::TSNPrintf(destPath, sizeof(destPath), "%s/%s", dest, entryName);
if (entry.attributes.isDirectory)
{
m_Result = nn::fs::TryCreateDirectory(destPath);
if (m_Result.IsFailure())
{
if (m_Result.GetDescription() == nn::fs::DESCRIPTION_FAT_ALREADY_EXISTS
&& m_Result.GetModule() == nn::Result::MODULE_NN_FS)
{
}
else
{
return m_Result;
}
}
m_Result = CopyRecursivly(buf, bufSize, srcPath, destPath, progress);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(m_Result);
}
else
{
nn::fs::FileInputStream input;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(input.TryInitialize(srcPath));
nn::fs::FileOutputStream output;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(output.TryInitialize(destPath, true));
CopyFile(input, output, buf, bufSize, progress);
}
}
return nn::ResultSuccess();
}
} /* namespace common */

View File

@ -0,0 +1,92 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SaveDataMover.h
Copyright (C)2011 Nintendo Co., Ltd. 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$
*---------------------------------------------------------------------------*/
#ifndef SAVEDATAMOVER_H_
#define SAVEDATAMOVER_H_
#include <nn.h>
namespace common
{
class SaveDataMover
{
public:
SaveDataMover();
virtual ~SaveDataMover();
//! @brief SDカードへの出力を開始します
void StartExport(void* buf, size_t bufSize, u64* progress);
//! @brief SDカードからの入力を開始します
void StartImport(void* buf, size_t bufSize, u64* progress);
//! @brief 処理の結果を取得します
nn::Result GetLastResult();
private:
//******************** 出力用API群 ********************
//! @brief 出力を準備します
void SetupExport();
//! @brief 出力するファイルサイズを計算します
void CalculateExportFileSize();
void CalculateExportSystemSaveDataSize();
void CalculateExportSharedExtSaveDataSize();
//! @brief システムセーブデータを出力します
void ExportSystemSaveData(void* buf, size_t bufSize, u64* progress);
//! @brief 共有拡張セーブデータを出力します
void ExportSharedExtSaveData(void* buf, size_t bufSize, u64* progress);
//! @breif 共有拡張セーブデータを出力します
nn::Result Export(void* buf, size_t bufSize, bit32 id, u64* progress);
//******************** 入力用API群 ********************
//!@ brief 入力を準備します
void SetupImport(void* buf, size_t bufSize);
//! @brief システムセーブデータを入力します
void ImportSystemSaveData(void* buf, size_t bufSize, u64* progress);
//! @brief 共有拡張セーブデータを入力します
void ImportSharedExtSaveData(void* buf, size_t bufSize, u64* progress);
//! @brief 共有拡張セーブデータを出力します
nn::Result Import(void* buf, size_t bufSize, bit32 id, u64* progress);
//! @brief 入力するファイルサイズを計算します
void CalculateImportFileSize();
nn::Result CopyFile(nn::fs::FileInputStream& is, nn::fs::FileOutputStream& os, void* pBuffer, const s32 bufferSize,
u64* progress);
nn::Result CopyRecursivly(void* buf, size_t bufSize, const char* src, const char* dest, u64* progress);
NN_PADDING4;
s64 m_Progress;
s64 m_FinishedSize;
s64 m_TotalSize;
NN_PADDING4;
nn::Result m_Result;
};
} /* namespace common */
#endif /* SAVEDATAMOVER_H_ */

View File

@ -0,0 +1,287 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SdLogger.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 "SdLogger.h"
#include <string>
#include "SDMountManager.h"
#include "FileName.h"
namespace common
{
namespace Logger
{
static SdLogger s_SdLogger;
static nn::os::LightEvent s_SdEjectedEvent;
static nn::os::LightEvent s_SdInsertedEvent;
const size_t SDMC_EVENT_THREAD_STACK_SIZE = 1024;
nn::os::Thread s_SdmcEjectedEventThread;
nn::os::StackBuffer<SDMC_EVENT_THREAD_STACK_SIZE> s_SdmcEjectedEventThreadStack;
nn::os::Thread s_SdmcInsertedEventThread;
nn::os::StackBuffer<SDMC_EVENT_THREAD_STACK_SIZE> s_SdmcInsertedEventThreadStack;
void (*s_SdEjectedEventFunc)() = NULL;
void (*s_SdInsertedEventFunc)() = NULL;
void PrintResultIfFailed(nn::Result result, u32 line = 0)
{
if (result.IsFailure())
{
if(line != 0)
{
NN_LOG("%s, %d\n", __func__, line);
}
NN_DBG_PRINT_RESULT(result);
}
}
void SdmcEjectedEventThreadFunc()
{
NN_LOG("********************:SD Ejected Event Thread Start**********************\n");
for(;;)
{
s_SdEjectedEvent.Wait();
NN_LOG("********************:SD Card Ejected**********************\n");
if(s_SdEjectedEventFunc != NULL)
{
s_SdEjectedEventFunc();
}
SdMountManager::ForceUnmount();
s_SdEjectedEvent.ClearSignal();
s_SdLogger.Inactivate();
}
}
void SdmcInsertedEventThreadFunc()
{
NN_LOG("********************:SD Inserted Event Thread Start**********************\n");
for(;;)
{
s_SdInsertedEvent.Wait();
NN_LOG("********************:SD Card Inserted*********************\n");
if(s_SdInsertedEventFunc != NULL)
{
s_SdInsertedEventFunc();
}
SdMountManager::ForceUnmount();
s_SdInsertedEvent.ClearSignal();
s_SdLogger.Inactivate();
}
}
void InitializeEjectThread()
{
s_SdEjectedEvent.Initialize(true);
s_SdInsertedEvent.Initialize(true);
nn::fs::RegisterSdmcEjectedEvent(&s_SdEjectedEvent);
nn::fs::RegisterSdmcInsertedEvent(&s_SdInsertedEvent);
// SDカード抜けを検知するためのスレッド作成
s_SdmcEjectedEventThread.Start(SdmcEjectedEventThreadFunc, s_SdmcEjectedEventThreadStack);
// SDカード挿入を検知するためのスレッド作成
s_SdmcInsertedEventThread.Start(SdmcInsertedEventThreadFunc, s_SdmcInsertedEventThreadStack);
}
void SetEjectHandler(void (*func)())
{
s_SdEjectedEventFunc = func;
}
void SetInsertHandler(void (*func)())
{
s_SdInsertedEventFunc = func;
}
SdLogger::SdLogger() : m_TryActivate(false), m_Permitted(false)
{
}
SdLogger* GetSdInstance()
{
return &s_SdLogger;
}
void SdLogger::Print(const char* fmt, ::std::va_list arg)
{
Activate();
nn::Result result;
result = SdMountManager::Mount();
if (result.IsFailure())
{
PrintResultIfFailed(result, __LINE__);
}
s32 stringSize;
const size_t STRING_BUFFER_SIZE = 256;
char str[STRING_BUFFER_SIZE];
stringSize = nn::nstd::TVSNPrintf(str, sizeof(str), fmt, arg);
// 書き込み不可であればバッファリングのみ行う
if(!m_Permitted)
{
NN_LOG("SD Write Not Permitted\n");
m_Buffer.push_back(std::string(str));
return;
}
// バッファリング済みならまず吐き出す
for(std::vector<std::string>::iterator it = m_Buffer.begin(); it != m_Buffer.end(); it++)
{
PrintCore(it->c_str(), it->size());
}
m_Buffer.clear();
PrintCore(str, stringSize);
SdMountManager::Unmount();
}
nn::Result SdLogger::PrintCore(const char* str, size_t size)
{
nn::Result result;
::std::wstring log(common::SDMC_ROOT_DIRECTORY_PATH);
log += common::LOG_PATHNAME;
// ディレクトリが無ければ作る
nn::fs::Directory dir;
result = dir.TryInitialize(common::LOG_ROOT_DIRECTORY_PATH);
if(result.IsFailure())
{
result = nn::fs::TryCreateDirectory(common::LOG_ROOT_DIRECTORY_PATH);
}
result = sd.TryInitialize(log.c_str(), true);
if (result.IsSuccess())
{
// 追記する
// サイズ取得
s64 fileSize;
result = sd.TryGetSize(&fileSize);
if (result.IsSuccess())
{
// 末尾に移動
result = sd.TrySetPosition(fileSize);
if (result.IsSuccess())
{
s32 writeSize;
result = sd.TryWrite(&writeSize, str, size, true);
if (result.IsSuccess())
{
result = sd.TryFlush();
if (result.IsFailure())
{
NN_LOG("SD TryFlush failed\n");
PrintResultIfFailed(result, __LINE__);
}
}
else
{
NN_LOG("SD TryWrite failed\n");
PrintResultIfFailed(result, __LINE__);
}
}
else
{
NN_LOG("SD TrySetPosition failed\n");
PrintResultIfFailed(result, __LINE__);
}
}
else
{
NN_LOG("SD TryGetSize failed\n");
PrintResultIfFailed(result, __LINE__);
}
}
else
{
NN_LOG("SD TryInitialize failed, %s, %d\n", __func__, __LINE__);
PrintResultIfFailed(result, __LINE__);
}
dir.Finalize();
sd.Finalize();
return nn::ResultSuccess();
}
void SdLogger::Clear()
{
Activate();
if(!m_Permitted)
{
return;
}
nn::Result result;
SdMountManager::Mount();
::std::wstring log(common::SDMC_ROOT_DIRECTORY_PATH);
log += common::LOG_PATHNAME;
result = nn::fs::TryDeleteFile(log.c_str());
if(result.IsFailure())
{
NN_DBG_PRINT_RESULT(result);
}
SdMountManager::Unmount();
}
void SdLogger::Inactivate()
{
m_TryActivate = false;
m_Permitted = false;
}
void SdLogger::Activate()
{
if(m_TryActivate)
{
return;
}
nn::Result result;
result = common::SdMountManager::Mount();
if (result.IsSuccess())
{
nn::fs::FileInputStream fis;
result = fis.TryInitialize(common::AP_SETTING_PATHNAME);
if(result.IsSuccess())
{
m_Permitted = true;
}
fis.Finalize();
}
common::SdMountManager::Unmount();
m_TryActivate = true;
}
} // namespace Logger
} // namespace ConsoleBackup

View File

@ -0,0 +1,72 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SdLogger.h
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$
*---------------------------------------------------------------------------*/
#ifndef SDLOGGER_H_
#define SDLOGGER_H_
#include <nn.h>
#include <vector>
#include <string>
namespace common
{
namespace Logger
{
class SdLogger
{
public:
SdLogger();
~SdLogger() {};
// SDログに文字列を出力する
void Print(const char* fmt, ::std::va_list arg);
// SDログを削除する
void Clear();
// 内部状態を初期化する。SDカード挿抜時に呼ばれることを期待
void Inactivate();
private:
void Activate();
nn::Result PrintCore(const char* str, size_t size);
nn::fs::FileOutputStream sd;
std::vector<std::string> m_Buffer;
bool m_TryActivate;
bool m_Permitted;
NN_PADDING2;
};
// SDカード挿抜用のスレッドを初期化する
void InitializeEjectThread();
// SDカードが抜けた時に呼ばれるコールバック
void SetEjectHandler(void (*func)());
// SDカードが挿入された時に呼ばれるコールバック
void SetInsertHandler(void (*func)());
// 内部で保持しているインスタンスへのポインタを返す
SdLogger* GetSdInstance();
} // namespace Logger
} // namespace ConsoleBackup
#endif /* SDLOGGER_H_ */

View File

@ -0,0 +1,67 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SdMountManager.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 "SdMountManager.h"
#include "FileName.h"
namespace common
{
u32 SdMountManager::m_MountCounter = 0;
SdMountManager::SdMountManager()
{
}
SdMountManager::~SdMountManager()
{
}
nn::Result SdMountManager::Mount()
{
nn::Result result = nn::ResultSuccess();
if(m_MountCounter == 0)
{
result = nn::fs::MountSdmc();
}
m_MountCounter++;
return result;
}
nn::Result SdMountManager::Unmount()
{
nn::Result result = nn::ResultSuccess();
if(m_MountCounter != 0 && --m_MountCounter == 0)
{
result = nn::fs::Unmount(common::SDMC_ARCHIVE_NAME);
}
return result;
}
nn::Result SdMountManager::ForceUnmount()
{
m_MountCounter = 0;
return nn::fs::Unmount(common::SDMC_ARCHIVE_NAME);
}
}

View File

@ -0,0 +1,42 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SdMountManager.h
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$
*---------------------------------------------------------------------------*/
#ifndef SDMOUNTMANAGER_H_
#define SDMOUNTMANAGER_H_
namespace common
{
//! @brief SDカードのMount状態を管理するためのクラスです
class SdMountManager
{
public:
SdMountManager();
virtual ~SdMountManager();
//! @brief マウントが必要ならマウントします。
static nn::Result Mount();
//! @brief アンマウントが必要ならアンマウントします。
static nn::Result Unmount();
//! @brief 強制的にアンマウントします。
static nn::Result ForceUnmount();
private:
static u32 m_MountCounter;
};
}
#endif /* SDMOUNTMANAGER_H_ */

View File

@ -0,0 +1,244 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SdReaderWriter.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 "SdReaderWriter.h"
#include "SdMountManager.h"
#include "CommonLogger.h"
#include "Aes_define.h"
#include <nn/crypto/crypto_AesCmac.h>
#include <nn/crypto/crypto_SwAesCtrContext.h>
#include <nn/crypto/crypto_Sha256.h>
#include <nn/crypto/crypto_SwAesCmac.h>
#include <cstdlib>
namespace common
{
nn::Result SdReaderWriter::Initialize()
{
nn::Result result;
// 初期化済みなら何もしない
if(m_IsInitialized)
{
return nn::ResultSuccess();
}
result = SdMountManager::Mount();
if(result.IsSuccess())
{
m_IsInitialized = true;
return nn::ResultSuccess();
}
else
{
return result;
}
}
nn::Result SdReaderWriter::Finalize()
{
nn::Result result;
result = SdMountManager::Unmount();
m_IsInitialized = false;
return result;
}
nn::Result SdReaderWriter::WriteBufCore(nn::fs::FileStream& file, const wchar_t* path, void* buf, size_t size)
{
NN_ASSERT(path != NULL);
NN_ASSERT(size > 0);
nn::Result result = Initialize();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = file.TryInitialize(path, nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE);
if (result.IsSuccess())
{
s32 writeSize;
result = file.TryWrite(&writeSize, buf, size, false);
if (result.IsSuccess())
{
// 何もしない
}
else
{
NN_LOG("SD TryWrite failed\n");
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
else
{
NN_LOG("SD TryInitialize failed\n");
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
return result;
}
nn::Result SdReaderWriter::WriteBuf(nn::fs::FileStream& file, const wchar_t* path, void* buf, size_t size)
{
nn::Result result;
result = WriteBufCore(file, path, buf, size);
NN_UTIL_RETURN_IF_FAILED(result);
result = file.TryFlush();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
file.Finalize();
result = Finalize();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
return result;
}
nn::Result SdReaderWriter::WriteBufWithCmac(const wchar_t* path, void* buf, size_t size)
{
nn::Result result;
nn::fs::FileStream file;
result = WriteBufCore(file, path, buf, size);
NN_UTIL_RETURN_IF_FAILED(result);
bit8 sha256Hash[nn::crypto::Sha256Context::HASH_SIZE];
nn::crypto::CalculateSha256(sha256Hash, buf, size);
bit8 cmac[nn::crypto::AES_CMAC_MAC_SIZE];
result = nn::crypto::CalculateAesCmacSw(cmac, sha256Hash, nn::crypto::Sha256Context::HASH_SIZE, common::cmacKey);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
s32 writeSize;
result = file.TryWrite(&writeSize, cmac, sizeof(cmac), false);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = file.TryFlush();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
file.Finalize();
result = Finalize();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
return result;
}
nn::Result SdReaderWriter::ReadBufCore(nn::fs::FileStream& file, const wchar_t* path, void* buf, size_t size,
size_t* totalSize)
{
NN_ASSERT(path != NULL);
NN_ASSERT(size > 0);
nn::Result result;
if(!m_IsInitialized)
{
Initialize();
}
result = file.TryInitialize(path, nn::fs::OPEN_MODE_READ);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
s32 readSize;
result = file.TryRead(&readSize, buf, size);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// TODO バッファを超えるサイズのファイル読み込み
*totalSize = readSize;
return result;
}
nn::Result SdReaderWriter::ReadBuf(nn::fs::FileStream& file, const wchar_t* path, void* buf, size_t size,
size_t* totalSize)
{
nn::Result result;
result = ReadBufCore(file, path, buf, size, totalSize);
NN_UTIL_RETURN_IF_FAILED(result);
file.Finalize();
return result;
}
nn::Result SdReaderWriter::ReadBufWithCmac(const wchar_t* path, void* buf, size_t size, size_t* totalSize)
{
nn::Result result;
nn::fs::FileStream file;
NN_ASSERT(size > nn::crypto::AES_CMAC_MAC_SIZE);
result = ReadBufCore(file, path, buf, size, totalSize);
NN_UTIL_RETURN_IF_FAILED(result);
file.Finalize();
// ハッシュが付加されていない
if(*totalSize < nn::crypto::AES_CMAC_MAC_SIZE)
{
return nn::fs::ResultVerificationFailed();
}
*totalSize -= nn::crypto::AES_CMAC_MAC_SIZE;
// CMACの検証を行う
bit8 sha256Hash[nn::crypto::Sha256Context::HASH_SIZE];
nn::crypto::CalculateSha256(sha256Hash, buf, *totalSize);
bit8 cmac[nn::crypto::AES_CMAC_MAC_SIZE];
result = nn::crypto::CalculateAesCmacSw(cmac, sha256Hash, nn::crypto::Sha256Context::HASH_SIZE, common::cmacKey);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
if(std::memcmp(reinterpret_cast<bit8*>(buf) + *totalSize, cmac, sizeof(cmac)) != 0)
{
// 無効なファイル
char filename[256];
std::wcstombs(filename, path, sizeof(filename));
filename[sizeof(filename) - 1] = '\0';
COMMON_LOGGER("Verification Failed %s\n", filename);
return nn::fs::ResultVerificationFailed();
}
// CMACを0埋め
std::memset(reinterpret_cast<bit8*>(buf) + *totalSize, 0, sizeof(cmac));
return result;
}
nn::Result SdReaderWriter::CreateDirectory(const wchar_t* path)
{
nn::Result result;
if(!m_IsInitialized)
{
Initialize();
}
NN_LOG("Create Directory %ls\n", path);
result = nn::fs::TryCreateDirectory(path);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = Finalize();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
return nn::ResultSuccess();
}
}

View File

@ -0,0 +1,78 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SdReaderWriter.h
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$
*---------------------------------------------------------------------------*/
#ifndef SDWRITER_H_
#define SDWRITER_H_
#include <nn.h>
namespace common
{
//! @brief SDカードに書き込むためのクラスです。
class SdReaderWriter
{
public :
SdReaderWriter() : m_IsInitialized(false) {};
~SdReaderWriter() {};
//! @brief 渡されたバッファからsizeバイト指定されたパス名で書きこみます。CMACが付加されます。
//! @param[in] path sdmc:で始まる出力パス名。予めディレクトリを作っておく必要があります。
//! @param[in] buf 入力データへのポインタ
//! @param[in] size 入力データのサイズ
nn::Result WriteBufWithCmac(const wchar_t* path, void* buf, size_t size);
//! @brief 渡されたバッファへ(size - CMAC)バイト指定されたパス名から読み込みます
//! @param[in] path sdmc:で始まるCMAC付きの入力パス名
//! @param[in] buf 出力バッファへのポインタ
//! @param[in] size バッファサイズ
//! @param[out] totalSize 読み込んだデータ - CMAC のサイズ
nn::Result ReadBufWithCmac(const wchar_t* path, void* buf, size_t size, size_t* totalSize);
//! @brief 渡されたディレクトリ名のディレクトリを作成します
nn::Result CreateDirectory(const wchar_t* path);
private:
//! @brief 渡されたバッファからサイズ分指定されたパス名で書きこみます
//! @param[in] path sdmc:で始まる出力パス名。予めディレクトリを作っておく必要があります。
//! @param[in] buf 入力データへのポインタ
//! @param[in] size 入力データのサイズ
nn::Result WriteBuf(nn::fs::FileStream& file, const wchar_t* path, void* buf, size_t size);
nn::Result WriteBufCore(nn::fs::FileStream& file, const wchar_t*path, void* buf, size_t size);
//! @brief 渡されたバッファへサイズ分指定されたパス名から読み込みます
//! @param[in] path sdmc:で始まる入力パス名
//! @param[in] buf 出力バッファへのポインタ
//! @param[in] size バッファサイズ
//! @param[out] totalSize 読み込んだデータのサイズ
nn::Result ReadBuf(nn::fs::FileStream& file, const wchar_t* path, void* buf, size_t size, size_t* totalSize);
nn::Result ReadBufCore(nn::fs::FileStream& file, const wchar_t* path, void* buf, size_t size, size_t* totalSize);
//! @brief 初期化します。
nn::Result Initialize();
//! @brief 終了します。
nn::Result Finalize();
NN_PADDING3;
bool m_IsInitialized;
};
}
#endif /* SDWRITER_H_ */

View File

@ -0,0 +1,240 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SimplePlayer.cpp
Copyright (C)2009 Nintendo Co., Ltd. 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/os.h>
#include <nn/fnd.h>
#include <nn/fs.h>
#include <nn/hid.h>
#include <nn/snd.h>
#include <string.h>
#include "SimplePlayer.h"
#include "wave.h"
#include "HeapManager.h"
namespace common
{
namespace
{
const int nFiles = 4; // 使用できる voice の最大値は 24
const char* apFileNames[nFiles] =
{
"rom:/ok.wav",
"rom:/ng.wav",
"rom:/cursor.wav",
"rom:/annotation.wav"
};
nn::snd::CTR::Voice* apVoice[nFiles];
nn::snd::CTR::WaveBuffer aBuffer[nFiles];
WaveFmt fmt[nFiles];
WaveData data[nFiles];
u8* apMemory[nFiles];
nn::os::CriticalSection s_CriticalSection;
bool s_SoundThreadInitialized = false;
// サウンドスレッド関連
const int SOUND_THREAD_STACK_SIZE = 4096;
nn::os::StackBuffer<SOUND_THREAD_STACK_SIZE> s_SoundThreadStack;
nn::os::Thread threadSound;
bool threadSoundFlag;
void SoundThreadFunc()
{
// サウンド出力をステレオに
nn::snd::SetSoundOutputMode(nn::snd::OUTPUT_MODE_STEREO);
// マスターボリュームを設定
nn::snd::SetMasterVolume( 1.0 );
NN_LOG("Loading wav files...\n");
// ファイルを開く
for (int i = 0; i < nFiles; i++)
{
if (apFileNames[i] == NULL) continue;
nn::snd::Voice* pVoice = NULL;
nn::fs::FileReader fileReader;
nn::Result result = fileReader.TryInitialize(apFileNames[i]);
NN_UTIL_PANIC_IF_FAILED(result);
if (::std::strcmp(::std::strrchr(apFileNames[i], '.'), ".wav") == false)
{
// 連続メモリ領域の取得、確認
apMemory[i] = reinterpret_cast<u8*>(ForceAllocate(GetWaveLength(fileReader), 32));
if (apMemory[i] == NULL)
{
NN_LOG("Failed to allocate continuous memory\n");
continue;
}
// Wave データを読み込み、キャッシュを無効に
data[i].buf = apMemory[i];
LoadWave(fileReader, &fmt[i], &data[i]);
nn::snd::FlushDataCache(reinterpret_cast<uptr>(apMemory[i]), data[i].size);
NN_LOG("%s (%1dch, %5dHz, %2d-bit wav file)\n",
apFileNames[i], fmt[i].channel, fmt[i].sample_rate, fmt[i].quantum_bits);
pVoice = apVoice[i] = nn::snd::AllocVoice(128, NULL, NULL);
NN_TASSERT_(pVoice);
nn::snd::SampleFormat format = (fmt[i].quantum_bits == 8) ?
nn::snd::SAMPLE_FORMAT_PCM8 :
nn::snd::SAMPLE_FORMAT_PCM16;
pVoice->SetChannelCount( fmt[i].channel );
pVoice->SetSampleFormat( format );
nn::snd::InitializeWaveBuffer(&aBuffer[i]);
aBuffer[i].bufferAddress = apMemory[i];
aBuffer[i].sampleLength = nn::snd::GetSampleLength(data[i].size, format, fmt[i].channel);
aBuffer[i].loopFlag = false;
fileReader.Finalize();
// 音量の設定
nn::snd::MixParam mix;
mix.mainBus[nn::snd::CHANNEL_INDEX_FRONT_LEFT ] = 0.707f; // メインボリューム (L)
mix.mainBus[nn::snd::CHANNEL_INDEX_FRONT_RIGHT] = 0.707f; // メインボリューム (R)
pVoice->SetMixParam(mix);
pVoice->SetVolume(1.0f);
// pitch の設定
pVoice->SetSampleRate(fmt[i].sample_rate);
pVoice->SetPitch(1.0f);
}
}
// 再生開始
for (int i = 0; i < nFiles; i++)
{
if (apFileNames[i] != NULL)
{
apVoice[i]->SetState( nn::snd::Voice::STATE_PLAY );
}
}
s_SoundThreadInitialized = true;
threadSoundFlag = true;
while (threadSoundFlag)
{
nn::snd::WaitForDspSync(); // DSP からのデータ受信を待つ。
s_CriticalSection.Enter(); // メインスレッドとの排他制御
nn::snd::SendParameterToDsp(); // パラメータを DSP に送信。
s_CriticalSection.Leave(); // メインスレッドとの排他制御
}
// 再生終了
for (int i = 0; i < nFiles; i++)
{
if (apVoice[i])
{
nn::snd::FreeVoice(apVoice[i]);
}
}
}
}
void InitializeSimplePlayer()
{
NN_LOG("Initialize SimplePlayer\n");
nn::Result result;
const size_t ROMFS_BUFFER_SIZE = 1024 * 64;
static char buffer[ROMFS_BUFFER_SIZE];
NN_UTIL_PANIC_IF_FAILED(
nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE));
// dsp, snd の初期化
result = nn::dsp::Initialize();
NN_UTIL_PANIC_IF_FAILED(result);
result = nn::dsp::LoadDefaultComponent();
NN_UTIL_PANIC_IF_FAILED(result);
result = nn::snd::Initialize();
NN_UTIL_PANIC_IF_FAILED(result);
s_CriticalSection.Initialize();
// サウンドスレッドを起動DSP 割り込みイベント待ち)
threadSound.Start(SoundThreadFunc, s_SoundThreadStack);
}
void PlaySound(SoundEffect index)
{
NN_ASSERT(index < SOUND_MAX);
while(!s_SoundThreadInitialized)
{
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(1));
}
nn::snd::CTR::Voice* pVoice = apVoice[index];
if (!pVoice->IsPlaying())
{
nn::snd::InitializeWaveBuffer(&aBuffer[index]);
aBuffer[index].bufferAddress = apMemory[index];
nn::snd::SampleFormat format = (fmt[index].quantum_bits == 8) ? nn::snd::SAMPLE_FORMAT_PCM8
: nn::snd::SAMPLE_FORMAT_PCM16;
aBuffer[index].sampleLength = nn::snd::GetSampleLength(data[index].size, format, fmt[index].channel);
aBuffer[index].loopFlag = false;
pVoice->AppendWaveBuffer(&aBuffer[index]);
NN_LOG("[voice%d] %s (pitch = %f)\n",
index,
(pVoice->GetState() == nn::snd::Voice::STATE_PAUSE ? "pause" : "play "),
pVoice->GetPitch());
}
}
void FinalizeSimplePlayer()
{
nn::Result result;
// サウンドスレッドの破棄
threadSoundFlag = false;
threadSound.Join();
// SND の終了処理
result = nn::snd::Finalize();
NN_UTIL_PANIC_IF_FAILED(result);
s_CriticalSection.Finalize();
// DSP の終了処理
result = nn::dsp::UnloadComponent();
NN_UTIL_PANIC_IF_FAILED(result);
nn::dsp::Finalize();
NN_LOG("Finalize SimplePlayer\n");
}
} // namespace ConsoleBackup
/*---------------------------------------------------------------------------*
End of file
*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,44 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: SimplePlayer.h
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$
*---------------------------------------------------------------------------*/
#ifndef SIMPLEPLAYER_H_
#define SIMPLEPLAYER_H_
namespace common
{
typedef enum SoundEffect
{
SOUND_OK,
SOUND_NG,
SOUND_CURSOR,
SOUND_ANNOTATION,
SOUND_MAX
} SoundEffect;
// サウンドを鳴らすための初期化を行う
void InitializeSimplePlayer();
// 終了処理を行う
void FinalizeSimplePlayer();
// サウンドを鳴らす
void PlaySound(SoundEffect index);
} // namespace common
#endif /* SIMPLEPLAYER_H_ */

View File

@ -0,0 +1,363 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Util.cpp
Copyright (C)2010-2011 Nintendo Co., Ltd. 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 <cctype>
#include <nn.h>
#include <nn/ptm/CTR/ptm_ApiSysmenu.h>
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/fs/CTR/MPCore/fs_ApiIntegrityVerificationSeed.h>
#include <nn/fs/fs_ApiSysSaveData.h>
#include <nn/cfg/CTR/cfg_Api.h>
#include <nn/cfg/CTR/cfg_ApiInit.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/friends.h>
#include <nn/friends/CTR/friends_ApiPrivate.h>
#include <nn/ps.h>
#include <nn/drivers/mcu/CTR/driverMcuRegisterMap.h>
#include "Util.h"
#include "FileName.h"
#include "CommonLogger.h"
#include "HeapManager.h"
#include "FileTransfer.h"
namespace common
{
Util::Util() :
m_FriendCode(0), mp_Ivs(NULL), m_SizeofIvs(0), m_BatteryRemain(100), m_CanReadSerialNumber(false), m_CanReadIvs(
false), m_HasReadFriendCode(false)
{
}
Util::~Util()
{
}
void Util::InitializeForBackup()
{
Initialize();
}
void Util::InitializeForRestore()
{
Initialize();
// friendsの初期化
nn::Result result = nn::friends::detail::Initialize();
// フレンドコードの取得
nn::friends::CTR::FriendKey friendKey;
result = nn::friends::CTR::GetMyFriendKey(&friendKey);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
m_FriendCode = nn::friends::CTR::FriendKeyToFriendCode(friendKey);
m_HasReadFriendCode = true;
}
void Util::Initialize()
{
nn::Result result;
// mcuの初期化
nn::mcu::CTR::InitializeHwCheck(&m_McuSession);
mp_Mcu = new nn::mcu::CTR::HwCheck(m_McuSession);
// シリアルナンバーの取得
std::memset(m_SerialNo, '\0',
nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN);
result = nn::cfg::CTR::system::GetSerialNo(m_SerialNo);
if(result.IsSuccess())
{
m_CanReadSerialNumber = true;
}
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
AddCheckDigit(reinterpret_cast<char*>(m_SerialNo));
// デバイスIDの取得
result = nn::ps::CTR::GetDeviceId(&m_DeviceId);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
// リージョンの取得
m_Region = nn::cfg::CTR::GetRegion();
// バージョンの取得
common::GetSystemVersion(&m_VerData, m_Region);
// IVSの取得
ReadIvs(m_VerData.cup.majorVersion);
// MACアドレスの取得
nn::nwm::Mac mac;
result = nn::nwm::GetMacAddress(mac);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
mac.GetString(m_MacAddress);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
}
void Util::FinalizeForBackup()
{
Finalize();
}
void Util::FinalizeForRestore()
{
nn::friends::detail::Finalize();
}
void Util::Finalize()
{
nn::mcu::CTR::FinalizeHwCheck(&m_McuSession);
}
void Util::ReadIvs(u8 cupMajorVersion)
{
if (cupMajorVersion < common::CUP_MAJOR_VER_2ND_NUP)
{
nn::Result result;
// 完全性検証SEEDの取得
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
if (result.IsSuccess())
{
nn::fs::FileInputStream fis;
result = fis.TryInitialize(common::IVS_NAND_PATHNAME);
if (result.IsSuccess())
{
s64 fileSize = fis.GetSize();
s32 ret;
void* addr = NULL;
addr = ForceAllocate(fileSize);
if (addr != NULL)
{
mp_Ivs = addr;
m_SizeofIvs = fileSize;
result = fis.TryRead(&ret, addr, fileSize);
if (result.IsSuccess())
{
m_CanReadIvs = true;
}
// 後でIVSを参照するのでFreeしない
}
}
fis.Finalize();
}
// 一旦アンマウントしておく
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
}
else
{
nn::Result result;
void* pSeed = ForceAllocate(sizeof(nn::fs::CTR::IntegrityVerificationSeed));
if(pSeed != NULL)
{
result = nn::fs::CTR::ExportIntegrityVerificationSeed(
reinterpret_cast<nn::fs::CTR::IntegrityVerificationSeed*>(pSeed));
if(result.IsSuccess())
{
mp_Ivs = pSeed;
m_SizeofIvs = sizeof(nn::fs::CTR::IntegrityVerificationSeed);
m_CanReadIvs = true;
}
// 後でIVSを参照するのでFreeしない
}
}
}
// NULL終端されたシリアルナンバーを受け取る
// NULL終端された場所にチェックデジットを付加して新たにNULL終端する
void Util::AddCheckDigit(char* serial)
{
size_t len = std::strlen(serial);
u8 digit = 0;
bool odd = true;
for(u8 i = len - 1; i > 0 && std::isdigit(serial[i]); i--)
{
if(odd)
{
digit += (serial[i] - '0') * 3;
}
else
{
digit += (serial[i] - '0');
}
odd = !odd;
}
if(digit % 10 != 0)
{
serial[len] = 10 - (digit % 10) + '0';
}
else
{
serial[len] = '0';
}
serial[len + 1] = '\0';
}
// /Nintendo 3DS/6ea6b9d6ab70493ea9edd8b947d5d819/853600b24760a87f534430320002544d
// から、6ea6b9d6ab70493ea9edd8b947d5d819 を取り出す
void Util::GetSaveDataDirectoryRoot(::std::string& sysSaveRoot)
{
nn::Result result;
wchar_t path[512];
result = nn::fs::GetSdmcCtrRootPath(path, sizeof(path));
COMMON_LOGGER_RETURN_VOID_IF_FAILED(result);
NN_LOG("%ls\n", path);
std::string sdmcRootPath = common::GetCharStr(path);
sysSaveRoot = sdmcRootPath.substr(sizeof("Nintendo 3DS/"), 32);
NN_LOG("saveRoot = %s\n", sysSaveRoot.c_str());
}
bool Util::IsAdapterConnected()
{
static nn::os::Tick last(0);
static bool lastResult = false;
const u8 UPDATE_INTERVAL = 100;
nn::os::Tick now = nn::os::Tick::GetSystemCurrent();
if(last == 0 || (now - last).ToTimeSpan().GetMilliSeconds() > UPDATE_INTERVAL)
{
u8 buf;
nn::Result result = mp_Mcu->ReadByReceive(nn::drivers::mcu::CTR::MCU_PERIPHERAL_STATUS_ADDR, &buf, sizeof(buf));
if(result.IsSuccess())
{
last = now;
lastResult = buf & nn::drivers::mcu::CTR::MCU_STATUS_ADAPTER_MASK;
}
}
return lastResult;
}
bool Util::IsBatteryLower()
{
m_BatteryRemain = GetBatteryRemain();
return m_BatteryRemain <= 10;
}
bool Util::CanReadIVS()
{
return m_CanReadIvs;
}
bool Util::CanReadSerialNumber()
{
return m_CanReadSerialNumber;
}
void Util::GetSerialNumber(u8** serial, size_t* size)
{
*serial = m_SerialNo;
*size = nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN;
}
u8* Util::GetSerialNumber()
{
return m_SerialNo;
}
void Util::GetIvs(void** ivs, size_t* size)
{
*ivs = mp_Ivs;
*size = m_SizeofIvs;
}
bit32 Util::GetDeviceId()
{
return m_DeviceId;
}
u8 Util::GetCupMajorVersion()
{
return m_VerData.cup.majorVersion;
}
u8 Util::GetCupMinorVersion()
{
return m_VerData.cup.minorVersion;
}
u8 Util::GetCupMicroVersion()
{
return m_VerData.cup.microVersion;
}
u8 Util::GetNupVersion()
{
return m_VerData.nup.majorVersion;
}
nn::Handle Util::GetMcuHandle()
{
return m_McuSession;
}
u32 Util::GetBatteryRemain()
{
u8 remain;
mp_Mcu->GetBatteryRemain(&remain);
return remain;
}
u64 Util::GetInfraDeviceId()
{
bit64 infraDeviceId;
infraDeviceId = m_DeviceId + common::INFRA_DEVICE_ID_OFFSET;
return infraDeviceId;
}
u64 Util::GetFriendcode()
{
return m_FriendCode;
}
char8* Util::GetMacAddress()
{
return m_MacAddress;
}
nn::cfg::CTR::CfgRegionCode Util::GetRegion()
{
return m_Region;
}
const char* Util::GetRegionCodeA3()
{
return nn::cfg::GetRegionCodeA3(m_Region);
}
void Util::GetVersionData(common::VerDef* version)
{
*version = m_VerData;
}
bool Util::HasReadFriendCode()
{
return m_HasReadFriendCode;
}
}

View File

@ -0,0 +1,167 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: Util.h
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$
*---------------------------------------------------------------------------*/
#ifndef UTIL_H_
#define UTIL_H_
#include <string>
#include <nn.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/mcu.h>
#include <nn/nwm.h>
#include "VersionDetect.h"
namespace common
{
class Util
{
public:
Util();
virtual ~Util();
void InitializeForBackup();
void InitializeForRestore();
void FinalizeForBackup();
void FinalizeForRestore();
// シリアルナンバーにモジュラス10 ウェイト3・1M10W31でチェックデジットを付加する
static void AddCheckDigit(char* serial);
// IVSから計算されるセーブデータディレクトリ名を取得する
static void GetSaveDataDirectoryRoot(::std::string& sysSaveRoot);
// ACアダプタが接続されているかどうか
bool IsAdapterConnected();
// バッテリ残量が10%未満かどうか
bool IsBatteryLower();
// IVSを読み取れるかどうか
bool CanReadIVS();
// シリアルナンバーを読み取れるかどうか
bool CanReadSerialNumber();
// シリアルナンバーを取得する
void GetSerialNumber(u8** serial, size_t* size);
// シリアルナンバーを返す
u8* GetSerialNumber();
// IVSを取得する
void GetIvs(void** ivs, size_t* size);
// 32bitデバイスIDを返す
bit32 GetDeviceId();
// CUPメジャーバージョンを返す
u8 GetCupMajorVersion();
// CUPマイナーバージョンを返す
u8 GetCupMinorVersion();
// CUPマイクロバージョンを返す
u8 GetCupMicroVersion();
// NUPバージョンを返す
u8 GetNupVersion();
// MCUプロセスに接続するためのハンドルを返す
nn::Handle GetMcuHandle();
// バッテリ残量を0100で返す
u32 GetBatteryRemain();
// 64bitインフラデバイスIDを返す
u64 GetInfraDeviceId();
// フレンドコードを返す
u64 GetFriendcode();
// MACアドレスを返す
char8* GetMacAddress();
// リージョンコードを返す
nn::cfg::CTR::CfgRegionCode GetRegion();
// リージョンコードを3文字のアルファベットに置き換えた文字列を返す
const char* GetRegionCodeA3();
// バージョン情報を取得する
void GetVersionData(common::VerDef* version);
// フレンドコードを取得済みかどうか
bool HasReadFriendCode();
private:
void Initialize();
void Finalize();
void ReadIvs(u8 cupMajorVersion);
NN_PADDING4;
// フレンドコード
u64 m_FriendCode;
// バージョン情報
common::VerDef m_VerData;
// mcu接続のためのハンドル
nn::Handle m_McuSession;
// デバイスID
bit32 m_DeviceId;
// IVSへのポインタ
void* mp_Ivs;
// IVSのサイズ
size_t m_SizeofIvs;
NN_PADDING4;
// MCUへのポインタ
nn::mcu::CTR::HwCheck* mp_Mcu;
// リージョン
nn::cfg::CTR::CfgRegionCode m_Region;
// バッテリ残量
u8 m_BatteryRemain;
// シリアルナンバーが読めるかどうか
bool m_CanReadSerialNumber;
// IVSが読めるかどうか
bool m_CanReadIvs;
// シリアルナンバー
u8 m_SerialNo[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN];
// MACアドレス
char8 m_MacAddress[nn::nwm::Mac::MAC_STRING_SIZE];
NN_PADDING3;
// FriendCodeを読んだかどうか
bool m_HasReadFriendCode;
NN_PADDING3;
NN_PADDING4;
};
}
#endif /* UTIL_H_ */

View File

@ -0,0 +1,120 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: VersionDetect.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.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include "VersionDetect.h"
#include "HeapManager.h"
#include "CommonLogger.h"
namespace common
{
void GetCupVersion(nn::pl::CTR::CardUpdateVersion* cup, nn::cfg::CTR::CfgRegionCode region)
{
nn::Result result;
const size_t BUF_SIZE = 1024;
u8 buf[BUF_SIZE];
// CUPバージョン
{
result = nn::fs::MountContent("cver:", nn::fs::MEDIA_TYPE_NAND, common::cCupVerId[region], 0, 1, 1, buf,
BUF_SIZE);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
nn::fs::FileInputStream fis;
result = fis.TryInitialize(L"cver:/version.bin");
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsSuccess())
{
s64 fileSize = fis.GetSize();
NN_LOG("version.bin size = %lld\n", fileSize);
s32 ret;
void* addr = NULL;
common::HeapManager heap(fileSize);
addr = heap.GetAddr();
if (addr != NULL)
{
result = fis.TryRead(&ret, addr, fileSize);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsSuccess())
{
nn::pl::CTR::CardUpdateVersion* ver_buf = reinterpret_cast<nn::pl::CTR::CardUpdateVersion*> (addr);
std::memcpy(cup, ver_buf, sizeof(nn::pl::CTR::CardUpdateVersion));
}
}
}
fis.Finalize();
nn::fs::Unmount("cver:");
}
}
void GetNupVersion(nn::pl::CTR::NetworkUpdateVersion* nup, nn::cfg::CTR::CfgRegionCode region)
{
nn::Result result;
const size_t BUF_SIZE = 1024;
u8 buf[BUF_SIZE];
// NUPバージョン
{
result = nn::fs::MountContent("nver:", nn::fs::MEDIA_TYPE_NAND, common::cNupVerId[region], 0, 1, 1, buf,
BUF_SIZE);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
nn::fs::FileInputStream fis;
result = fis.TryInitialize(L"nver:/version.bin");
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsSuccess())
{
s64 fileSize = fis.GetSize();
NN_LOG("version.bin size = %lld\n", fileSize);
s32 ret;
void* addr = NULL;
common::HeapManager heap(fileSize);
addr = heap.GetAddr();
if (addr != NULL)
{
result = fis.TryRead(&ret, addr, fileSize);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsSuccess())
{
nn::pl::CTR::NetworkUpdateVersion* ver_buf =
reinterpret_cast<nn::pl::CTR::NetworkUpdateVersion*> (addr);
std::memcpy(nup, ver_buf, sizeof(nn::pl::CTR::NetworkUpdateVersion));
}
}
}
fis.Finalize();
nn::fs::Unmount("nver:");
}
}
void GetSystemVersion(common::VerDef* mVerData, nn::cfg::CTR::CfgRegionCode region)
{
GetCupVersion(&mVerData->cup, region);
GetNupVersion(&mVerData->nup, region);
}
}

View File

@ -0,0 +1,31 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: VersionDetect.h
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$
*---------------------------------------------------------------------------*/
#ifndef VERSIONDETECT_H_
#define VERSIONDETECT_H_
#include <nn/cfg/CTR/cfg_RegionCode.h>
#include "common_Types.h"
namespace common
{
// リージョンコードに基づいてバージョン情報を取得する
void GetSystemVersion(common::VerDef* mVerData, nn::cfg::CTR::CfgRegionCode region);
}
#endif /* VERSIONDETECT_H_ */

View File

@ -0,0 +1,133 @@
/*---------------------------------------------------------------------------*
Project: Horizon
File: common_Types.h
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$
*---------------------------------------------------------------------------*/
#ifndef COMMON_TYPES_H_
#define COMMON_TYPES_H_
#include <nn/cfg/CTR/cfg_NtrSettings.h>
#include <nn/cfg/CTR/cfg_CountryCode.h>
#include <nn/cfg/CTR/cfg_LanguageCode.h>
#include <nn/cfg/CTR/detail/cfg_DataStructures.h>
#include <nn/pl/CTR/pl_SharedDataTitleId.h>
#include <nn/pl/CTR/pl_Version.h>
#include <vector>
#include <string>
namespace common
{
const u32 CONSOLE_WIDTH = 38;
const u32 CONSOLE_HEIGHT = 24;
const u32 CONSOLE_MAX_LINE = 1000;
const u32 NTR_WIFI_SETTING_SIZE = 0x400; // NTR Wifi 設定のサイズ
const u32 TWL_WIFI_SETTING_SIZE = 0x600; // TWL Wifi 設定のサイズ
const u64 INFRA_DEVICE_ID_OFFSET = 0x400000000;
const size_t FILE_COPY_HEAP_SIZE = 16 * 1024 * 1024;
const u8 CUP_MAJOR_VER_2ND_NUP = 3;
// NOR領域のみにある設定データ用構造体
struct NtrNorData
{
nn::cfg::CTR::NtrConfig ntrConfig;
u8 TwlWiFiSetting[TWL_WIFI_SETTING_SIZE];
u8 NtrWiFiSetting[NTR_WIFI_SETTING_SIZE];
};
struct CfgCountryLanguage
{
enum nn::cfg::CTR::CfgCountryCode country;
enum nn::cfg::CTR::CfgLanguageCode language;
NN_PADDING1;
};
struct VerDef
{
nn::pl::CTR::CardUpdateVersion cup;
nn::pl::CTR::NetworkUpdateVersion nup;
};
// CALに依存するCFGパラメータ
struct CfgCalData
{
nn::cfg::CTR::detail::TouchPanelCfgData touchPanelCfgData;
nn::cfg::CTR::detail::LcdFlickerCfgData lcdFlickerCfgData;
nn::cfg::CTR::detail::FcramCfgData fcramCfgData;
nn::cfg::CTR::detail::RtcCfgData rtcCfgData;
nn::cfg::CTR::detail::GyroscopeCfgData gyroscopeCfgData;
nn::cfg::CTR::detail::AccelCfgData accelCfgData;
nn::cfg::CTR::detail::CodecCfgData codecCfgData;
nn::cfg::CTR::detail::McuSlideVolumeRangeCfgData mcuSlideVolumeRangeCfgData;
NN_PADDING2;
};
// TODO:リージョン追加時に範囲外アクセスにならないよう注意
const nn::ProgramId cCupVerId[] =
{
nn::pl::CTR::SHAREDDATA_TITLEID_CUP_VERSION_JP,
nn::pl::CTR::SHAREDDATA_TITLEID_CUP_VERSION_US,
nn::pl::CTR::SHAREDDATA_TITLEID_CUP_VERSION_EU,
nn::pl::CTR::SHAREDDATA_TITLEID_CUP_VERSION_EU,
nn::pl::CTR::SHAREDDATA_TITLEID_CUP_VERSION_CN,
nn::pl::CTR::SHAREDDATA_TITLEID_CUP_VERSION_KR,
nn::pl::CTR::SHAREDDATA_TITLEID_CUP_VERSION_TW,
};
const nn::ProgramId cNupVerId[] =
{
nn::pl::CTR::SHAREDDATA_TITLEID_NUP_VERSION_JP,
nn::pl::CTR::SHAREDDATA_TITLEID_NUP_VERSION_US,
nn::pl::CTR::SHAREDDATA_TITLEID_NUP_VERSION_EU,
nn::pl::CTR::SHAREDDATA_TITLEID_NUP_VERSION_EU,
nn::pl::CTR::SHAREDDATA_TITLEID_NUP_VERSION_CN,
nn::pl::CTR::SHAREDDATA_TITLEID_NUP_VERSION_KR,
nn::pl::CTR::SHAREDDATA_TITLEID_NUP_VERSION_TW,
};
// SDに出力するデータのヘッダ
struct BackupDataHeader
{
s64 size; // パディングを含まないファイルサイズ
NN_PADDING4;
NN_PADDING4;
};
// SDから読み込むファイルリストのエントリ
struct ImportDataEntry
{
std::string fileName;
NN_PADDING3;
bool isDirectory;
};
typedef std::vector<common::ImportDataEntry> ImportDataList;
// TWLセーブデータリストのエントリ
struct SavePathInfo
{
std::wstring name;
NN_PADDING3;
bool isDirectory;
};
}
#endif /* COMMON_TYPES_H_ */

View File

@ -0,0 +1,181 @@
#include <wchar.h>
#include <nn/fs.h>
#include <cstdlib>
#include "configLoader.h"
namespace common
{
Result ConfigFileLoader::Initialize(const wchar_t* fileName, void* buffer, const size_t bufferSize)
{
s64 fileSize;
FileInputStream fi;
NN_UTIL_RETURN_IF_FAILED(fi.TryInitialize(fileName));
NN_UTIL_RETURN_IF_FAILED(fi.TryGetSize(&fileSize));
// NULL終端ぶん読めるサイズを減らす
if (fileSize > bufferSize - sizeof(wchar_t))
{
NN_TLOG_("Too Large File\n");
return Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_TOO_LARGE);
}
m_Buffer = static_cast<wchar_t*>(buffer);
NN_UTIL_RETURN_IF_FAILED(fi.TryRead(&m_UsedBufferSize, m_Buffer, fileSize));
NN_LOG("config size = %d\n", m_UsedBufferSize);
return ParseData();
}
void ConfigFileLoader::Finalize()
{
m_Buffer = 0;
m_ParamNum = 0;
}
Result ConfigFileLoader::ParseData()
{
if (!m_Buffer)
{
return Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_NOT_INITIALIZED);
}
int pos = 0;
// ビッグエンディアンでないことを確認
NN_ASSERTMSG(m_Buffer[0] != 0xfffe, "Invalid Config File's Endian\n");
if (m_Buffer[0] == 0xfeff)
{
// UTF-16 BOMの調整
pos++;
}
m_ParamNum = 0;
m_ParamName[m_ParamNum] = &(m_Buffer[pos]);
m_ParamValue[m_ParamNum] = L"";
m_Buffer[m_UsedBufferSize / sizeof(wchar_t)] = L'\0'; // NULL終端しておく
// ダブルクウォート中なら : も文字として読み取る
bool inEscape = false;
// # で行末までコメント
bool inComment = false;
// : で行頭から:までがkey、:から行末までがvalue
bool inSettingKeyValue = false;
while (pos < m_UsedBufferSize / sizeof(m_Buffer[0]))
{
switch (m_Buffer[pos])
{
case L'"':
{
inEscape = !inEscape;
}
break;
case L'#':
{
inComment = true;
}
break;
case L':':
{
if (inEscape || inComment)
{
break;
}
if (inSettingKeyValue)
{
break;
}
else
{
inSettingKeyValue = true;
}
m_Buffer[pos] = L'\0';
m_ParamValue[m_ParamNum++] = &(m_Buffer[pos + 1]);
}
break;
case L'\r':
case L'\n':
{
if (inComment)
{
inComment = false;
}
if (inSettingKeyValue)
{
inSettingKeyValue = false;
}
m_Buffer[pos] = L'\0';
m_ParamName[m_ParamNum] = &(m_Buffer[pos + 1]);
m_ParamValue[m_ParamNum] = L"";
}
break;
}
if (PARAM_MAX_NUM <= m_ParamNum)
{
NN_TLOG_("Too Many Params\n");
return Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_TOO_LARGE);
}
pos++;
}
return ResultSuccess();
}
s32 ConfigFileLoader::SearchParamName(const wchar_t *paramName)
{
if (!m_Buffer)
{
NN_TLOG_("ConfigFileLoader not initialized.\n");
return -1;
}
for (s32 i = 0; i < m_ParamNum; i++)
{
if (wcscmp(m_ParamName[i], paramName) == 0)
{
return i;
}
}
return -1;
}
const wchar_t *ConfigFileLoader::ReadAsWChar(const wchar_t *paramName)
{
s32 idx = SearchParamName(paramName);
if (idx < 0)
{
NN_LOG("Unknown Parameter Name %ls\n", paramName);
}
return (idx < 0) ? NULL : m_ParamValue[idx];
}
const char *ConfigFileLoader::ReadAsChar(const wchar_t *paramName)
{
memset(m_ReadCharBuffer, 0, sizeof(m_ReadCharBuffer));
const wchar_t *value = ReadAsWChar(paramName);
if(value == NULL)
{
return NULL;
}
wcstombs(m_ReadCharBuffer, value, sizeof(m_ReadCharBuffer));
// NULL終端する
m_ReadCharBuffer[sizeof(m_ReadCharBuffer) - 1] = '\0';
return m_ReadCharBuffer;
}
int ConfigFileLoader::ReadAsInteger(const wchar_t *paramName)
{
return atoi(ReadAsChar(paramName));
}
}

View File

@ -0,0 +1,78 @@
#ifndef NN_CONFIG_LOADER_H_
#define NN_CONFIG_LOADER_H_
namespace common
{
using namespace nn;
using namespace nn::fs;
using namespace std;
class ConfigFileLoader
{
private:
static const int PARAM_VALUE_MAX_STRING_LENGTH = 128;
static const int PARAM_MAX_NUM = 64;
char m_ReadCharBuffer[PARAM_VALUE_MAX_STRING_LENGTH];
wchar_t *m_ParamName[PARAM_MAX_NUM];
wchar_t *m_ParamValue[PARAM_MAX_NUM];
wchar_t *m_Buffer;
s32 m_UsedBufferSize;
s32 m_ParamNum;
public:
ConfigFileLoader() : m_Buffer(0), m_UsedBufferSize(0), m_ParamNum(0)
{
}
/*
@brief ConfigFileLoader
使
使 buffer
Finalize
UTF-16
  
    
ParameterName : ParameterValue;
L"ParameterName "
L" ParameterValue;"
@param[in] fileName
@param[in] buffer
@param[in] bufferSize buffer
@return
*/
Result Initialize(const wchar_t* fileName, void* buffer, const size_t bufferSize);
void Finalize();
// スレッドセーフです.
const wchar_t *ReadAsWChar(const wchar_t *paramName);
// スレッドセーフではありません.
const char *ReadAsChar(const wchar_t *paramName);
// スレッドセーフです.
int ReadAsInteger(const wchar_t *paramName);
private:
Result ParseData();
s32 SearchParamName(const wchar_t *paramName);
};
}
#endif // NN_CONFIG_LOADER_H_

Some files were not shown because too many files have changed in this diff Show More