diff --git a/branches/2-1-1/documents/CTR修理フロー_1stNUP.vsd b/branches/2-1-1/documents/CTR修理フロー_1stNUP.vsd new file mode 100644 index 0000000..a3d6b89 Binary files /dev/null and b/branches/2-1-1/documents/CTR修理フロー_1stNUP.vsd differ diff --git a/branches/2-1-1/documents/CTR本体データ移行ツール説明.doc b/branches/2-1-1/documents/CTR本体データ移行ツール説明.doc new file mode 100644 index 0000000..9af3457 Binary files /dev/null and b/branches/2-1-1/documents/CTR本体データ移行ツール説明.doc differ diff --git a/branches/2-1-1/documents/CTR用本体データ移行ツール仕様_20101221.ppt b/branches/2-1-1/documents/CTR用本体データ移行ツール仕様_20101221.ppt new file mode 100644 index 0000000..e16207e Binary files /dev/null and b/branches/2-1-1/documents/CTR用本体データ移行ツール仕様_20101221.ppt differ diff --git a/branches/2-1-1/documents/Readme.txt b/branches/2-1-1/documents/Readme.txt new file mode 100644 index 0000000..1344c71 --- /dev/null +++ b/branches/2-1-1/documents/Readme.txt @@ -0,0 +1,15 @@ +yrh‹z + +ESDK +Horizon trunk r43280ȍ~ + +Ecygwin +Esubversion + +yrh̒Ӂz +J@EʎY@AESς邽߁A}X^Oprh +sources\common\Aes_define.h + +#define USE_PROD_KEY +Lɂ邱ƁB + diff --git a/branches/2-1-1/documents/SD出力ファイルのフォーマット.vsd b/branches/2-1-1/documents/SD出力ファイルのフォーマット.vsd new file mode 100644 index 0000000..d81ab68 Binary files /dev/null and b/branches/2-1-1/documents/SD出力ファイルのフォーマット.vsd differ diff --git a/branches/2-1-1/documents/SavedataCheckerテスト.xls b/branches/2-1-1/documents/SavedataCheckerテスト.xls new file mode 100644 index 0000000..3c2ecc3 Binary files /dev/null and b/branches/2-1-1/documents/SavedataCheckerテスト.xls differ diff --git a/branches/2-1-1/documents/データ移行ツール1stNUPテスト.xls b/branches/2-1-1/documents/データ移行ツール1stNUPテスト.xls new file mode 100644 index 0000000..ea70cbd Binary files /dev/null and b/branches/2-1-1/documents/データ移行ツール1stNUPテスト.xls differ diff --git a/branches/2-1-1/documents/データ移行ツール2ndNUPテスト.xls b/branches/2-1-1/documents/データ移行ツール2ndNUPテスト.xls new file mode 100644 index 0000000..0301e6b Binary files /dev/null and b/branches/2-1-1/documents/データ移行ツール2ndNUPテスト.xls differ diff --git a/branches/2-1-1/sources/ConsoleBackup/Checker.cpp b/branches/2-1-1/sources/ConsoleBackup/Checker.cpp new file mode 100644 index 0000000..80543a5 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/Checker.cpp @@ -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 + +namespace ConsoleBackup +{ + +namespace +{ + +const size_t CHECKER_STACK_SIZE = 0x4000; +nn::os::Thread s_CheckerThread; +nn::os::StackBuffer 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(); +} + +} + diff --git a/branches/2-1-1/sources/ConsoleBackup/Checker.h b/branches/2-1-1/sources/ConsoleBackup/Checker.h new file mode 100644 index 0000000..74f57da --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/Checker.h @@ -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_ */ diff --git a/branches/2-1-1/sources/ConsoleBackup/ConsoleBackup.bsf b/branches/2-1-1/sources/ConsoleBackup/ConsoleBackup.bsf new file mode 100644 index 0000000..104a94d Binary files /dev/null and b/branches/2-1-1/sources/ConsoleBackup/ConsoleBackup.bsf differ diff --git a/branches/2-1-1/sources/ConsoleBackup/ConsoleBackup.cpp b/branches/2-1-1/sources/ConsoleBackup/ConsoleBackup.cpp new file mode 100644 index 0000000..981a48c --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/ConsoleBackup.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "demo.h" + +#include +#include + +#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 + +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(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 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(); + } + } +} + + +} diff --git a/branches/2-1-1/sources/ConsoleBackup/ConsoleBackup.rsf b/branches/2-1-1/sources/ConsoleBackup/ConsoleBackup.rsf new file mode 100644 index 0000000..0adba97 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/ConsoleBackup.rsf @@ -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)" \ No newline at end of file diff --git a/branches/2-1-1/sources/ConsoleBackup/Controller.cpp b/branches/2-1-1/sources/ConsoleBackup/Controller.cpp new file mode 100644 index 0000000..8d5da7d --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/Controller.cpp @@ -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 + +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 + +void PutAliveMessage(::std::vector& 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& 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 diff --git a/branches/2-1-1/sources/ConsoleBackup/Controller.h b/branches/2-1-1/sources/ConsoleBackup/Controller.h new file mode 100644 index 0000000..ef10878 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/Controller.h @@ -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 +#include +#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& 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_ */ diff --git a/branches/2-1-1/sources/ConsoleBackup/Exporter.cpp b/branches/2-1-1/sources/ConsoleBackup/Exporter.cpp new file mode 100644 index 0000000..fd4c75f --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/Exporter.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // cfg:norの初期化に必要 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 entryList; //カレントディレクトリのエントリ一覧を格納 + std::vector::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& 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 (manager.GetAddr()); + + size_t writeSize = 0; + if (titleListBuf != NULL) + { + for (std::vector::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, ®ion, 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* 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* 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* 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* list, + std::vector* programIdList) +{ + nn::fs::FileInputStream fis; + nn::fs::Directory dir; + nn::Result result; + std::vector entryList; //カレントディレクトリのエントリ一覧を格納 + std::vector::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* fileList, s64* fileSize) +{ + NN_NULL_ASSERT(fileList); + NN_NULL_ASSERT(fileSize); + + *fileSize = 0; + nn::Result result = nn::ResultSuccess(); + + for (std::vector::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 fileList; + std::vector 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::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::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; +} + +} diff --git a/branches/2-1-1/sources/ConsoleBackup/Exporter.h b/branches/2-1-1/sources/ConsoleBackup/Exporter.h new file mode 100644 index 0000000..6b8bdca --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/Exporter.h @@ -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 +#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_ */ diff --git a/branches/2-1-1/sources/ConsoleBackup/OMakefile b/branches/2-1-1/sources/ConsoleBackup/OMakefile new file mode 100644 index 0000000..bc1f3f6 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/OMakefile @@ -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) diff --git a/branches/2-1-1/sources/ConsoleBackup/SavedataChecker.cpp b/branches/2-1-1/sources/ConsoleBackup/SavedataChecker.cpp new file mode 100644 index 0000000..5dbada1 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/SavedataChecker.cpp @@ -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 +#include + +#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 */ diff --git a/branches/2-1-1/sources/ConsoleBackup/SavedataChecker.h b/branches/2-1-1/sources/ConsoleBackup/SavedataChecker.h new file mode 100644 index 0000000..c9a5a30 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/SavedataChecker.h @@ -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 + +#include +#include + +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_ */ diff --git a/branches/2-1-1/sources/ConsoleBackup/banner/model.cbmd b/branches/2-1-1/sources/ConsoleBackup/banner/model.cbmd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/ConsoleBackup/banner/model.cbmd differ diff --git a/branches/2-1-1/sources/ConsoleBackup/banner/sound.cbsd b/branches/2-1-1/sources/ConsoleBackup/banner/sound.cbsd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/ConsoleBackup/banner/sound.cbsd differ diff --git a/branches/2-1-1/sources/ConsoleBackup/banner/unknown24x24.ctpk b/branches/2-1-1/sources/ConsoleBackup/banner/unknown24x24.ctpk new file mode 100644 index 0000000..794b136 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/banner/unknown24x24.ctpk @@ -0,0 +1 @@ +888yyYyYyyyYyyYyyyyYyYy8 \ No newline at end of file diff --git a/branches/2-1-1/sources/ConsoleBackup/banner/unknown48x48.ctpk b/branches/2-1-1/sources/ConsoleBackup/banner/unknown48x48.ctpk new file mode 100644 index 0000000..8c7da16 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleBackup/banner/unknown48x48.ctpk @@ -0,0 +1 @@ +Y8888ƺ8888YYyyYYޚ޺yY8YyYYޚyY8ޚ8 \ No newline at end of file diff --git a/branches/2-1-1/sources/ConsoleRestore/ConsoleRestore.bsf b/branches/2-1-1/sources/ConsoleRestore/ConsoleRestore.bsf new file mode 100644 index 0000000..104a94d Binary files /dev/null and b/branches/2-1-1/sources/ConsoleRestore/ConsoleRestore.bsf differ diff --git a/branches/2-1-1/sources/ConsoleRestore/ConsoleRestore.cpp b/branches/2-1-1/sources/ConsoleRestore/ConsoleRestore.cpp new file mode 100644 index 0000000..ab8c616 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/ConsoleRestore.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "demo.h" + +#include +#include + +#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 + +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(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(s_HwUtility.GetFriendcode() / 100000000ULL % 10000ULL), + static_cast(s_HwUtility.GetFriendcode() / 10000ULL % 10000ULL), + static_cast(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 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(); + } + } +} + + +} diff --git a/branches/2-1-1/sources/ConsoleRestore/ConsoleRestore.rsf b/branches/2-1-1/sources/ConsoleRestore/ConsoleRestore.rsf new file mode 100644 index 0000000..b40cf17 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/ConsoleRestore.rsf @@ -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)" \ No newline at end of file diff --git a/branches/2-1-1/sources/ConsoleRestore/Controller.cpp b/branches/2-1-1/sources/ConsoleRestore/Controller.cpp new file mode 100644 index 0000000..24ced4c --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/Controller.cpp @@ -0,0 +1,1681 @@ +/*---------------------------------------------------------------------------* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Controller.h" +#include "FileChecker.h" +#include "SimplePlayer.h" +#include "CommonLogger.h" +#include "Importer.h" +#include "Updater.h" +#include "NtpClient.h" +#include "TitleDownloader.h" +#include "Shop.h" +#include "Util.h" + +namespace ConsoleRestore +{ + +namespace +{ + +// ネットワーク設定ファイルを読んだかどうか +bool s_ReadSettingDone = false; +// インターネット設定を読んだ結果 +bool s_ReadSettingIsSuccess = false; +// NUP専用モードかどうか +bool s_NupOnlyMode = false; +// IVS取得専用モードかどうか +bool s_GetIvsOnlyMode = false; +// SDカード確認専用モード +bool s_CheckSdOnlyMode = false; +// NUPスキップモードかどうか +bool s_SkipNupMode = false; + +// APSettingの書式が無い警告サウンドを鳴らしたかどうか +bool s_ExistAPSettingAnnotation = false; +// APSettingの書式が違っている警告サウンドを鳴らしたかどうか +bool s_APSettingAnnotation = false; +// シリアルナンバーがない警告サウンドを鳴らしたかどうか +bool s_SerialNumberAnnotation = false; +// 失敗サウンドを鳴らしたかどうか +bool s_PlayedFailSound = false; +// 操作開始サウンドを鳴らしたかどうか +bool s_PlayedStartCursor = false; +// リブート開始前サウンドを鳴らしたかどうか +bool s_PlayedRebootCursor = false; +// SD抜き出し前サウンドを鳴らしたかどうか +bool s_PlayedSdPullOutCursor = false; +// SDに書き込みできない警告サウンドを鳴らしたかどうか +bool s_SdWriteProetctAnnotation = false; +// WiFiがOFFである警告サウンドを鳴らしたかどうか +bool s_WifiStatusOffAnnotation = false; + +// ネットワークアップデートを開始したかどうか +bool s_ExecuteFgNup = false; +// FGNUPを何回リトライしたか +u32 s_FgNupRetryCount = 0; +// 時計同期モードかどうか +bool s_IsSyncClock = false; +// TWLタイトルのダウンロードを開始したかどうか +bool s_ExecuteTitleDownload = false; +// TWLタイトルのダウンロードを何回リトライしたか +u32 s_TitleDownloadRetryCount = 0; + +// ショップ処理を開始したかどうか +bool s_ShopOperationExecuted[SHOP_OPERATION_NUM_MAX]; +// ショップ処理を何回リトライしたか +u32 s_ShopOperationRetryCount[SHOP_OPERATION_NUM_MAX]; + +void PutAliveMessage(::std::vector& operationMessage, const char* str); +bool CheckAndReadAPSetting(::std::vector& operationMessage); + +bool NeedsAcAdater(common::HardwareStateManager& manager) +{ + return manager.IsBatteryLower() && !manager.IsAdapterConnected(); +} + +bool HasValidRtcData() +{ + return !s_CheckSdOnlyMode && !s_NupOnlyMode && !s_GetIvsOnlyMode; +} + +typedef enum RestoreState +{ + STARTUP, // 初期値 + INITIALIZE_CONSOLE, // セーブデータ領域のNAND初期化を行う + SERIAL_IS_NOT_IN_SD, // シリアルナンバーファイルがSDカードにないことを表示 + WAIT_START_UPDATE, // アップデート開始入力待ち + WAIT_START_IMPORT, // 書き込み開始入力待ち + WAIT_START_SYNC_CLOCK, // 時計合わせ開始入力待ち + IMPORT_RTC, // RTC同期 + UPDATE_IN_PROGRESS, // アップデート中 + UPDATE_DONE, // アップデート完了 + NUP_ONLY_WAIT_SD_EJECT, // NUP_ONLYモードでSDカード抜き待ち + NUP_ONLY_WAIT_NEXT, // NUP_ONLYモードでキー入力待ち + WAIT_START_TRANSFER_ACCOUNT, // アカウント転送開始入力まち + TRANSFER_ACCOUNT, // アカウント転送を完了させる + TRANSFER_ACCOUNT_DONE, // アカウント転送完了 + DOWNLOAD_IVS, // インフラからIVSを取得する + DOWNLOAD_IVS_DONE, // インフラからIVSを取得完了 + DOWNLOAD_IVS_WAIT_NEXT, // IVS取得モードでキー入力待ち + CHECK_IVS, // IVSとSDカードのセーブデータディレクトリの一致を確認 + CHECK_SD_DIRECTORY, // SDカードのIVS依存ディレクトリを探す + CHECK_SD_DIRECTORY_SUCCESS, // SDカードのIVS依存ディレクトリチェック完了 + CHECK_SD_DIRECTORY_FAIL, // SDカードのIVS依存ディレクトリが見つからなかった + WAIT_START_DELETE_ACCOUNT, // ショップアカウント削除開始入力待ち, + DELETE_ACCOUNT, // ショップアカウントを削除する + DELETE_ACCOUNT_DONE, // ショップアカウント削除完了 + SYNC_TICKET, // eTicketを同期する + READ_FILELIST, // ファイル一覧の読み込み + RESTORE_TWL_NAND, // TWL NANDの書き込み中 + RESTORE_TWL_SOUND, // TWLサウンドの書き込み中 + RESTORE_TWL_PHOTO, // TWL写真の書き込み中 + RESTORE_IN_PROGRESS, // 書き込み中 + POST_RESTORE, // 書き込み後の処理 + RESTORE_DONE, // 書き込み完了 + REBOOTING, // 再起動を行う + ERASE, // 削除処理を行う + RESTORE_CAL, // cfgの一部をcal値で上書きする + TIME_ADJUST, // 時計あわせを行う + DOWNLOAD_TWL, // TWLアプリ本体をダウンロードする + WAIT_SD_EJECT, // SDカードぬき待ち + ALL_DONE, // すべて完了 + INITIALIZE_AND_SHUTDOWN, // 本体初期化後にシャットダウン中 + FAIL // 失敗 +} RestoreState; + + + +// Restore状態管理 +RestoreState s_RestoreState = STARTUP; +// Restoreモード管理 +RestoreMode s_RestoreMode = RESTORE_MODE_RESTORE; + +void CheckSdInserted(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckAcAdapter(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckSdWritable(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckApSetting(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckNupExecuted(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckDownloadIvs(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckAccountDeleted(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckAccountTransfered(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckWriteFinished(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckReadIvs(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckConsoleInitialized(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckExistsSerialNumber(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckIvsinSd(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); +void CheckRegioinSd(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep); + +// SDカード挿入チェック +void CheckSdInserted(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + if (nn::fs::IsSdmcInserted()) + { + CheckAcAdapter(manager, message, goNextStep); + } + else + { + message.push_back(::std::string("Insert SD Card!!")); + s_RestoreState = STARTUP; + } +} + +// ACアダプタが必要かどうかチェック +void CheckAcAdapter(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + // ACアダプタが必要か? + if (NeedsAcAdater(manager)) + { + message.push_back(::std::string("Connect AC Adapter!!")); + s_RestoreState = STARTUP; + } + else + { + CheckSdWritable(manager, message, goNextStep); + } +} + +// SDカード書き込みチェック +void CheckSdWritable(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + // SDカードに書き込みできるか? + if (nn::fs::IsSdmcWritable()) + { + CheckApSetting(manager, message, goNextStep); + } + else + { + if (!s_SdWriteProetctAnnotation) + { + s_SdWriteProetctAnnotation = true; + common::PlaySound(common::SOUND_ANNOTATION); + } + message.push_back(::std::string("Can't Write SD Card!!\n")); + s_RestoreState = STARTUP; + } +} + + +// 設定ファイル書式チェック +void CheckApSetting(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + NN_UNUSED_VAR(manager); + NN_UNUSED_VAR(goNextStep); + + if (CheckAndReadAPSetting(message)) + { + s_RestoreState = IMPORT_RTC; + } + else + { + s_RestoreState = STARTUP; + } +} + +// NUP済みかどうかチェック +void CheckNupExecuted(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + if (common::ExistsUpdateCheckedFile()) + { + if (s_NupOnlyMode) + { + s_RestoreState = WAIT_START_DELETE_ACCOUNT; + } + else + { + CheckAccountDeleted(manager, message, goNextStep); + } + } + else + { + // NUPを実行 + if (CheckAndReadAPSetting(message)) + { + if (nn::nwm::CTR::IsWifiOn()) + { + // ネットワークアップデートを行う + s_RestoreState = WAIT_START_UPDATE; + } + else + { + if (!s_WifiStatusOffAnnotation) + { + s_WifiStatusOffAnnotation = true; + common::PlaySound(common::SOUND_ANNOTATION); + } + + message.push_back(::std::string("Wireless is Off\n")); + s_RestoreState = STARTUP; + } + } + } +} + +// インフラからIVS取得済みかチェック +void CheckDownloadIvs(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + NN_UNUSED_VAR(message); + NN_UNUSED_VAR(goNextStep); + + // IVS取得確認ファイルがあるか? + if (common::ExistsDownloadIvsCheckedFile()) + { + if(s_GetIvsOnlyMode) + { + s_RestoreState = DOWNLOAD_IVS_WAIT_NEXT; + } + else + { + CheckWriteFinished(manager, message, goNextStep); + } + } + else + { + COMMON_LOGGER("Download SDCI\n"); + s_RestoreState = DOWNLOAD_IVS; + } + +} + +// アカウント削除済みかチェック +void CheckAccountDeleted(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + // アカウント削除確認ファイルがあるか? + if (common::ExistsDeleteAccountChecked()) + { + CheckAccountTransfered(manager, message, goNextStep); + } + else + { + // 同一本体下記書き戻しの場合はアカウント削除しない + if(EqualsDeviceIdFileandDeviceId(manager).IsSuccess()) + { + // IVS専用モードならばIVSを取得させる + if(s_GetIvsOnlyMode) + { + CheckDownloadIvs(manager, message, goNextStep); + } + else + { + CheckAccountTransfered(manager, message, goNextStep); + } + } + else + { + s_RestoreState = WAIT_START_DELETE_ACCOUNT; + } + } +} + +// アカウント移行済みかチェック +void CheckAccountTransfered(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + // アカウント移行確認ファイルがあるか? + if (common::ExistsTransferAccountChecked()) + { + CheckDownloadIvs(manager, message, goNextStep); + } + else + { + s_RestoreState = WAIT_START_TRANSFER_ACCOUNT; + } +} + +// 書き込み完了かどうかチェック +void CheckWriteFinished(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + NN_UNUSED_VAR(goNextStep); + + // SDカードに書き込み完了ファイルがあるか? + if (common::ExistsWriteFinishedFile()) + { + if (CheckAndReadAPSetting(message)) + { + if (nn::nwm::CTR::IsWifiOn()) + { + // 削除処理を行う + s_RestoreState = WAIT_START_SYNC_CLOCK; + } + else + { + if (!s_WifiStatusOffAnnotation) + { + s_WifiStatusOffAnnotation = true; + common::PlaySound(common::SOUND_ANNOTATION); + } + message.push_back(::std::string("Wireless is Off\n")); + } + } + } + else + { + CheckReadIvs(manager, message, goNextStep); + } +} + +// IVSを読めるかどうかチェック +void CheckReadIvs(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + // IVSを読めるか? + if (manager.CanReadIvs()) + { + CheckConsoleInitialized(manager, message, goNextStep); + } + else + { + s_RestoreState = FAIL; + COMMON_LOGGER("Can't Read SDCI!!"); + } +} + +// 本体初期化済みかどうかチェック +void CheckConsoleInitialized(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + // 本体初期化完了ファイルがあるか? + if (common::ExistsConsoleInitializedFile()) + { + CheckRegioinSd(manager, message, goNextStep); + } + else + { + CheckIvsinSd(manager, message, goNextStep); + } +} + +// シリアルナンバーがあるかどうかチェック +void CheckExistsSerialNumber(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + NN_UNUSED_VAR(manager); + NN_UNUSED_VAR(message); + NN_UNUSED_VAR(goNextStep); + + + // SDカードにシリアルナンバーがあるか? + if (common::ExistsSerialNumberFile()) + { + u8 serial[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN]; + nn::Result result = ReadSerialNumber(serial); + if (result.IsSuccess()) + { + s_RestoreState = WAIT_START_IMPORT; + } + else + { + s_RestoreState = FAIL; + } + } + else + { + COMMON_LOGGER("Can't Read Serial Number in SD Card!!\n"); + s_RestoreState = SERIAL_IS_NOT_IN_SD; + } +} + +// SDカードにIVSがあるかどうかチェック +void CheckIvsinSd(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + NN_UNUSED_VAR(manager); + NN_UNUSED_VAR(message); + NN_UNUSED_VAR(goNextStep); + + if (common::ExistsIVSFile()) + { + s_RestoreState = INITIALIZE_CONSOLE; + } + else + { + // 移行不能なのでFAIL + COMMON_LOGGER("Can't Read SDCI in SD Card!!\n"); + s_RestoreState = FAIL; + } +} + +// SDカードにリージョンデータがあるかどうかチェック +void CheckRegioinSd(common::HardwareStateManager& manager, ::std::vector& message, bool& goNextStep) +{ + NN_UNUSED_VAR(message); + NN_UNUSED_VAR(goNextStep); + + // SDカードにリージョンデータがあるか? + if (common::ExistsRegionData()) + { + // リージョンデータは一致しているか? + if (EqualsRegionDataandRegion().IsFailure()) + { + COMMON_LOGGER("Current Region and Region in SD differ!!\n"); + s_RestoreState = FAIL; + } + else + { + CheckExistsSerialNumber(manager, message, goNextStep); + } + + } + else + { + // 移行不能なのでFAIL + COMMON_LOGGER("Can't Read Region in SD Card!!\n"); + s_RestoreState = FAIL; + } +} + +void ShopOperationSuccess(ShopOperation op, const char* logMessage, RestoreState nextState) +{ + COMMON_LOGGER("%s", logMessage); + if (op == SHOP_OPERATION_UNREGISTER || op == SHOP_OPERATION_FORCE_UNREGISTER) + { + CreateDeleteAccountFinishedFile(); + } + else if (op == SHOP_OPERATION_GET_IVS) + { + CreateTransferAccountFinishedFile(); + CreateDownloadIvsFinishedFile(); + } + + s_RestoreState = nextState; + +} + +void ShopOperationSingleTemplate( + common::HardwareStateManager& manager, + std::vector& message, + ShopOperation op, + const char* aliveMessage, + const char* logMessage, + const char* retryLogMessage, + RestoreState nextState + ) +{ + // ACアダプタが必要か? + if (NeedsAcAdater(manager)) + { + message.push_back(::std::string("Connect AC Adapter!!")); + } + + // アップデートを行う + if (!s_ShopOperationExecuted[op]) + { + if (ImportCountryLanguageData().IsSuccess()) + { + StartShopOperationSingle(op); + s_ShopOperationExecuted[op] = true; + } + else + { + s_RestoreState = FAIL; + } + } + + // 動いていることを表示 + { + PutAliveMessage(message, aliveMessage); + } + + if (IsShopOperationSingleFinished()) + { + FinalizeShopOperationSingle(); + // エラーがあったら表示する + if (GetShopOperationSingleResult().IsSuccess()) + { + ShopOperationSuccess(op, logMessage, nextState); + } + // IVSがアップロードされていない場合もあるため + // IVSを取得できない状況も成功として扱う + // IVSサイズが違う場合も成功として扱う + else if(op == SHOP_OPERATION_GET_IVS && ( GetShopOperationSingleResult() == nn::nim::ResultCannotGetIvs() || + GetShopOperationSingleResult() == nn::nim::ResultInvalidData() + )) + { + ShopOperationSuccess(op, logMessage, nextState); + } + else if(op == SHOP_OPERATION_CONNECT && nextState == TRANSFER_ACCOUNT_DONE && + GetShopOperationSingleResult() == nn::nim::ResultNeedGetIvs()) + + { + NN_LOG("ResultNeedGetIvs\n"); + ShopOperationSuccess(op, logMessage, nextState); + } + else + { + if (GetShopOperationSingleResult().IsFailure()) + { + if (GetShopOperationSingleResult() == nn::ac::ResultFailedConnectAp()) + { + COMMON_LOGGER("Failed Connect AccesPoint."); + nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromSeconds(5)); + } + + + // APが見つからない + if (GetUpdateResult() == nn::ac::ResultNotFoundAccessPoint()) + { + COMMON_LOGGER("No Access Point Found!"); + } + } + + if (s_ShopOperationRetryCount[op]++ < RETRY_MAX) + { + // エラーのためやり直す + COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult()); + COMMON_LOGGER("%s %d\n", retryLogMessage, s_ShopOperationRetryCount[op]); + + // スレッドを作るとこからやり直し + s_ShopOperationExecuted[op] = false; + } + else + { + s_RestoreState = FAIL; + } + } + + } +} + +void UpdateOperation(common::HardwareStateManager& manager, ::std::vector& message, RestoreState nextState) +{ + // ACアダプタが必要か? + if (NeedsAcAdater(manager)) + { + message.push_back(::std::string("Connect AC Adapter!!")); + } + + // アップデートを行う + if (!s_ExecuteFgNup) + { + if (ImportCountryLanguageData().IsSuccess()) + { + StartFGNetworkUpdate(); + s_ExecuteFgNup = true; + } + else + { + s_RestoreState = FAIL; + } + } + + // 動いていることを表示 + { + PutAliveMessage(message, "Updating"); + } + + if (IsNetworkUpdateFinished()) + { + FinishFGNetworkUpdate(); + // エラーがあったら表示する + if (GetUpdateResult().IsFailure()) + { + // APが見つからない + if (GetUpdateResult() == nn::ac::ResultNotFoundAccessPoint()) + { + COMMON_LOGGER("No Access Point Found!"); + } + } + + if (GetUpdateResult().IsSuccess()) + { + COMMON_LOGGER("Network Update Finished.\n"); + if(nextState == UPDATE_DONE) + { + // アップデート完了ファイルを作成 + CreateUpdateFinishedFile(); + } + + s_RestoreState = nextState; + } + else + { + if (s_FgNupRetryCount++ < RETRY_MAX) + { + // エラーのためやり直す + COMMON_LOGGER_RESULT_IF_FAILED(GetUpdateResult()); + COMMON_LOGGER("Network Update Failed. Retrying... %d\n", s_FgNupRetryCount); + + // FGNUP用のスレッドを作るとこからやり直し + s_ExecuteFgNup = false; + } + else + { + s_RestoreState = FAIL; + } + } + + } +} + +bool CheckAndReadAPSetting(::std::vector& operationMessage) +{ + using namespace common; + + if (!ExistsAPSetting()) + { + if(!s_ExistAPSettingAnnotation) + { + s_ExistAPSettingAnnotation = true; + common::PlaySound(common::SOUND_ANNOTATION); + } + operationMessage.push_back(::std::string("Accsess_Point_Setting does not exist!")); + return false; + } + + // 設定ファイルからAP設定を読み込む + if (!s_ReadSettingDone) + { + s_ReadSettingDone = true; + s_ReadSettingIsSuccess = ReadSetting(&s_NupOnlyMode, &s_GetIvsOnlyMode, &s_CheckSdOnlyMode, &s_SkipNupMode); + } + + if (s_NupOnlyMode && s_GetIvsOnlyMode + || s_GetIvsOnlyMode && s_CheckSdOnlyMode + || s_CheckSdOnlyMode && s_NupOnlyMode) + { + operationMessage.push_back("Only one special mode setting is valid!!"); + s_ReadSettingIsSuccess = false; + } + else if(s_NupOnlyMode && s_SkipNupMode) + { + operationMessage.push_back("Both NUP_ONLY and SKIP_NUP are described!!"); + s_ReadSettingIsSuccess = false; + } + else + { + if (s_NupOnlyMode) + { + s_RestoreMode = RESTORE_MODE_NUP_ONLY; + } + + if (s_GetIvsOnlyMode) + { + s_RestoreMode = RESTORE_MODE_GET_IVS; + } + + if(s_CheckSdOnlyMode) + { + s_RestoreMode = RESTORE_MODE_CHECK_SD; + } + } + + if (!s_ReadSettingIsSuccess) + { + operationMessage.push_back(::std::string("Invalid Accsess_Point_Setting format!")); + if(!s_APSettingAnnotation) + { + s_APSettingAnnotation = true; + common::PlaySound(common::SOUND_ANNOTATION); + } + } + + return s_ReadSettingIsSuccess; +} + +void PutAliveMessage(::std::vector& 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; +} + +nn::Result ExecSyncMcuRtc(common::HardwareStateManager& manager) +{ + nn::Result result = nn::ResultSuccess(); + if(!common::ExistsRtcSyncFinishedFile()) + { + result = ImportMcuRtc(manager); + if(result.IsSuccess()) + { + // RTCを同期完了ファイルを作る + CreateRtcSyncFinishedFile(); + } + } + + return result; +} + +} // namespace + +void ControlState(common::HardwareStateManager& manager, ::std::vector& operationMessage, bool& nextStep) +{ + using namespace common; + nn::Result result; + + // 状態遷移Controller + switch (s_RestoreState) + { + // 起動時 + case STARTUP: + { + CheckSdInserted(manager, operationMessage, nextStep); + } + break; + + + case INITIALIZE_CONSOLE: + { + COMMON_LOGGER("Initialize Console\n"); + + // 本体初期化完了ファイルを作る + CreateConsoleInitializedFile(); + + // ファイルシステムの初期化を行う + if(InitializeFileSystem()) + { + s_RestoreState = REBOOTING; + } + else + { + s_RestoreState = FAIL; + } + + } + break; + + case WAIT_START_UPDATE: + { + operationMessage.push_back(::std::string("Push A or START Button")); + operationMessage.push_back(::std::string("Network Update Mode")); + if (!s_PlayedStartCursor) + { + PlaySound(SOUND_CURSOR); + s_PlayedStartCursor = true; + } + + if (nextStep) + { + COMMON_LOGGER("Start Network Update\n"); + // インポートコンテキストの削除 + nn::am::DeleteAllImportContexts(nn::fs::MEDIA_TYPE_NAND); + s_RestoreState = UPDATE_IN_PROGRESS; + } + } + break; + + case WAIT_START_IMPORT: + { + u8 serial[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN]; + result = ReadSerialNumber(serial); + if (result.IsSuccess()) + { + ::std::string serialStr(reinterpret_cast (serial)); + operationMessage.push_back(::std::string("Serial Number in SD : ") + serialStr); + } + else + { + s_RestoreState = FAIL; + } + + operationMessage.push_back(::std::string("Push A or START Button")); + operationMessage.push_back(::std::string("Import Data Mode")); + if (!s_PlayedStartCursor) + { + PlaySound(SOUND_CURSOR); + s_PlayedStartCursor = true; + } + + if (nextStep) + { + s_RestoreState = READ_FILELIST; + } + } + break; + + case WAIT_START_SYNC_CLOCK: + { + operationMessage.push_back(::std::string("Push A or START Button")); + operationMessage.push_back(::std::string("DownLoad Twl Title and Clock Sync Mode")); + if (!s_PlayedStartCursor) + { + PlaySound(SOUND_CURSOR); + s_PlayedStartCursor = true; + } + + if (nextStep) + { + COMMON_LOGGER("Erase Trash\n"); + s_RestoreState = ERASE; + } + } + break; + + case IMPORT_RTC: + { + result = nn::ResultSuccess(); + if (HasValidRtcData()) + { + result = ExecSyncMcuRtc(manager); + if (result <= nn::fs::ResultVerificationFailed()) + { + s_RestoreState = FAIL; + } + else + { + if (s_SkipNupMode) + { + CheckAccountTransfered(manager, operationMessage, nextStep); + } + else + { + CheckNupExecuted(manager, operationMessage, nextStep); + } + } + } + else + { + if (s_CheckSdOnlyMode) + { + s_RestoreState = CHECK_IVS; + } + else + { + CheckNupExecuted(manager, operationMessage, nextStep); + } + } + } + break; + + // シリアルナンバーがSDカードにないこと警告 + case SERIAL_IS_NOT_IN_SD: + { + operationMessage.push_back(::std::string("Serial Number Is Not In SD Card")); + operationMessage.push_back(::std::string("Push A or START Button")); + operationMessage.push_back(::std::string("Import Data Mode")); + + if (!s_SerialNumberAnnotation) + { + s_SerialNumberAnnotation = true; + PlaySound(SOUND_ANNOTATION); + } + + if (nextStep) + { + s_RestoreState = READ_FILELIST; + } + } + break; + + // アップデート中 + case UPDATE_IN_PROGRESS: + { + UpdateOperation(manager, operationMessage, UPDATE_DONE); + } + break; + + // アップデート完了 + case UPDATE_DONE: + { + operationMessage.push_back(::std::string("Network Update Done.")); + operationMessage.push_back(::std::string("Press A or START Button to Reboot")); + + if (!s_PlayedRebootCursor) + { + PlaySound(SOUND_CURSOR); + s_PlayedRebootCursor = true; + } + + if (nextStep) + { + s_RestoreState = REBOOTING; + } + } + break; + + case DOWNLOAD_IVS: + { + ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_GET_IVS, "Get SDCI", + "Get SDCI Finished.\n", "Get SDCI Failed. Retrying...", DOWNLOAD_IVS_DONE); + } + break; + + + case DOWNLOAD_IVS_DONE: + { + operationMessage.push_back(::std::string("Get SDCI Done.")); + operationMessage.push_back(::std::string("Press A or START Button to Reboot")); + + if (!s_PlayedRebootCursor) + { + PlaySound(SOUND_CURSOR); + s_PlayedRebootCursor = true; + } + + if (nextStep) + { + s_RestoreState = REBOOTING; + } + } + break; + + case CHECK_IVS: + { + operationMessage.push_back(::std::string("Insert User's SD Card")); + } + break; + + case CHECK_SD_DIRECTORY: + { + if (nn::fs::IsSdmcInserted()) + { + NN_LOG("Check User's SD Card\n"); + // ユーザのSDカードにはAP設定ファイルは無いはず + if (ExistsAPSetting()) + { + NN_LOG("AP Setting Exists. Retry\n"); + s_RestoreState = CHECK_IVS; + } + else + { + NN_LOG("Read User's SD Card\n"); + std::string sysSaveRoot; + common::Util::GetSaveDataDirectoryRoot(sysSaveRoot); + if (ExistsIvsDirectory(sysSaveRoot)) + { + s_RestoreState = CHECK_SD_DIRECTORY_SUCCESS; + } + else + { + s_RestoreState = CHECK_SD_DIRECTORY_FAIL; + } + } + } + } + break; + + case CHECK_SD_DIRECTORY_SUCCESS: + { + operationMessage.push_back(::std::string("Check User's SD Card Succeeded.")); + operationMessage.push_back(::std::string("Pull Out SD Card")); + } + break; + + case CHECK_SD_DIRECTORY_FAIL: + { + operationMessage.push_back(::std::string("Check User's SD Card Failed.")); + operationMessage.push_back(::std::string("Pull Out SD Card")); + } + break; + + case WAIT_START_TRANSFER_ACCOUNT: + { + if(s_SkipNupMode) + { + operationMessage.push_back(::std::string("After Operating BMS Account Transfer,")); + } + + operationMessage.push_back(::std::string("Push A or START Button")); + operationMessage.push_back(::std::string("Transfer Account Mode")); + if (!s_PlayedStartCursor) + { + PlaySound(SOUND_CURSOR); + s_PlayedStartCursor = true; + } + + if (nextStep) + { + COMMON_LOGGER("Transfer Account\n"); + s_RestoreState = TRANSFER_ACCOUNT; + } + } + break; + + case TRANSFER_ACCOUNT: + { + ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_GET_IVS, "Transfer Account", + "Transfer Account Finished.\n", "Transfer Account Failed. Retrying...", DOWNLOAD_IVS_DONE); + } + break; + + case WAIT_START_DELETE_ACCOUNT: + { + operationMessage.push_back(::std::string("Push A or START Button")); + operationMessage.push_back(::std::string("Delete Account Mode")); + if (!s_PlayedStartCursor) + { + PlaySound(SOUND_CURSOR); + s_PlayedStartCursor = true; + } + + if (nextStep) + { + COMMON_LOGGER("Delete Account\n"); + s_RestoreState = DELETE_ACCOUNT; + } + } + break; + + case DELETE_ACCOUNT: + { + if(s_NupOnlyMode) + { + ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_FORCE_UNREGISTER, "Deleting Account", + "Delete Account Finished.\n", "Delete Account Failed. Retrying...", DELETE_ACCOUNT_DONE); + + } + else + { + ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_UNREGISTER, "Deleting Account", + "Delete Account Finished.\n", "Delete Account Failed. Retrying...", DELETE_ACCOUNT_DONE); + } + } + break; + + case DELETE_ACCOUNT_DONE: + { + if(s_NupOnlyMode) + { + s_RestoreState = NUP_ONLY_WAIT_SD_EJECT; + + // リストア状態チェックファイルをすべて削除 + DeleteAllCheckFiles(); + } + else + { + operationMessage.push_back(::std::string("Delete Account Done.")); + operationMessage.push_back(::std::string("Operate BMS.")); + operationMessage.push_back(::std::string("")); + operationMessage.push_back(::std::string("Press A or START Button to Continue")); + + if (!s_PlayedRebootCursor) + { + PlaySound(SOUND_CURSOR); + s_PlayedRebootCursor = true; + } + + if (nextStep) + { + s_RestoreState = STARTUP; + } + } + } + break; + + case READ_FILELIST: + { + result = SetupVersionAndFileList(); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + if (result.IsSuccess()) + { + if (s_IsSyncClock) + { + s_RestoreState = RESTORE_TWL_NAND; + } + else + { + s_RestoreState = RESTORE_TWL_SOUND; + } + + } + else + { + s_RestoreState = FAIL; + } + } + break; + + // TWLサウンド領域の書き込み中 + case RESTORE_TWL_SOUND: + { + static bool init = true; + if (init) + { + // データを書き込む + ImportTwlSoundData(); + init = false; + } + + PutAliveMessage(operationMessage, "Importing TWL Sound Data"); + + // 処理が完了した + if (IsImportThreadFinished()) + { + FinalizeImportThread(); + if(IsImportSucceeded()) + { + s_RestoreState = RESTORE_TWL_PHOTO; + } + else + { + s_RestoreState = FAIL; + } + + } + } + break; + + // TWL写真領域の書き込み + case RESTORE_TWL_PHOTO: + { + static bool init = true; + if (init) + { + // データを書き込む + ImportTwlPhotoData(); + init = false; + } + + PutAliveMessage(operationMessage, "Importing TWL Photo Data"); + + // 処理が完了した + if (IsImportThreadFinished()) + { + FinalizeImportThread(); + if(IsImportSucceeded()) + { + s_RestoreState = RESTORE_IN_PROGRESS; + } + else + { + s_RestoreState = FAIL; + } + + } + } + break; + + // 書き込み中 + case RESTORE_IN_PROGRESS: + { + // ACアダプタが必要か? + if (NeedsAcAdater(manager)) + { + operationMessage.push_back(::std::string("Connect AC Adapter!!")); + } + + // データを読み込む + if (ImportData().IsFailure()) + { + s_RestoreState = FAIL; + } + else + { + PutAliveMessage(operationMessage, "Importing Nand Data"); + + // 処理が完了した + if (!NeedsAcAdater(manager) && IsImportThreadFinished()) + { + if (IsImportSucceeded()) + { + + COMMON_LOGGER("Import NAND Data Finished.\n"); + + if (GetProgress() > 99) + { + s_RestoreState = POST_RESTORE; + } + else + { + s_RestoreState = FAIL; + } + } + else + { + s_RestoreState = FAIL; + } + } + } + } + break; + + // リブート中 + case REBOOTING: + { + static bool init = true; + + if (init) + { + // ErrDispから引用 + result = nn::ns::CTR::InitializeForShell(); + if (result.IsSuccess()) + { + COMMON_LOGGER("System Reboot.\n"); + + nn::ns::CTR::HardwareResetAsync(nn::CTR::MEMORY_ARRANGE_NORMAL); + while (!nn::applet::IsExpectedToCloseApplication()) + { + nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(5)); + } + + nn::ns::CTR::FinalizeForShell(); + + // INFO: リブートは非同期のため処理は継続 + } + init = false; + } + } + break; + + // 書き込み後の処理 + case POST_RESTORE: + { + operationMessage.push_back(::std::string("Post Process...")); + + // SDカードのIVSファイルを書き込む + if(ImportIvsData()) + { + // 書き込み完了ファイルを作成 + CreateWriteFinishedFile(); + + s_RestoreState = RESTORE_DONE; + } + else + { + s_RestoreState = FAIL; + } + } + break; + + // 書き込み完了 + case RESTORE_DONE: + { + operationMessage.push_back(::std::string("Restore Done.")); + operationMessage.push_back(::std::string("Press A or START Button to Reboot")); + + if (!s_PlayedRebootCursor) + { + PlaySound(SOUND_CURSOR); + s_PlayedRebootCursor = true; + } + + if (nextStep) + { + s_RestoreState = REBOOTING; + } + } + break; + + // 削除処理 + case ERASE: + { + Cleanup(); + s_RestoreState = RESTORE_CAL; + } + break; + + // 削除処理 + case RESTORE_CAL: + { + // ptmのセーブデータ移行後に時計を無効化する + nn::ptm::CTR::InvalidateSystemTime(); + + // cfgの本体固有値をcal値で初期化する + result = InitializeHardwareDependentSetting(); + if (result.IsFailure()) + { + s_RestoreState = FAIL; + } + + COMMON_LOGGER("Sync eTicket\n"); + s_RestoreState = SYNC_TICKET; + } + break; + + case SYNC_TICKET: + { + if(s_GetIvsOnlyMode) + { + ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_CONNECT, "Shop Connect", + "Shop Connect Finished.\n", "Shop Connect Failed. Retrying...", WAIT_SD_EJECT); + } + else + { + ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_CONNECT, "Shop Connect", + "Shop Connect Finished.\n", "Shop Connect Failed. Retrying...", DOWNLOAD_TWL); + } + } + break; + + case DOWNLOAD_TWL: + { + // ファイルリストがなければ次へ + if( !ExistsTwlTitleListFile()) + { + s_IsSyncClock = true; + s_RestoreState = READ_FILELIST; + } + else + { + if (!s_ExecuteTitleDownload) + { + COMMON_LOGGER("Download Twl Title\n"); + s_ExecuteTitleDownload = true; + StartTitleDownload(); + } + + // 動いていることを表示 + { + PutAliveMessage(operationMessage, "Download Twl Title"); + } + + if (IsDownloadTitleFinished()) + { + FinalizeTitleDownload(); + if (DownloadTitleSucceeded()) + { + s_IsSyncClock = true; + s_RestoreState = READ_FILELIST; + } + else + { + if (s_TitleDownloadRetryCount++ < RETRY_MAX) + { + // エラーのためやり直す + COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult()); + COMMON_LOGGER("Download Twl Title Failed. Retrying... %d\n", s_TitleDownloadRetryCount); + + s_ExecuteTitleDownload = false; + } + else + { + s_RestoreState = FAIL; + } + } + } + } + } + break; + + // TWL NAND領域の書き込み中 + case RESTORE_TWL_NAND: + { + static bool init = true; + if (init) + { + // データを書き込む + ImportTwlSaveData(); + init = false; + } + + PutAliveMessage(operationMessage, "Importing TWL SaveData"); + + // 処理が完了した + if (IsImportThreadFinished()) + { + FinalizeImportThread(); + s_RestoreState = TIME_ADJUST; + } + } + break; + + // 時計あわせ + case TIME_ADJUST: + { + static bool init = true; + if (init) + { + COMMON_LOGGER("Adjust Time\n"); + AdjustTime(); + init = false; + } + + // 動いていることを表示 + { + PutAliveMessage(operationMessage, "Sync Clock"); + } + + if (IsTimeAdjustFinished()) + { + if (IsTimeAdjustSuccessed()) + { + s_RestoreState = WAIT_SD_EJECT; + } + else + { + s_RestoreState = FAIL; + } + + // リストア状態チェックファイルをすべて削除 + DeleteAllCheckFiles(); + } + } + break; + + // すべて完了 + case WAIT_SD_EJECT: + { + operationMessage.push_back(::std::string("ALL Done. Pull Out SD Card.")); + // SDカード抜けのみで次の状態に遷移する + + if (!s_PlayedSdPullOutCursor) + { + common::PlaySound(common::SOUND_CURSOR); + s_PlayedSdPullOutCursor = true; + } + + } + break; + + // すべて完了 + case ALL_DONE: + { + operationMessage.push_back(::std::string("Restore Succeeded!!")); + static bool init = true; + if (init) + { + PlaySound(SOUND_OK); + init = false; + } + } + break; + + // 書き込み失敗 + case FAIL: + { + static bool init = true; + if (init) + { + // 状態初期化 + DeleteAllCheckFiles(); + init = false; + } + + operationMessage.push_back(::std::string("Failed.")); + if (!s_PlayedFailSound) + { + PlaySound(SOUND_NG); + s_PlayedFailSound = true; + } + } + break; + + case NUP_ONLY_WAIT_SD_EJECT: + { + operationMessage.push_back(::std::string("Update Done. Pull Out SD Card.")); + + // SDカード抜けのみで次の状態に遷移する + if (!s_PlayedSdPullOutCursor) + { + common::PlaySound(common::SOUND_CURSOR); + s_PlayedSdPullOutCursor = true; + } + } + break; + + case DOWNLOAD_IVS_WAIT_NEXT: + { + operationMessage.push_back(::std::string("Press A or START Button to Continue.")); + if(nextStep) + { + s_RestoreState = SYNC_TICKET; + DeleteAllCheckFiles(); + } + } + break; + + case NUP_ONLY_WAIT_NEXT: + { + operationMessage.push_back(::std::string("Press A or START Button to Shutdown.")); + + if (nextStep) + { + s_RestoreState = INITIALIZE_AND_SHUTDOWN; + } + } + break; + + case INITIALIZE_AND_SHUTDOWN: + { + // 本体初期化を行う + if(!InitializeFileSystem()) + { + s_RestoreState = FAIL; + } + + // シャットダウンする + nn::ptm::CTR::ShutdownAsync(0, nn::fnd::TimeSpan::FromSeconds(0)); + } + break; + + } +} + +bool InProgress() +{ + return s_RestoreState == RESTORE_IN_PROGRESS; +} + +bool IsRestoreSucceeded() +{ + return s_RestoreState == ALL_DONE; +} + +bool IsRestoreFailed() +{ + return s_RestoreState == FAIL; +} + +void OnSdEjected() +{ + if (s_RestoreState == WAIT_SD_EJECT || s_RestoreState == ALL_DONE || s_RestoreState == CHECK_SD_DIRECTORY_SUCCESS) + { + s_RestoreState = ALL_DONE; + } + else if (s_RestoreState == NUP_ONLY_WAIT_SD_EJECT || s_RestoreState == NUP_ONLY_WAIT_NEXT) + { + s_RestoreState = NUP_ONLY_WAIT_NEXT; + } + // ユーザのSDが抜かれてからFAILにする + else if (s_RestoreState == CHECK_SD_DIRECTORY_FAIL) + { + s_RestoreState = FAIL; + } + // FAILのときは一旦電源を切らないと動かないようにしておく + // IVSチェック時はユーザのSDカードを挿入してもらうため + else if (s_RestoreState != FAIL && s_RestoreState != CHECK_IVS) + { + InitializeState(); + ClearFileReadResult(); + } +} + +void OnSdInserted() +{ + if(s_RestoreState == CHECK_IVS) + { + // SDカードが変わるのでファイルチェックは初期化する + common::InitializeFileCheck(); + s_RestoreState = CHECK_SD_DIRECTORY; + } +} + +void InitializeState() +{ + s_RestoreState = STARTUP; + s_RestoreMode = RESTORE_MODE_RESTORE; + + for(u32 i = 0; i < SHOP_OPERATION_NUM_MAX; i++) + { + s_ShopOperationExecuted[i] = false; + s_ShopOperationRetryCount[i] = 0; + } + + common::InitializeFileCheck(); + + s_ExistAPSettingAnnotation = false; + s_ReadSettingDone = false; + s_ReadSettingIsSuccess = false; + s_APSettingAnnotation = false; + s_SerialNumberAnnotation = false; + s_PlayedFailSound = false; + s_ExecuteFgNup = false; + s_FgNupRetryCount = 0; + s_PlayedStartCursor = false; + s_PlayedRebootCursor = false; + s_PlayedSdPullOutCursor = false; + s_NupOnlyMode = false; + s_GetIvsOnlyMode = false; + s_SdWriteProetctAnnotation = false; + s_WifiStatusOffAnnotation = false; + s_CheckSdOnlyMode = false; + s_SkipNupMode = false; +} + +u32 GetProgress() +{ + if(s_RestoreState == RESTORE_TWL_SOUND || + s_RestoreState == RESTORE_TWL_PHOTO || + s_RestoreState == RESTORE_TWL_NAND || + s_RestoreState == RESTORE_IN_PROGRESS || + s_RestoreState == POST_RESTORE || + s_RestoreState == RESTORE_DONE) + { + return GetImportProgress(); + } + else if(s_RestoreState == UPDATE_IN_PROGRESS || + s_RestoreState == UPDATE_DONE) + { + return GetUpdateProgress(); + } + else if(s_RestoreState == DOWNLOAD_TWL) + { + return GetTitleDownloadProgress(); + } + else + { + return 0; + } + +} + +RestoreMode GetRestoreMode() +{ + return s_RestoreMode; +} + +} // namespace ConsoleRestore diff --git a/branches/2-1-1/sources/ConsoleRestore/Controller.h b/branches/2-1-1/sources/ConsoleRestore/Controller.h new file mode 100644 index 0000000..bc8400b --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/Controller.h @@ -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 +#include +#include +#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& operationMessage, bool& nextStep); + +// リストア処理中かどうか +bool InProgress(); + +// リストアが完了したかどうか +bool IsRestoreSucceeded(); + +// リストアが失敗したかどうか +bool IsRestoreFailed(); + +// 書き込みスレッドの進捗を返す +u32 GetProgress(); + + +// SDカードが抜き出されたときに実行したい関数 +void OnSdEjected(); + +// SDカードが挿入されたときに実行したい関数 +void OnSdInserted(); + +// 状態を初期化する +void InitializeState(); + +// リストア状態を取得する +RestoreMode GetRestoreMode(); + +} + +#endif /* CONTOROLLER_H_ */ diff --git a/branches/2-1-1/sources/ConsoleRestore/Importer.cpp b/branches/2-1-1/sources/ConsoleRestore/Importer.cpp new file mode 100644 index 0000000..d6b9a20 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/Importer.cpp @@ -0,0 +1,1976 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: Importer.cpp + + Copyright 2009 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Rev$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include // cfg:norの初期化に必要 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FileName.h" +#include "Importer.h" +#include "SdMountManager.h" +#include "HeapManager.h" +#include "SdReaderWriter.h" +#include "CommonLogger.h" +#include "FileTransfer.h" +#include "common_Types.h" +#include "Aes_define.h" +#include "configLoader.h" +#include "FileChecker.h" +#include "VersionDetect.h" +#include "SaveDataMover.h" + +#include +#include + +namespace ConsoleRestore +{ +namespace +{ +const size_t IMPORT_THREAD_STACK_SIZE = 0x4000; +nn::os::Thread s_ImportThread; +nn::os::StackBuffer s_ImportThreadStack; +bool s_IsImportSucceeded; + +const size_t TIME_ZONE_LENGTH = 9; // "+23:45" +char s_TimeZoneStr[TIME_ZONE_LENGTH]; + +TimeZone s_TimeZone; +const size_t NTP_SERVER_NAME_LENGTH = 256; +char s_NtpServerName[NTP_SERVER_NAME_LENGTH]; + +bool s_CheckedEqualsDeviceIdFileandDeviceId = false; +bool s_CheckedEqualsRegionDataandRegion = false; +bool s_ReadSerialNumber = false; + +struct SdFileSize +{ + s64 totalFileSize; + s64 twlFileSize; + s64 twlSoundFileSize; + s64 twlPhotoFileSize; + s64 ctrFileSize; +}; + +SdFileSize s_SdFileSize; + +// シリアルナンバー +u8 s_SerialNo[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN]; + +// 空のファイルを作成する +bool CreateEmptyFile(const wchar_t* path); +// SDからNANDにセーブデータをコピーする +void ImportSaveData(); +// SDからNORにNORデータをコピーする +nn::Result ImportNorData(); + +// SDカードに保存してあるバージョン情報 +common::VerDef s_SDVersionData; + +// SDカードから読み込んだファイル一覧 +common::ImportDataList s_FileLists; + +u64 s_ImportProgress = 0; + +} + +// SDからファイル一覧を読み込む +nn::Result ReadFileList(SdFileSize* sdFileSize, common::ImportDataList* fileList); + +bool RequiresImportApi(); + +CheckedNetworkSetting s_CurrentNetowrkSetting1; + +void ConvertTimeZoneString(const char* str) +{ + s_TimeZone.hour = 0; + s_TimeZone.minutes = 0; + s_TimeZone.isMinus = false; + + bool hour = true; + bool ten = true; + u32 count = 0; + for(u32 i = 0; i < TIME_ZONE_LENGTH && count < 2; i++) + { + switch (str[i]) + { + case ':': + { + hour = false; + } + break; + + case '"': + { + // 2回読んだら終了 + count++; + } + break; + + case '+': + { + s_TimeZone.isMinus = false; + } + break; + + case '-': + { + s_TimeZone.isMinus = true; + } + break; + + default: + { + if(hour) + { + if(ten) + { + s_TimeZone.hour += (str[i] - '0') * 10; + ten = false; + } + else + { + s_TimeZone.hour += str[i] - '0'; + ten = true; + } + } + else + { + if(ten) + { + s_TimeZone.minutes += (str[i] - '0') * 10; + ten = false; + } + else + { + s_TimeZone.minutes += str[i] - '0'; + ten = true; + } + } + } + break; + } + } + + + NN_LOG("Converted TimeZone = "); + if(s_TimeZone.isMinus) + { + NN_LOG("-"); + } + NN_LOG("%02d:%02d\n", s_TimeZone.hour, s_TimeZone.minutes); + +} + +namespace +{ + +bool CreateEmptyFile(const wchar_t* path) +{ + nn::Result result; + bool create = false; + result = common::SdMountManager::Mount(); + + if (result.IsSuccess()) + { + nn::fs::FileOutputStream fos; + + result = fos.TryInitialize(path, true); + if(result.IsSuccess()) + { + fos.TryFlush(); + create = true; + } + fos.Finalize(); + } + + common::SdMountManager::Unmount(); + + return create; +} + +} + +nn::Result ReadSerialNumber(u8* serial) +{ + static nn::Result result = nn::ResultSuccess(); + + if(s_ReadSerialNumber) + { + std::memcpy(serial, s_SerialNo, sizeof(s_SerialNo)); + return result; + } + + COMMON_LOGGER("Read Serial Number in SD.\n"); + + size_t readSize; + common::SdReaderWriter sdReader; + size_t bufSize = 1024; + common::HeapManager readHeap(bufSize); + void* buf = readHeap.GetAddr(); + if(buf != NULL) + { + result = sdReader.ReadBufWithCmac(common::SERIAL_PATHNAME, buf, bufSize, &readSize); + if(result.IsSuccess()) + { + std::memcpy(s_SerialNo, buf, sizeof(s_SerialNo)); + std::memcpy(serial, s_SerialNo, sizeof(s_SerialNo)); + s_ReadSerialNumber = true; + } + } + else + { + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + return result; +} + +nn::Result EqualsDeviceIdFileandDeviceId(common::HardwareStateManager& manager) +{ + static nn::Result result = nn::ResultSuccess(); + + if(s_CheckedEqualsDeviceIdFileandDeviceId) + { + return result; + } + + COMMON_LOGGER("Check Device Id\n"); + + bit32 sdDeviceId; + common::SdReaderWriter sdReader; + size_t totalSize; + size_t bufSize = 1024; + common::HeapManager heap(bufSize); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + result = sdReader.ReadBufWithCmac(common::DEVICE_ID_PATHNAME, buf, bufSize, &totalSize); + if (result.IsSuccess()) + { + s_CheckedEqualsDeviceIdFileandDeviceId = true; + std::memcpy(&sdDeviceId, buf, sizeof(sdDeviceId)); + + if (manager.GetDeviceId() == sdDeviceId) + { + result = nn::ResultSuccess(); + } + else + { + result = nn::Result(nn::Result::LEVEL_STATUS, nn::Result::SUMMARY_INVALID_RESULT_VALUE, + nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_INVALID_RESULT_VALUE); + } + } + } + else + { + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + + return result; +} + +nn::Result EqualsRegionDataandRegion() +{ + static nn::Result result = nn::ResultSuccess(); + + if(s_CheckedEqualsRegionDataandRegion) + { + return result; + } + + COMMON_LOGGER("Check Region\n"); + + nn::cfg::CTR::CfgRegionCode region; + region = nn::cfg::CTR::GetRegion(); + + nn::cfg::CTR::CfgRegionCode sdRegion; + common::SdReaderWriter sdReader; + size_t readSize; + size_t bufSize = 1024; + common::HeapManager heap(bufSize); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + result = sdReader.ReadBufWithCmac(common::REGION_DATA_PATHNAME, buf, bufSize, &readSize); + if (result.IsSuccess()) + { + std::memcpy(&sdRegion, buf, sizeof(sdRegion)); + s_CheckedEqualsRegionDataandRegion = true; + if(region == sdRegion) + { + result = nn::ResultSuccess(); + } + else + { + result = nn::Result(nn::Result::LEVEL_STATUS, nn::Result::SUMMARY_INVALID_RESULT_VALUE, + nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_INVALID_RESULT_VALUE); + } + } + } + else + { + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + + return result; +} + +void SetCountry(nn::cfg::CTR::CfgCountryCode countryCode) +{ + using namespace nn::cfg::CTR; + using namespace nn::cfg::CTR::detail; + + SimpleAddressIdCfgData simpleAddressId; + TwlCountryCodeCfgData countryData; + + nn::cfg::CTR::system::Initialize(); + + NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::GetConfig(&simpleAddressId, sizeof(SimpleAddressIdCfgData), GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID))); + NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::GetConfig(&countryData, sizeof(TwlCountryCodeCfgData), GET_CFG_KEY(NN_CFG_TWL, NN_CFG_TWL_COUNTRY_CODE))); + nn::cfg::CTR::system::Finalize(); + + simpleAddressId.id = (countryCode << CFG_SIMPLE_ADDRESS_ID_COUNTRY_SHIFT) | (1 + << CFG_SIMPLE_ADDRESS_ID_REGION_SHIFT); + countryData.country = countryCode; + + nn::cfg::CTR::system::Initialize(); + NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::SetConfig(GET_CFG_KEY(NN_CFG_SIMPLE_ADDRESS, NN_CFG_SIMPLE_ADDRESS_ID), &simpleAddressId, sizeof(SimpleAddressIdCfgData))); + NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::system::SetConfig(GET_CFG_KEY(NN_CFG_TWL, NN_CFG_TWL_COUNTRY_CODE), &countryData, sizeof(TwlCountryCodeCfgData))); + nn::cfg::CTR::system::FlushConfig(); + nn::cfg::CTR::system::Finalize(); +} + +void SetLanguage(nn::cfg::CTR::CfgLanguageCode languageCode) +{ + NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::init::SetConfig( + GET_CFG_KEY(nn::cfg::CTR::detail::NN_CFG_USER_INFO, + nn::cfg::CTR::detail::NN_CFG_USER_INFO_LANGUAGE), + &languageCode, + sizeof(nn::cfg::CTR::detail::LanguageCfgData))); + NN_UTIL_PANIC_IF_FAILED(nn::cfg::CTR::init::FlushConfig()); + nn::cfg::nor::CTR::Initialize(); + NN_UTIL_PANIC_IF_FAILED(nn::cfg::nor::CTR::SetLanguage(static_cast(languageCode))); + nn::cfg::nor::CTR::Finalize(); +} + +nn::Result ImportCountryLanguageData() +{ + nn::Result result = nn::ResultSuccess(); + + // 設定済みなら何もしない + if(nn::cfg::CTR::GetCountry() != nn::cfg::CTR::CFG_COUNTRY_UNKNOWN) + { + return result; + } + + if (common::ExistsCountryLanguageFile()) + { + size_t bufSize = 1024; + common::HeapManager heap(bufSize); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + common::SdReaderWriter sdReader; + + size_t readSize; + result = sdReader.ReadBufWithCmac(common::COUNTRY_SETTING_PATHNAME, buf, bufSize, &readSize); + if (result.IsSuccess()) + { + // SDから読み出し成功 + SetCountry(reinterpret_cast (buf)->country); + + SetLanguage(reinterpret_cast (buf)->language); + } + + NN_UTIL_RETURN_IF_FAILED(result); + } + } + else + { + // リージョンから適当な国を指定する + nn::cfg::CTR::CfgRegionCode region; + region = nn::cfg::CTR::GetRegion(); + NN_LOG("Country Setting does not exist. Use Default Setting\n"); + switch(region) + { + case nn::cfg::CTR::CFG_REGION_JAPAN: + { + SetCountry(nn::cfg::CTR::CFG_COUNTRY_JAPAN); + } + break; + + case nn::cfg::CTR::CFG_REGION_AMERICA: + { + SetCountry(nn::cfg::CTR::CFG_COUNTRY_UNITED_STATES); + } + break; + + case nn::cfg::CTR::CFG_REGION_EUROPE: + { + SetCountry(nn::cfg::CTR::CFG_COUNTRY_FRANCE); + } + break; + + case nn::cfg::CTR::CFG_REGION_AUSTRALIA: + { + SetCountry(nn::cfg::CTR::CFG_COUNTRY_AUSTRALIA); + } + break; + + case nn::cfg::CTR::CFG_REGION_CHINA: + { + SetCountry(nn::cfg::CTR::CFG_COUNTRY_CHINA); + } + break; + + case nn::cfg::CTR::CFG_REGION_KOREA: + { + SetCountry(nn::cfg::CTR::CFG_COUNTRY_SOUTH_KOREA); + } + break; + + case nn::cfg::CTR::CFG_REGION_TAIWAN: + { + SetCountry(nn::cfg::CTR::CFG_COUNTRY_TAIWAN); + } + break; + } + + } + + return result; +} + +inline u8 DecimalToBcd(u8 param) +{ + u8 theTen, theOne; + theTen = param / 10; + theOne = param - theTen * 10; + return (theTen << 4 | theOne); +} + +nn::Result ImportMcuRtc(common::HardwareStateManager& manager) +{ + COMMON_LOGGER("Import RTC Data.\n"); + nn::Result result = nn::ResultSuccess(); + nn::Handle handle = manager.GetMcuHandle(); + + if(handle.IsValid()) + { + if (common::CheckFileExists(common::MCU_RTC_PATHNAME)) + { + size_t bufSize = 1024; + NN_LOG("AllocatableSize = %d\n", bufSize); + + common::HeapManager heap(bufSize); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + common::SdReaderWriter sdReader; + + size_t readSize; + result = sdReader.ReadBufWithCmac(common::MCU_RTC_PATHNAME, buf, bufSize, &readSize); + if (result.IsSuccess()) + { + // mcuを使ってセットする + nn::mcu::CTR::HwCheck mcu(handle); + nn::mcu::CTR::RtcData* rtc = reinterpret_cast (buf); + NN_LOG("RTC = 20%02d/%02d/%02d %02d:%02d:%02d\n", rtc->m_Year, rtc->m_Month, rtc->m_Day, rtc->m_Hour, rtc->m_Minute, rtc->m_Second); + + // BCD変換が必要 + + size_t RTC_PARAM_SIZE = sizeof(nn::mcu::CTR::RtcData); + u8 bcd[RTC_PARAM_SIZE]; + for (int i = 0; i < RTC_PARAM_SIZE; i++) + { + bcd[i] = DecimalToBcd(reinterpret_cast (rtc)[i]); + } + + const u8 RETRY = 10; + for (u8 i = 0; i < RETRY; i++) + { + result = mcu.WriteBySend(nn::drivers::mcu::CTR::MCU_RTC_SEC_ADDR, bcd, RTC_PARAM_SIZE); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + if(result.IsSuccess()) + { + break; + } + nn::os::Thread::Sleep( + nn::fnd::TimeSpan::FromMilliSeconds( + nn::os::Tick::GetSystemCurrent().ToTimeSpan().GetMilliSeconds() % 100)); + + } + } + + NN_UTIL_RETURN_IF_FAILED(result); + } + else + { + COMMON_LOGGER("Failed Allocate Heap!!\n"); + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + } + } + else + { + result = nn::Result(nn::Result::LEVEL_PERMANENT, nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_INVALID_HANDLE); + } + + return result; +} + +bool InitializeFileSystem() +{ + nn::Result result; + + for (u32 i = 0; i < common::TWL_PATHNAME_MAX; i++) + { + result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[i], common::TWL_FS_ARCHIVE_KIND[i]); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + nn::fs::Directory dir; + std::vector entryList; //カレントディレクトリのエントリ一覧を格納 + std::vector::iterator entryIndex; + + std::wstring currentDirectory = common::NAND_TWL_ROOT_PATHNAME_WITH_SLASH_TABLE[i]; + 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(); + + // ルートディレクトリの子を開く + 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_FALSE_IF_FAILED(result); + + } + // ファイルなら削除する + else + { + NN_LOG("Try Delete %ls%ls\n", currentDirectory.c_str(), entryIndex->entryName); + result = nn::fs::TryDeleteFile( + (currentDirectory + ::std::wstring(entryIndex->entryName)).c_str()); + COMMON_LOGGER_RETURN_FALSE_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 = nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[i]); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + } + + result = nn::am::DeleteAllTwlUserPrograms(); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + nn::fs::InitializeCtrFileSystem(); + return true; +} + +nn::Result ImportIvs() +{ + nn::Result result = nn::ResultSuccess(); + nn::fs::FileOutputStream fos; + + size_t bufSize = 1024; + common::HeapManager encHeap(bufSize); + void* enc = encHeap.GetAddr(); + if (enc != NULL) + { + common::SdReaderWriter sdReader; + + size_t readSize; + result = sdReader.ReadBufWithCmac(common::IVS_PATHNAME, enc, bufSize, &readSize); + if(result.IsSuccess()) + { + // SDから読み出し成功 + result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND); + if (result.IsSuccess()) + { + common::HeapManager decHeap(bufSize); + void *dec = decHeap.GetAddr(); + if (dec != NULL) + { + // AES復号化する + nn::crypto::SwAesCtrContext swAesCtrContest; + + swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key)); + swAesCtrContest.Decrypt(dec, enc, readSize); + + // IVS書き込み + result = fos.TryInitialize(common::IVS_NAND_PATHNAME, true); + if (result.IsSuccess()) + { + if (result.IsSuccess()) + { + // 2ndNUPからはAPI経由で書き込む + if (RequiresImportApi()) + { + result = nn::fs::CTR::ImportIntegrityVerificationSeed( + *reinterpret_cast(dec)); + NN_UTIL_RETURN_IF_FAILED(result); + COMMON_LOGGER("Import SDCI.\n"); + } + else + { + s32 writeSize; + result = fos.TryWrite(&writeSize, dec, readSize, true); + if (result.IsSuccess()) + { + COMMON_LOGGER("Import SDCI.\n"); + } + } + } + } + } + else + { + COMMON_LOGGER("Failed Allocate Heap!!\n"); + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + + } + nn::fs::Unmount(common::NAND_ARCHIVE_NAME); + } + NN_UTIL_RETURN_IF_FAILED(result); + } + else + { + COMMON_LOGGER("Failed Allocate Heap!!\n"); + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + + return result; +} + +bool ImportIvsData() +{ + return ImportIvs().IsSuccess(); +} + +bool RequiresImportApi() +{ + return common::CUP_MAJOR_VER_2ND_NUP <= s_SDVersionData.cup.majorVersion; +} + +void ImportThreadFunc() +{ + nn::Result result; + s_IsImportSucceeded = true; + + result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); + + result = common::SdMountManager::Mount(); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); + + 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 heap(bufSize, AES_BLOCK_SIZE * 2); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + // 吸い出したバージョンによって書き込み関数を変える + if(RequiresImportApi()) + { + common::SaveDataMover saveDataMover; + saveDataMover.StartImport(buf, bufSize, &s_ImportProgress); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED( + saveDataMover.GetLastResult(), s_IsImportSucceeded + ); + } + else + { + if (!common::CopyDirectory( + &s_FileLists, + (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(), + common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH, buf, bufSize, false, NULL, NULL)) + { + s_IsImportSucceeded = false; + return; + } + } + } + + common::SdMountManager::Unmount(); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); + nn::fs::Unmount(common::NAND_ARCHIVE_NAME); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); + + NN_LOG("Import Thread Finalize\n"); +} + +namespace +{ + +void ImportSaveData() +{ + // SDカードからNANDに読み込み + nn::Result result; + + // ファイルサイズ設定 + common::InitializeTransferProgress(s_SdFileSize.ctrFileSize); + + // SDカードにあるセーブデータディレクトリ以下のデータをNANDにコピー + COMMON_LOGGER("Import NAND Data Start...\n"); + s_ImportThread.Start(ImportThreadFunc, s_ImportThreadStack); + +} + +nn::Result ImportNorData() +{ + COMMON_LOGGER("Import NOR Data.\n"); + + nn::Result result = nn::ResultSuccess(); + + nn::cfg::nor::CTR::Initialize(); + + size_t bufSize = common::GetAllocatableSize() / 2; + NN_LOG("AllocatableSize = %d\n", bufSize); + if(bufSize > common::FILE_COPY_HEAP_SIZE) + { + bufSize = common::FILE_COPY_HEAP_SIZE; + } + + common::HeapManager heap(bufSize); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + common::SdReaderWriter sdReader; + + size_t readSize; + result = sdReader.ReadBufWithCmac(common::NOR_PATHNAME, buf, bufSize, &readSize); + if(result.IsSuccess()) + { + // cfgを使ってセットする + result = nn::cfg::nor::CTR::SetNtrSetting(&reinterpret_cast(buf)->ntrConfig.ncd, + &reinterpret_cast(buf)->ntrConfig.ncd_ex); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + // WiFiコネクションIDが仮の値であればWiFi設定は移行しない + // TWL修理に準拠している + u64 attestedUserId1 = 0; + u64 attestedUserId2 = 0; + const u32 WIFI_CONNECTION_USERID_OFFSET1 = 0xf0; + const u32 WIFI_CONNECTION_USERID_OFFSET2 = 0x1f0; + const u32 USERID_SIZE = 6; + const bit64 USERID_MASK = 0x7FFFFFFFFFF; // 43bit + + + void* NtrWifiSettingAddr = &reinterpret_cast(buf)->NtrWiFiSetting; + std::memcpy(&attestedUserId1, + &reinterpret_cast(NtrWifiSettingAddr)[WIFI_CONNECTION_USERID_OFFSET1], + USERID_SIZE); + attestedUserId1 &= USERID_MASK; + + std::memcpy(&attestedUserId2, + &reinterpret_cast(NtrWifiSettingAddr)[WIFI_CONNECTION_USERID_OFFSET2], + USERID_SIZE); + attestedUserId2 &= USERID_MASK; + + if (attestedUserId1 == attestedUserId2 && attestedUserId1 != 0) + { + // TWL WiFi設定 + result = nn::cfg::nor::CTR::WriteTwlWifiSetting(0, + reinterpret_cast (buf)->TwlWiFiSetting, common::TWL_WIFI_SETTING_SIZE); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + // NTR WiFi設定 + result = nn::cfg::nor::CTR::WriteNtrWifiSetting(0, + reinterpret_cast (buf)->NtrWiFiSetting, common::NTR_WIFI_SETTING_SIZE); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + } + else + { + // クリアしておく + result = nn::cfg::nor::CTR::ClearTwlWifiSetting(); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = nn::cfg::nor::CTR::ClearNtrWifiSetting(); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + } + } + + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + } + else + { + COMMON_LOGGER("Failed Allocate Heap!!\n"); + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + + return result; +} + + +} + +nn::Result ReadVersionData() +{ + nn::Result result = nn::ResultSuccess(); + std::memset(&s_SDVersionData, 0, sizeof(common::VerDef)); + + size_t bufSize = common::GetAllocatableSize() / 2; + NN_LOG("AllocatableSize = %d\n", bufSize); + if(bufSize > common::FILE_COPY_HEAP_SIZE) + { + bufSize = common::FILE_COPY_HEAP_SIZE; + } + + common::HeapManager heap(bufSize); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + common::SdReaderWriter sdReader; + + size_t readSize; + result = sdReader.ReadBufWithCmac(common::VERSION_DATA_PATHNAME, buf, bufSize, &readSize); + if(result.IsSuccess()) + { + // バージョン情報を保持する + std::memcpy(&s_SDVersionData, buf, readSize); + NN_LOG("SD Version = %02d.%02d.%02d-%02d\n", s_SDVersionData.cup.majorVersion, + s_SDVersionData.cup.minorVersion, + s_SDVersionData.cup.microVersion, + s_SDVersionData.nup.majorVersion); + } + + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + } + else + { + COMMON_LOGGER("Failed Allocate Heap!!\n"); + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + + return result; +} + +bool ExistsIvsDirectory(std::string& ivsRoot) +{ + nn::Result result; + nn::fs::Directory dir; + + common::SdMountManager::Mount(); + + result = dir.TryInitialize(common::SD_NINTENDO_3DS_ROOT_PATH); + if(result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED(result); + common::SdMountManager::Unmount(); + return false; + } + + wchar_t ivs[34]; + std::mbstowcs(ivs, ivsRoot.c_str(), ivsRoot.size() + 1); + + nn::fs::DirectoryEntry entry; + s32 numEntry; + for (;;) + { + result = dir.TryRead(&numEntry, &entry, 1); + if (result.IsFailure()) + { + dir.Finalize(); + common::SdMountManager::Unmount(); + return false; + } + if (numEntry == 0) + { + dir.Finalize(); + common::SdMountManager::Unmount(); + return false; + } + else + { + // 比較する + if (entry.attributes.isDirectory) + { + NN_LOG("%ls\n", entry.entryName); + if(std::wcscmp(ivs, entry.entryName) == 0) + { + common::SdMountManager::Unmount(); + return true; + } + } + } + } +} + +nn::Result Cleanup() +{ + nn::Result result; + bool execCleanup; + + result = nn::am::NeedsCleanup(&execCleanup, nn::fs::MEDIA_TYPE_NAND); + if(result.IsSuccess()) + { + if(execCleanup) + { + COMMON_LOGGER("Cleanup NAND\n"); + return nn::am::DoCleanup(nn::fs::MEDIA_TYPE_NAND); + } + } + + return result; +} + +void DeleteAllCheckFiles() +{ + nn::Result result; + common::SdMountManager::Mount(); + + for(u32 i = 0; i < sizeof(CHECK_FILENAME_TABLE) / sizeof(CHECK_FILENAME_TABLE[0]); i++) + { + if(common::CheckFileExists(CHECK_FILENAME_TABLE[i])) + { + result = nn::fs::TryDeleteFile(CHECK_FILENAME_TABLE[i]); + COMMON_LOGGER_RESULT_IF_FAILED(result); + } + } + common::SdMountManager::Unmount(); +} + +void FinalizeImportThread() +{ + s_ImportThread.Join(); + s_ImportThread.Finalize(); +} + +bool IsImportThreadFinished() +{ + return s_ImportThread.IsValid() && !s_ImportThread.IsAlive(); +} + +void CreateWriteFinishedFile() +{ + CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_WRITE_FINISHED]); + common::ClearFileCheck(common::EXISTS_WRITE_FINISHED); +} + +void CreateConsoleInitializedFile() +{ + CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_CONSOLE_INTIALIZED]); + common::ClearFileCheck(common::EXISTS_CONSOLE_INTIALIZED); +} + +void CreateUpdateFinishedFile() +{ + CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_UPDATE_FINISHED]); + common::ClearFileCheck(common::EXISTS_UPDATE_FINISHED); +} + +void CreateRtcSyncFinishedFile() +{ + CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_RTC_SYNC_FINISHED]); + common::ClearFileCheck(common::EXISTS_RTC_SYNC_FINISHED); +} + +void CreateDownloadIvsFinishedFile() +{ + CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_DOWNLOAD_IVS]); + common::ClearFileCheck(common::EXISTS_DOWNLOAD_IVS); +} + +void CreateDeleteAccountFinishedFile() +{ + CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_DELETE_ACCOUNT]); + common::ClearFileCheck(common::EXISTS_DELETE_ACCOUNT); + +} + +void CreateTransferAccountFinishedFile() +{ + CreateEmptyFile(common::FILENAME_TABLE[common::EXISTS_TRANSFER_ACCOUNT]); + common::ClearFileCheck(common::EXISTS_TRANSFER_ACCOUNT); +} + +u32 GetImportProgress() +{ + if(RequiresImportApi()) + { + return s_ImportProgress; + } + else + { + return common::GetProgress(); + } +} + +bool UpdateNetworkSetting(nn::ac::NetworkSetting& networkSetting) +{ + nn::Result result; + bool retval = true; + + result = nn::ac::InitializeInternal(); + if(result.IsFailure()) + { + retval = false; + COMMON_LOGGER("Error: nn::ac::InitializeInternal() failed\n"); + } + else + { + //特に入力させる必要のない自動で設定する項目 + networkSetting.wireless.enable = true; + networkSetting.wireless.multiSsid.enable = false; + networkSetting.ip.enableDHCP = true; + networkSetting.scanlessConnect.hasConnected = false; + networkSetting.proxy.enable = false; + networkSetting.other.enableUPnP = false; + + // 現在のインターネット設定1を一時的に保持 + result = nn::ac::LoadNetworkSetting(0, s_CurrentNetowrkSetting1.setting); + if(result.IsSuccess()) + { + s_CurrentNetowrkSetting1.isValid = true; + } + else + { + s_CurrentNetowrkSetting1.isValid = false; + } + + result = nn::ac::UpdateNetworkSetting( 0, networkSetting ); + if(!result.IsSuccess()) + { + retval = false; + COMMON_LOGGER("Error: SetNetworkSetting (Update Error)\n"); + } + else + { + result = nn::ac::FinalizeInternal(); + if (!result.IsSuccess()) + { + retval = false; + COMMON_LOGGER("Error: SetNetworkSetting (Finalize Error)\n"); + } + } + } + + return retval; +} + +bool ReadSetting(bool* nupOnly, bool* getIvs, bool* checkSd, bool* skipNup) +{ + nn::Result result; + bool retval = true; + common::ConfigFileLoader configfileLoader; + + common::SdMountManager::Mount(); + size_t size = 10240; + common::HeapManager heap(size); + void* heapAddr = heap.GetAddr(); + + if(heapAddr != NULL) + { + result = configfileLoader.Initialize(common::AP_SETTING_PATHNAME, heapAddr, size); + if (result.IsSuccess()) + { + nn::ac::NetworkSetting networkSetting; + + { + const char* ssid = configfileLoader.ReadAsChar(L"SSID"); // SSID + if(ssid == NULL) + { + COMMON_LOGGER("SSID: is missing\n"); + retval = false; + } + else + { + std::strncpy(reinterpret_cast (networkSetting.wireless.essidSecurity.ssid), ssid, 32); + networkSetting.wireless.essidSecurity.ssidLength = std::strlen(ssid) % 33; + COMMON_LOGGER("SSID = %s\n", networkSetting.wireless.essidSecurity.ssid); + } + } + + + { + const char* mode = configfileLoader.ReadAsChar(L"MODE"); // MODE + if(mode == NULL) + { + COMMON_LOGGER("MODE: is missing\n"); + retval = false; + } + else + { + if (std::strcmp(mode, "OPEN") == 0) + { + networkSetting.wireless.essidSecurity.securityMode = nn::ac::OPEN; + } + else if (std::strcmp(mode, "WEP40") == 0) + { + networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_40BIT; + } + else if (std::strcmp(mode, "WEP104") == 0) + { + networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_104BIT; + } + else if (std::strcmp(mode, "WEP128") == 0) + { + networkSetting.wireless.essidSecurity.securityMode = nn::ac::WEP_128BIT; + } + else if (std::strcmp(mode, "WPA-TKIP") == 0) + { + networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA_TKIP; + } + else if (std::strcmp(mode, "WPA2-TKIP") == 0) + { + networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA2_TKIP; + } + else if (std::strcmp(mode, "WPA-AES") == 0) + { + networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA_AES; + } + else if (std::strcmp(mode, "WPA2-AES") == 0) + { + networkSetting.wireless.essidSecurity.securityMode = nn::ac::WPA2_AES; + } + else + { + networkSetting.wireless.essidSecurity.securityMode = nn::ac::OPEN; + } + + switch (networkSetting.wireless.essidSecurity.securityMode) + { + case nn::ac::OPEN: + { + COMMON_LOGGER("MODE = OPEN\n"); + } + break; + + case nn::ac::WEP_40BIT: + { + COMMON_LOGGER("MODE = WEP_40BIT\n"); + } + break; + + case nn::ac::WEP_104BIT: + { + COMMON_LOGGER("MODE = WEP_104BIT\n"); + } + break; + + case nn::ac::WEP_128BIT: + { + COMMON_LOGGER("MODE = WEP_128BIT\n"); + } + break; + + case nn::ac::WPA_TKIP: + { + COMMON_LOGGER("MODE = WPA_TKIP\n"); + } + break; + + case nn::ac::WPA2_TKIP: + { + COMMON_LOGGER("MODE = WPA2_TKIP\n"); + } + break; + + case nn::ac::WPA_AES: + { + COMMON_LOGGER("MODE = WPA_AES\n"); + } + break; + + case nn::ac::WPA2_AES: + { + COMMON_LOGGER("MODE = WPA2_AES\n"); + } + break; + + } + + } + } + + { + const char* pass = configfileLoader.ReadAsChar(L"PASS"); // PASS + if(pass == NULL) + { + COMMON_LOGGER("PASS: is missing\n"); + retval = false; + } + else + { + switch (networkSetting.wireless.essidSecurity.securityMode) + { + case nn::ac::WEP_40BIT: + case nn::ac::WEP_104BIT: + case nn::ac::WEP_128BIT: + { + std::strncpy(reinterpret_cast (networkSetting.wireless.essidSecurity.passphrase), + pass, 64); + std::memcpy(networkSetting.wireless.essidSecurity.key, + networkSetting.wireless.essidSecurity.passphrase, 64); + } + break; + + case nn::ac::WPA_TKIP: + case nn::ac::WPA2_TKIP: + case nn::ac::WPA_AES: + case nn::ac::WPA2_AES: + { + std::strncpy(reinterpret_cast (networkSetting.wireless.essidSecurity.passphrase), + pass, 64); + size_t phrase_size = std::strlen( + reinterpret_cast (networkSetting.wireless.essidSecurity.passphrase)); + + nn::nwm::Ssid ssid(reinterpret_cast (networkSetting.wireless.essidSecurity.ssid)); + nn::nwm::ConvertPasswordToPsk( + reinterpret_cast (networkSetting.wireless.essidSecurity.passphrase), + phrase_size, ssid, networkSetting.wireless.essidSecurity.key); + } + break; + + case nn::ac::OPEN: + default: + { + //do nothing + } + break; + } + } + } + + + { + s32 dnsAuto; // DNS_AUTO + if(configfileLoader.ReadAsChar(L"DNS_AUTO") == NULL) + { + COMMON_LOGGER("DNS_AUTO: is missing\n"); + retval = false; + } + else + { + dnsAuto = configfileLoader.ReadAsInteger(L"DNS_AUTO"); + if (dnsAuto == 1) + { + networkSetting.ip.autoDNSSetting = true; + } + else + { + networkSetting.ip.autoDNSSetting = false; + } + + COMMON_LOGGER("DNS_AUTO = %d\n", networkSetting.ip.autoDNSSetting); + + } + } + + { + const char* dnsPrimary = configfileLoader.ReadAsChar(L"DNS_PRI"); // プライマリDNS + if(!networkSetting.ip.autoDNSSetting) + { + if (dnsPrimary == NULL) + { + COMMON_LOGGER("DNS_PRI: is missing\n"); + retval = false; + + } + else + { + u8 dns[4]; + nn::socket::InAddr addr; + if (1 == nn::socket::InetAtoN(dnsPrimary, &addr)) + { + dns[3] = (0xff & (addr.addr >> 24)); + dns[2] = (0xff & (addr.addr >> 16)); + dns[1] = (0xff & (addr.addr >> 8)); + dns[0] = (0xff & (addr.addr)); + } + std::memcpy(networkSetting.ip.dns[0], dns, 4); + COMMON_LOGGER("DNS_PRI = %03d.%03d.%03d.%03d\n", networkSetting.ip.dns[0][0], + networkSetting.ip.dns[0][1], + networkSetting.ip.dns[0][2], + networkSetting.ip.dns[0][3]); + + } + } + } + + { + const char* dnsSecondary = configfileLoader.ReadAsChar(L"DNS_SEC"); // セカンダリDNS + if(!networkSetting.ip.autoDNSSetting) + { + if(dnsSecondary == NULL) + { + COMMON_LOGGER("DNS_SEC: is missing\n"); + retval = false; + } + else + { + u8 dns[4]; + nn::socket::InAddr addr; + if (1 == nn::socket::InetAtoN(dnsSecondary, &addr)) + { + dns[3] = (0xff & (addr.addr >> 24)); + dns[2] = (0xff & (addr.addr >> 16)); + dns[1] = (0xff & (addr.addr >> 8)); + dns[0] = (0xff & (addr.addr)); + } + std::memcpy(networkSetting.ip.dns[1], dns, 4); + COMMON_LOGGER("DNS_SEC = %03d.%03d.%03d.%03d\n", networkSetting.ip.dns[1][0], + networkSetting.ip.dns[1][1], + networkSetting.ip.dns[1][2], + networkSetting.ip.dns[1][3]); + + } + } + } + + { + const char* ntpServerName = configfileLoader.ReadAsChar(L"NTPSRV"); // NTPサーバ + if(ntpServerName == NULL) + { + COMMON_LOGGER("NTPSRV: is missing\n"); + retval = false; + } + else + { + std::strlcpy(s_NtpServerName, ntpServerName, sizeof(s_NtpServerName)); + COMMON_LOGGER("NTPSRV = %s\n", s_NtpServerName); + } + + + } + + { + const char* timeZone = configfileLoader.ReadAsChar(L"TIMEZONE"); // タイムゾーン + if(timeZone == NULL) + { + COMMON_LOGGER("TIMEZONE: is missing\n"); + retval = false; + } + else + { + std::strlcpy(s_TimeZoneStr, timeZone, sizeof(s_TimeZoneStr)); + COMMON_LOGGER("TIMEZONE = %s\n", s_TimeZoneStr); + ConvertTimeZoneString(s_TimeZoneStr); + } + + } + + { + const wchar_t* const NUP_ONLY_STR = L"NUP_ONLY"; + NN_NULL_ASSERT(nupOnly); + if (configfileLoader.ReadAsChar(NUP_ONLY_STR) != NULL) + { + s32 num = configfileLoader.ReadAsInteger(NUP_ONLY_STR); + if (num == 1) + { + *nupOnly = true; + COMMON_LOGGER("NUP Only Mode.\n"); + } + } + } + + { + const wchar_t* const GET_IVS_STR = L"GET_SDCI"; + NN_NULL_ASSERT(getIvs); + if (configfileLoader.ReadAsChar(GET_IVS_STR) != NULL) + { + s32 num = configfileLoader.ReadAsInteger(GET_IVS_STR); + if (num == 1) + { + *getIvs = true; + COMMON_LOGGER("GET SDCI Mode.\n"); + } + } + } + + { + const wchar_t* const CHECK_SD_STR = L"CHECK_SD"; + NN_NULL_ASSERT(checkSd); + if (configfileLoader.ReadAsChar(CHECK_SD_STR) != NULL) + { + s32 num = configfileLoader.ReadAsInteger(CHECK_SD_STR); + if (num == 1) + { + *checkSd = true; + COMMON_LOGGER("CHECK SD Mode.\n"); + } + } + } + + { + const wchar_t* const SKIP_NUP_STR = L"SKIP_NUP"; + NN_NULL_ASSERT(skipNup); + if (configfileLoader.ReadAsChar(SKIP_NUP_STR) != NULL) + { + s32 num = configfileLoader.ReadAsInteger(SKIP_NUP_STR); + if (num == 1) + { + *skipNup = true; + COMMON_LOGGER("Skip NUP Mode.\n"); + } + } + } + + configfileLoader.Finalize(); + + // 書き込み完了しなければfalse + if(!UpdateNetworkSetting(networkSetting)) + { + retval = false; + } + + } + else + { + NN_LOG("configfileLoader Initialize Failed\n"); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + retval = false; + } + } + else + { + NN_LOG("Can't Allocate Heap\n"); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + retval = false; + } + + common::SdMountManager::Unmount(); + return retval; +} + +char* GetNtpServerName() +{ + return s_NtpServerName; +} + +TimeZone GetTimeZone() +{ + return s_TimeZone; +} + +CheckedNetworkSetting* GetTempNetworkSetting() +{ + return &s_CurrentNetowrkSetting1; +} + +void ImportTwlData(enum common::TWL_PATH_INDEX path, s64 fileSize) +{ + NN_ASSERT(path < common::TWL_PATHNAME_MAX); + + nn::Result result; + s_IsImportSucceeded = 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_IsImportSucceeded); + + result = common::SdMountManager::Mount(); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); + + 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::InitializeTransferProgress(fileSize); + + common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + wchar_t archiveName[nn::fs::MAX_FILE_PATH_LENGTH]; + ::std::mbstowcs(archiveName, common::TWL_ARCHIVE_NAME_TABLE[path], std::strlen(common::TWL_ARCHIVE_NAME_TABLE[path]) + 1); + std::wstring archiveString(archiveName); + if(!common::CopyDirectory( + &s_FileLists, + (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(), + (archiveString + ::std::wstring(L"/")).c_str(), + buf, bufSize, false, NULL, NULL)) + { + s_IsImportSucceeded = false; + return; + } + } + + common::SdMountManager::Unmount(); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); + nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[path]); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); +} + +void ImportTwlTitleSaveData(s64 fileSize) +{ + nn::Result result; + s_IsImportSucceeded = true; + + 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_IsImportSucceeded); + + result = common::SdMountManager::Mount(); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); + + 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::InitializeTransferProgress(fileSize); + + common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + if(!common::CopyDirectory( + &s_FileLists, + (::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str(), + (std::wstring(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH) + ::std::wstring(L"/")).c_str(), + buf, bufSize, false, NULL, NULL)) + { + s_IsImportSucceeded = false; + return; + } + } + + common::SdMountManager::Unmount(); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); + nn::fs::Unmount(common::NAND_TWL_ARCHIVE_NAME); + COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsImportSucceeded); +} + +void ImportTwlPhotoDataFunc() +{ + COMMON_LOGGER("Import Twl Photo Data.\n"); + ImportTwlData(common::TWL_PHOTO, s_SdFileSize.twlPhotoFileSize); +} + +void ImportTwlSoundDataFunc() +{ + COMMON_LOGGER("Import Twl Sound Data.\n"); + ImportTwlData(common::TWL_SOUND, s_SdFileSize.twlSoundFileSize); +} + +void ImportTwlSaveDataFunc() +{ + COMMON_LOGGER("Import Twl Save Data.\n"); + ImportTwlTitleSaveData(s_SdFileSize.twlFileSize); +} + +void ImportTwlPhotoData() +{ + s_ImportThread.Start(ImportTwlPhotoDataFunc, s_ImportThreadStack); +} + +void ImportTwlSoundData() +{ + s_ImportThread.Start(ImportTwlSoundDataFunc, s_ImportThreadStack); +} + +void ImportTwlSaveData() +{ + s_ImportThread.Start(ImportTwlSaveDataFunc, s_ImportThreadStack); +} + + +void ClearFileReadResult() +{ + s_CheckedEqualsDeviceIdFileandDeviceId = false; + s_CheckedEqualsRegionDataandRegion = false; + s_ReadSerialNumber = false; +} + +nn::Result ExportCalData() +{ + using namespace nn::cfg::CTR::detail; + + nn::Result result; + common::CfgCalData cfgCalData; + common::SdReaderWriter sdWriter; + + COMMON_LOGGER("Export CalData\n"); + + result = common::SdMountManager::Mount(); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = nn::cfg::CTR::init::GetConfig(&cfgCalData.touchPanelCfgData, sizeof(TouchPanelCfgData), + GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_TOUCHPANEL)); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = nn::cfg::CTR::init::GetConfig(&cfgCalData.lcdFlickerCfgData, sizeof(LcdFlickerCfgData), + GET_CFG_KEY(NN_CFG_LCD, NN_CFG_LCD_CAL_FLICKER)); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = nn::cfg::CTR::init::GetConfig(&cfgCalData.fcramCfgData, sizeof(FcramCfgData), + GET_CFG_KEY(NN_CFG_FCRAM, NN_CFG_FCRAM_CAL_DELAY)); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = nn::cfg::CTR::init::GetConfig(&cfgCalData.rtcCfgData, sizeof(RtcCfgData), + GET_CFG_KEY(NN_CFG_RTC, NN_CFG_RTC_CAL_COMPENSATION)); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = nn::cfg::CTR::init::GetConfig(&cfgCalData.gyroscopeCfgData, sizeof(GyroscopeCfgData), + GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_GYROSCOPE)); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = nn::cfg::CTR::init::GetConfig(&cfgCalData.accelCfgData, sizeof(AccelCfgData), + GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_ACCELEROMETER)); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = nn::cfg::CTR::init::GetConfig(&cfgCalData.codecCfgData, sizeof(CodecCfgData), + GET_CFG_KEY(NN_CFG_CODEC, NN_CFG_CODEC_CAL)); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = nn::cfg::CTR::init::GetConfig(&cfgCalData.mcuSlideVolumeRangeCfgData, sizeof(McuSlideVolumeRangeCfgData), + GET_CFG_KEY(NN_CFG_MCU, NN_CFG_MCU_SLIDE_VOLUME)); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = sdWriter.WriteBufWithCmac(common::CFG_CALIBRATION_PATHNAME, &cfgCalData, sizeof(cfgCalData)); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + result = common::SdMountManager::Unmount(); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + return nn::ResultSuccess(); +} + +nn::Result ImportCalData(common::CfgCalData *data) +{ + using namespace nn::cfg::CTR::detail; + + nn::Result result = nn::ResultSuccess(); + + COMMON_LOGGER("Import CalData\n"); + + common::SdMountManager::Mount(); + + size_t bufSize = common::GetAllocatableSize() / 2; + if(bufSize > common::FILE_COPY_HEAP_SIZE) + { + bufSize = common::FILE_COPY_HEAP_SIZE; + } + common::HeapManager heap(bufSize); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + common::SdReaderWriter sdReader; + + size_t readSize; + result = sdReader.ReadBufWithCmac(common::CFG_CALIBRATION_PATHNAME, buf, bufSize, &readSize); + if(result.IsSuccess()) + { + // SDから読み出し成功 + std::memcpy(data, buf, readSize); + } + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + } + else + { + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + + common::SdMountManager::Unmount(); + return result; +} + +nn::Result InitializeHardwareDependentSetting() +{ + using namespace nn::cfg::CTR::detail; + nn::Result result = nn::ResultSuccess(); + + common::CfgCalData cfgCalData; + result = ImportCalData(&cfgCalData); + NN_UTIL_RETURN_IF_FAILED(result); + + result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_TOUCHPANEL), + &cfgCalData.touchPanelCfgData, sizeof(TouchPanelCfgData)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_LCD, NN_CFG_LCD_CAL_FLICKER), + &cfgCalData.lcdFlickerCfgData, sizeof(LcdFlickerCfgData)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_FCRAM, NN_CFG_FCRAM_CAL_DELAY), &cfgCalData.fcramCfgData, + sizeof(FcramCfgData)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_RTC, NN_CFG_RTC_CAL_COMPENSATION), + &cfgCalData.rtcCfgData, sizeof(RtcCfgData)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_GYROSCOPE), + &cfgCalData.gyroscopeCfgData, sizeof(GyroscopeCfgData)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_HID, NN_CFG_HID_CAL_ACCELEROMETER), + &cfgCalData.accelCfgData, sizeof(AccelCfgData)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_CODEC, NN_CFG_CODEC_CAL), &cfgCalData.codecCfgData, + sizeof(CodecCfgData)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + result = nn::cfg::CTR::init::SetConfig(GET_CFG_KEY(NN_CFG_MCU, NN_CFG_MCU_SLIDE_VOLUME), + &cfgCalData.mcuSlideVolumeRangeCfgData, sizeof(McuSlideVolumeRangeCfgData)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + NN_LOG("Set cfgCalData\n"); + + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + nn::cfg::CTR::init::ResetCameraCalibration(); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + nn::cfg::CTR::init::ResetAnalogStickCalibration(); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + return result; +} + +nn::Result SetupVersionAndFileList() +{ + std::memset(&s_SdFileSize, 0, sizeof(s_SdFileSize)); + + // ファイル一覧を読み込む + nn::Result result = ReadFileList(&s_SdFileSize, &s_FileLists); + NN_UTIL_RETURN_IF_FAILED(result); + + // バージョンデータを読み込む + result = ReadVersionData(); + NN_UTIL_RETURN_IF_FAILED(result); + + return result; +} + +nn::Result ReadFileList(SdFileSize* sdFiles, common::ImportDataList* fileList) +{ + nn::Result result = nn::ResultSuccess(); + + COMMON_LOGGER("Read File List\n"); + + size_t readSize; + common::SdReaderWriter sdReader; + s64 fileSize; + { + nn::fs::FileInputStream file; + + // サイズ取得のため一時的に開く + result = file.TryInitialize(common::FILE_LIST_PATHNAME); + NN_UTIL_RETURN_IF_FAILED(result); + + result = file.TryGetSize(&fileSize); + if (result.IsFailure()) + { + file.Finalize(); + return result; + } + file.Finalize(); + } + + // 初期化状態の場合は空 + if(fileSize == nn::crypto::AES_CMAC_MAC_SIZE) + { + sdFiles->ctrFileSize = 0; + sdFiles->totalFileSize = 0; + sdFiles->twlFileSize = 0; + sdFiles->twlPhotoFileSize = 0; + sdFiles->twlSoundFileSize = 0; + return nn::ResultSuccess(); + } + + common::HeapManager heap(fileSize); + void* buf = heap.GetAddr(); + if(buf != NULL) + { + result = sdReader.ReadBufWithCmac(common::FILE_LIST_PATHNAME, buf, fileSize, &readSize); + if(result.IsSuccess()) + { + // ファイル一覧 + const char comma[] = ","; + const char newLine[] = "\n"; + char *token = NULL; + token = std::strtok(reinterpret_cast(buf), comma); + bool parseFileName = false; + common::ImportDataEntry entry; + + entry.fileName = std::string(token); + while( token != NULL) + { + if(parseFileName) + { + token = std::strtok(NULL, comma); + if(token != NULL) + { + entry.fileName = std::string(token); + } + } + else + { + token = std::strtok(NULL, newLine); + if(token != NULL) + { + s64 size = std::atoll(token); + if(size != -1) + { + entry.isDirectory = false; + sdFiles->totalFileSize += size; + + wchar_t wcToken[nn::fs::MAX_FILE_PATH_LENGTH]; + if(std::mbstowcs(wcToken, entry.fileName.c_str(), entry.fileName.size()) != entry.fileName.size() - 1) + { + if(std::wcsstr(wcToken, common::SD_SAVEDATA_ROOT_NAME) != NULL) + { + sdFiles->ctrFileSize += size; + } + else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME) != NULL) + { + sdFiles->twlPhotoFileSize += size; + } + else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME) != NULL) + { + sdFiles->twlSoundFileSize += size; + } + else if(std::wcsstr(wcToken, common::SD_SAVEDATA_TWL_ROOT_NAME) != NULL) + { + sdFiles->twlFileSize += size; + } + } + } + else + { + entry.isDirectory = true; + } + + fileList->push_back(entry); + } + } + parseFileName = !parseFileName; + + } + + } + } + else + { + result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON, + nn::Result::DESCRIPTION_OUT_OF_MEMORY); + } + return result; + +} + +bool IsImportSucceeded() +{ + return s_IsImportSucceeded; +} + +nn::Result ImportData() +{ + static nn::Result result = nn::ResultSuccess(); + static bool init = true; + if(init) + { + init = false; + + // インポート前にACを止める + result = nn::ndm::SuspendScheduler(); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + // NANDのごみを削除する + result = Cleanup(); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + // NORデータを書き込む + result = ImportNorData(); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + // 固体固有calLデータをSDカードに出力する + // 本体初期化後はcal値が設定されている + result = ExportCalData(); + COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); + + // SDカードのセーブデータをNANDに書き込む + ImportSaveData(); + } + + return result; +} + +} diff --git a/branches/2-1-1/sources/ConsoleRestore/Importer.h b/branches/2-1-1/sources/ConsoleRestore/Importer.h new file mode 100644 index 0000000..d17382a --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/Importer.h @@ -0,0 +1,165 @@ +/*---------------------------------------------------------------------------* + 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 +#include "FileName.h" +#include +#include +#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(); + +} + +#endif /* IMPORTER_H_ */ diff --git a/branches/2-1-1/sources/ConsoleRestore/NtpClient.cpp b/branches/2-1-1/sources/ConsoleRestore/NtpClient.cpp new file mode 100644 index 0000000..b92040c --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/NtpClient.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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(reinterpret_cast (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 (&addr), reinterpret_cast (&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 (&dns1), reinterpret_cast (&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 (&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 (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 (&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 (&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); +} + +} diff --git a/branches/2-1-1/sources/ConsoleRestore/NtpClient.h b/branches/2-1-1/sources/ConsoleRestore/NtpClient.h new file mode 100644 index 0000000..0e9514e --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/NtpClient.h @@ -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_ */ diff --git a/branches/2-1-1/sources/ConsoleRestore/OMakefile b/branches/2-1-1/sources/ConsoleRestore/OMakefile new file mode 100644 index 0000000..7979488 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/OMakefile @@ -0,0 +1,78 @@ +#!/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 + ../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) diff --git a/branches/2-1-1/sources/ConsoleRestore/Shop.cpp b/branches/2-1-1/sources/ConsoleRestore/Shop.cpp new file mode 100644 index 0000000..3a1b0bd --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/Shop.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 ポインタをそれぞれ と NULL として返す +#ifdef COMMON_LOGGER_DETAIL_ENABLE +const char* Cstr(const char* p) +{ + return p ? (p[0] ? p : "") : "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; +} + +} diff --git a/branches/2-1-1/sources/ConsoleRestore/Shop.h b/branches/2-1-1/sources/ConsoleRestore/Shop.h new file mode 100644 index 0000000..1cf5eac --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/Shop.h @@ -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 +#include + +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_ */ diff --git a/branches/2-1-1/sources/ConsoleRestore/TitleDownloader.cpp b/branches/2-1-1/sources/ConsoleRestore/TitleDownloader.cpp new file mode 100644 index 0000000..2960c36 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/TitleDownloader.cpp @@ -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 +#include +#include +#include + +#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 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; inEntries == 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 + +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 (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; +} + +} diff --git a/branches/2-1-1/sources/ConsoleRestore/TitleDownloader.h b/branches/2-1-1/sources/ConsoleRestore/TitleDownloader.h new file mode 100644 index 0000000..7051b3c --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/TitleDownloader.h @@ -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 + +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_ */ diff --git a/branches/2-1-1/sources/ConsoleRestore/Updater.cpp b/branches/2-1-1/sources/ConsoleRestore/Updater.cpp new file mode 100644 index 0000000..55addb4 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/Updater.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#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 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(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; +} + + +} diff --git a/branches/2-1-1/sources/ConsoleRestore/Updater.h b/branches/2-1-1/sources/ConsoleRestore/Updater.h new file mode 100644 index 0000000..7802590 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/Updater.h @@ -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 + +namespace ConsoleRestore +{ + +// 新たにスレッドを立て、ネットワークアップデートを開始する +void StartFGNetworkUpdate(); + +// ネットワークアップデートスレッドを終了する +void FinishFGNetworkUpdate(); + +// ネットワークアップデートスレッドが終了したかどうか +bool IsNetworkUpdateFinished(); + +// ネットワークアップデートの進捗を取得する +u32 GetUpdateProgress(); + +// ネットワークアップデートのResultを取得する +nn::Result GetUpdateResult(); + +} + +#endif /* UPDATER_H_ */ diff --git a/branches/2-1-1/sources/ConsoleRestore/banner/model.cbmd b/branches/2-1-1/sources/ConsoleRestore/banner/model.cbmd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/ConsoleRestore/banner/model.cbmd differ diff --git a/branches/2-1-1/sources/ConsoleRestore/banner/sound.cbsd b/branches/2-1-1/sources/ConsoleRestore/banner/sound.cbsd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/ConsoleRestore/banner/sound.cbsd differ diff --git a/branches/2-1-1/sources/ConsoleRestore/banner/unknown24x24.ctpk b/branches/2-1-1/sources/ConsoleRestore/banner/unknown24x24.ctpk new file mode 100644 index 0000000..794b136 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/banner/unknown24x24.ctpk @@ -0,0 +1 @@ +888yyYyYyyyYyyYyyyyYyYy8 \ No newline at end of file diff --git a/branches/2-1-1/sources/ConsoleRestore/banner/unknown48x48.ctpk b/branches/2-1-1/sources/ConsoleRestore/banner/unknown48x48.ctpk new file mode 100644 index 0000000..8c7da16 --- /dev/null +++ b/branches/2-1-1/sources/ConsoleRestore/banner/unknown48x48.ctpk @@ -0,0 +1 @@ +Y8888ƺ8888YYyyYYޚ޺yY8YyYYޚyY8ޚ8 \ No newline at end of file diff --git a/branches/2-1-1/sources/OMakefile b/branches/2-1-1/sources/OMakefile new file mode 100644 index 0000000..0ebeff4 --- /dev/null +++ b/branches/2-1-1/sources/OMakefile @@ -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() diff --git a/branches/2-1-1/sources/OMakeroot b/branches/2-1-1/sources/OMakeroot new file mode 100644 index 0000000..7ee1cb5 --- /dev/null +++ b/branches/2-1-1/sources/OMakeroot @@ -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:$ +#---------------------------------------------------------------------------- + +# fBNgCAEgɂ‚Ă̐ +# +# a) \[XR[h[gfBNgɔzuꍇ +# : +# /OMakeroot +# /foo/bar/OMakefile +# +# : +# OMakefile ƓfBNgȉ objects images ܂B +# +# /foo/bar/objects/... +# /foo/bar/images/.. +# +# +# b) \[XR[h sources ȉɔzuꍇ +# : +# /OMakeroot +# /sources/foo/bar/OMakefile +# +# : +# [gfBNgȉ objects images ܂B +# +# /objects/foo/bar/... +# /images/foo/bar/... +# +# + +# [g‹ϐ̎擾 +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 v܂BpXݒ肷邩Aǂ炩`ĉB) + 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: . + diff --git a/branches/2-1-1/sources/common/Aes_define.h b/branches/2-1-1/sources/common/Aes_define.h new file mode 100644 index 0000000..68a4cc6 --- /dev/null +++ b/branches/2-1-1/sources/common/Aes_define.h @@ -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 + +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_ */ diff --git a/branches/2-1-1/sources/common/CommonLogger.cpp b/branches/2-1-1/sources/common/CommonLogger.cpp new file mode 100644 index 0000000..998e49b --- /dev/null +++ b/branches/2-1-1/sources/common/CommonLogger.cpp @@ -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; +} + +} + +} diff --git a/branches/2-1-1/sources/common/CommonLogger.h b/branches/2-1-1/sources/common/CommonLogger.h new file mode 100644 index 0000000..208bd82 --- /dev/null +++ b/branches/2-1-1/sources/common/CommonLogger.h @@ -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 +#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_ */ diff --git a/branches/2-1-1/sources/common/DrawSystemState.cpp b/branches/2-1-1/sources/common/DrawSystemState.cpp new file mode 100644 index 0000000..62d0a6a --- /dev/null +++ b/branches/2-1-1/sources/common/DrawSystemState.cpp @@ -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 + +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* 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(s_FriendCode / 100000000ULL % 10000ULL), static_cast (s_FriendCode / 10000ULL % 10000ULL), + static_cast (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::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& 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, ""); +} + +} diff --git a/branches/2-1-1/sources/common/DrawSystemState.h b/branches/2-1-1/sources/common/DrawSystemState.h new file mode 100644 index 0000000..db575fe --- /dev/null +++ b/branches/2-1-1/sources/common/DrawSystemState.h @@ -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 +#include "demo.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +#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& operationMessage, + nn::cfg::CTR::CfgRegionCode region, + u8* s_SerialNo, + bool readFriendCode +); + +} + + +#endif /* DRAWSYSTEMSTATE_H_ */ diff --git a/branches/2-1-1/sources/common/FileChecker.cpp b/branches/2-1-1/sources/common/FileChecker.cpp new file mode 100644 index 0000000..5397e29 --- /dev/null +++ b/branches/2-1-1/sources/common/FileChecker.cpp @@ -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 +#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; + } +} + + +} diff --git a/branches/2-1-1/sources/common/FileChecker.h b/branches/2-1-1/sources/common/FileChecker.h new file mode 100644 index 0000000..47576c2 --- /dev/null +++ b/branches/2-1-1/sources/common/FileChecker.h @@ -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_ */ diff --git a/branches/2-1-1/sources/common/FileName.h b/branches/2-1-1/sources/common/FileName.h new file mode 100644 index 0000000..bb66cdf --- /dev/null +++ b/branches/2-1-1/sources/common/FileName.h @@ -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 + +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_ */ diff --git a/branches/2-1-1/sources/common/FileTransfer.cpp b/branches/2-1-1/sources/common/FileTransfer.cpp new file mode 100644 index 0000000..185e3a8 --- /dev/null +++ b/branches/2-1-1/sources/common/FileTransfer.cpp @@ -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 +#include + +#include +#include +#include +#include + +#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 entryList; //カレントディレクトリのエントリ一覧を格納 + std::vector::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(buf), bufSize / 2, &readsize); + + // 暗号化後SHA256を計算しつつ書き込み + result = swAesCtrContext.Encrypt(reinterpret_cast(buf) + bufSize / 2, buf, readsize); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + context.Update(reinterpret_cast(buf) + bufSize / 2, readsize); + + result = to_file.TryWrite(&writesize, reinterpret_cast(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(buf), bufSize / 2, &readsize); + + // 暗号化後SHA256を計算しつつ書き込み + result = swAesCtrContext.Encrypt(reinterpret_cast(buf) + bufSize / 2, buf, readsize); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + context.Update(reinterpret_cast(buf) + bufSize / 2, readsize); + + result = to_file.TryWrite(&writesize, reinterpret_cast(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(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(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(buf), bufSize / 2, &readSize); + result = swAesCtrContext.Encrypt(reinterpret_cast(buf) + bufSize / 2, buf, readSize); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + context.Update(reinterpret_cast(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(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(); +} + +} diff --git a/branches/2-1-1/sources/common/FileTransfer.h b/branches/2-1-1/sources/common/FileTransfer.h new file mode 100644 index 0000000..d74fa78 --- /dev/null +++ b/branches/2-1-1/sources/common/FileTransfer.h @@ -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 +#include +#include +#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_ */ diff --git a/branches/2-1-1/sources/common/HardwareStateManager.cpp b/branches/2-1-1/sources/common/HardwareStateManager.cpp new file mode 100644 index 0000000..0f5fa76 --- /dev/null +++ b/branches/2-1-1/sources/common/HardwareStateManager.cpp @@ -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); +} + +} diff --git a/branches/2-1-1/sources/common/HardwareStateManager.h b/branches/2-1-1/sources/common/HardwareStateManager.h new file mode 100644 index 0000000..1483dff --- /dev/null +++ b/branches/2-1-1/sources/common/HardwareStateManager.h @@ -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_ */ diff --git a/branches/2-1-1/sources/common/HeapManager.cpp b/branches/2-1-1/sources/common/HeapManager.cpp new file mode 100644 index 0000000..1930fc2 --- /dev/null +++ b/branches/2-1-1/sources/common/HeapManager.cpp @@ -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); + } +} + +} diff --git a/branches/2-1-1/sources/common/HeapManager.h b/branches/2-1-1/sources/common/HeapManager.h new file mode 100644 index 0000000..eb8da76 --- /dev/null +++ b/branches/2-1-1/sources/common/HeapManager.h @@ -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 +#include + +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_ */ diff --git a/branches/2-1-1/sources/common/LogConsole.cpp b/branches/2-1-1/sources/common/LogConsole.cpp new file mode 100644 index 0000000..7ddd16e --- /dev/null +++ b/branches/2-1-1/sources/common/LogConsole.cpp @@ -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 + +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::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::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 diff --git a/branches/2-1-1/sources/common/LogConsole.h b/branches/2-1-1/sources/common/LogConsole.h new file mode 100644 index 0000000..1b2bbbe --- /dev/null +++ b/branches/2-1-1/sources/common/LogConsole.h @@ -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 +#include +#include +#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 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_ */ diff --git a/branches/2-1-1/sources/common/LogConsole_Private.h b/branches/2-1-1/sources/common/LogConsole_Private.h new file mode 100644 index 0000000..8fbdd42 --- /dev/null +++ b/branches/2-1-1/sources/common/LogConsole_Private.h @@ -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_ */ diff --git a/branches/2-1-1/sources/common/OMakefile b/branches/2-1-1/sources/common/OMakefile new file mode 100644 index 0000000..e874cbc --- /dev/null +++ b/branches/2-1-1/sources/common/OMakefile @@ -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() diff --git a/branches/2-1-1/sources/common/ProgramId.h b/branches/2-1-1/sources/common/ProgramId.h new file mode 100644 index 0000000..c565f11 --- /dev/null +++ b/branches/2-1-1/sources/common/ProgramId.h @@ -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_ */ diff --git a/branches/2-1-1/sources/common/ResFont.cpp b/branches/2-1-1/sources/common/ResFont.cpp new file mode 100644 index 0000000..a9a8a79 --- /dev/null +++ b/branches/2-1-1/sources/common/ResFont.cpp @@ -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 +#include +#include +#include +#include + +#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(width); + f32 l = 0; + f32 r = static_cast(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 + +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; +} + +} diff --git a/branches/2-1-1/sources/common/ResFont.h b/branches/2-1-1/sources/common/ResFont.h new file mode 100644 index 0000000..379a0bb --- /dev/null +++ b/branches/2-1-1/sources/common/ResFont.h @@ -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 + +namespace common +{ + +// ResFontを初期化する。 +void InitializeResFont(); + +// 文字列の描画時に実行したいハンドラを設定する +void SetDrawTextHandler(void (*func)()); + +// SetDrawTextHandler で設定した関数を使って文字列を描画する +void DrawResFont(s32 display); + +// 内部で保持しているTextWriterへのポインタを返す +nn::font::TextWriter* GetTextWriter(); + + +} + + +#endif /* RESFONT_H_ */ diff --git a/branches/2-1-1/sources/common/SaveDataMover.cpp b/branches/2-1-1/sources/common/SaveDataMover.cpp new file mode 100644 index 0000000..f16de94 --- /dev/null +++ b/branches/2-1-1/sources/common/SaveDataMover.cpp @@ -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 + +#include +#include +#include +#include +#include + +#include + +#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 */ diff --git a/branches/2-1-1/sources/common/SaveDataMover.h b/branches/2-1-1/sources/common/SaveDataMover.h new file mode 100644 index 0000000..7e5bebc --- /dev/null +++ b/branches/2-1-1/sources/common/SaveDataMover.h @@ -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 + +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_ */ diff --git a/branches/2-1-1/sources/common/SdLogger.cpp b/branches/2-1-1/sources/common/SdLogger.cpp new file mode 100644 index 0000000..087e7cb --- /dev/null +++ b/branches/2-1-1/sources/common/SdLogger.cpp @@ -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 +#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 s_SdmcEjectedEventThreadStack; + +nn::os::Thread s_SdmcInsertedEventThread; +nn::os::StackBuffer 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::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 + + diff --git a/branches/2-1-1/sources/common/SdLogger.h b/branches/2-1-1/sources/common/SdLogger.h new file mode 100644 index 0000000..103c5fc --- /dev/null +++ b/branches/2-1-1/sources/common/SdLogger.h @@ -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 +#include +#include + +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 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_ */ diff --git a/branches/2-1-1/sources/common/SdMountManager.cpp b/branches/2-1-1/sources/common/SdMountManager.cpp new file mode 100644 index 0000000..4895529 --- /dev/null +++ b/branches/2-1-1/sources/common/SdMountManager.cpp @@ -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 +#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); +} + + +} diff --git a/branches/2-1-1/sources/common/SdMountManager.h b/branches/2-1-1/sources/common/SdMountManager.h new file mode 100644 index 0000000..c4db65b --- /dev/null +++ b/branches/2-1-1/sources/common/SdMountManager.h @@ -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_ */ diff --git a/branches/2-1-1/sources/common/SdReaderWriter.cpp b/branches/2-1-1/sources/common/SdReaderWriter.cpp new file mode 100644 index 0000000..01fe5fe --- /dev/null +++ b/branches/2-1-1/sources/common/SdReaderWriter.cpp @@ -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 +#include +#include +#include + +#include + +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(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(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(); +} + +} diff --git a/branches/2-1-1/sources/common/SdReaderWriter.h b/branches/2-1-1/sources/common/SdReaderWriter.h new file mode 100644 index 0000000..392ba0d --- /dev/null +++ b/branches/2-1-1/sources/common/SdReaderWriter.h @@ -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 + +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_ */ diff --git a/branches/2-1-1/sources/common/SimplePlayer.cpp b/branches/2-1-1/sources/common/SimplePlayer.cpp new file mode 100644 index 0000000..921eff9 --- /dev/null +++ b/branches/2-1-1/sources/common/SimplePlayer.cpp @@ -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 +#include +#include +#include +#include +#include + +#include +#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 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(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(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 + *---------------------------------------------------------------------------*/ diff --git a/branches/2-1-1/sources/common/SimplePlayer.h b/branches/2-1-1/sources/common/SimplePlayer.h new file mode 100644 index 0000000..2f73c78 --- /dev/null +++ b/branches/2-1-1/sources/common/SimplePlayer.h @@ -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_ */ diff --git a/branches/2-1-1/sources/common/Util.cpp b/branches/2-1-1/sources/common/Util.cpp new file mode 100644 index 0000000..4afe5fb --- /dev/null +++ b/branches/2-1-1/sources/common/Util.cpp @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(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(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; +} + +} diff --git a/branches/2-1-1/sources/common/Util.h b/branches/2-1-1/sources/common/Util.h new file mode 100644 index 0000000..2f6a6e7 --- /dev/null +++ b/branches/2-1-1/sources/common/Util.h @@ -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 +#include +#include +#include +#include + +#include "VersionDetect.h" + +namespace common +{ + +class Util +{ +public: + Util(); + virtual ~Util(); + + void InitializeForBackup(); + void InitializeForRestore(); + + void FinalizeForBackup(); + void FinalizeForRestore(); + + // シリアルナンバーにモジュラス10 ウェイト3・1(M10W31)でチェックデジットを付加する + 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(); + + // バッテリ残量を0~100で返す + 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_ */ diff --git a/branches/2-1-1/sources/common/VersionDetect.cpp b/branches/2-1-1/sources/common/VersionDetect.cpp new file mode 100644 index 0000000..09977cd --- /dev/null +++ b/branches/2-1-1/sources/common/VersionDetect.cpp @@ -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 +#include +#include + +#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 (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 (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); +} + +} + diff --git a/branches/2-1-1/sources/common/VersionDetect.h b/branches/2-1-1/sources/common/VersionDetect.h new file mode 100644 index 0000000..9b41b56 --- /dev/null +++ b/branches/2-1-1/sources/common/VersionDetect.h @@ -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 +#include "common_Types.h" + +namespace common +{ + +// リージョンコードに基づいてバージョン情報を取得する +void GetSystemVersion(common::VerDef* mVerData, nn::cfg::CTR::CfgRegionCode region); + +} + + +#endif /* VERSIONDETECT_H_ */ diff --git a/branches/2-1-1/sources/common/common_Types.h b/branches/2-1-1/sources/common/common_Types.h new file mode 100644 index 0000000..e158c53 --- /dev/null +++ b/branches/2-1-1/sources/common/common_Types.h @@ -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 +#include +#include +#include +#include +#include + +#include +#include + +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 ImportDataList; + +// TWLセーブデータリストのエントリ +struct SavePathInfo +{ + std::wstring name; + NN_PADDING3; + bool isDirectory; +}; + +} + +#endif /* COMMON_TYPES_H_ */ diff --git a/branches/2-1-1/sources/common/configLoader.cpp b/branches/2-1-1/sources/common/configLoader.cpp new file mode 100644 index 0000000..b262ba9 --- /dev/null +++ b/branches/2-1-1/sources/common/configLoader.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +#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(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)); +} + +} diff --git a/branches/2-1-1/sources/common/configLoader.h b/branches/2-1-1/sources/common/configLoader.h new file mode 100644 index 0000000..67e1edf --- /dev/null +++ b/branches/2-1-1/sources/common/configLoader.h @@ -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_ diff --git a/branches/2-1-1/sources/common/romfiles/annotation.wav b/branches/2-1-1/sources/common/romfiles/annotation.wav new file mode 100644 index 0000000..b64f77b Binary files /dev/null and b/branches/2-1-1/sources/common/romfiles/annotation.wav differ diff --git a/branches/2-1-1/sources/common/romfiles/cursor.wav b/branches/2-1-1/sources/common/romfiles/cursor.wav new file mode 100644 index 0000000..85765b3 Binary files /dev/null and b/branches/2-1-1/sources/common/romfiles/cursor.wav differ diff --git a/branches/2-1-1/sources/common/romfiles/lc.bcfnt b/branches/2-1-1/sources/common/romfiles/lc.bcfnt new file mode 100644 index 0000000..28d1db0 Binary files /dev/null and b/branches/2-1-1/sources/common/romfiles/lc.bcfnt differ diff --git a/branches/2-1-1/sources/common/romfiles/ng.wav b/branches/2-1-1/sources/common/romfiles/ng.wav new file mode 100644 index 0000000..dc2f3ef Binary files /dev/null and b/branches/2-1-1/sources/common/romfiles/ng.wav differ diff --git a/branches/2-1-1/sources/common/romfiles/nnfont_RectDrawerShader.shbin b/branches/2-1-1/sources/common/romfiles/nnfont_RectDrawerShader.shbin new file mode 100644 index 0000000..4290c2c Binary files /dev/null and b/branches/2-1-1/sources/common/romfiles/nnfont_RectDrawerShader.shbin differ diff --git a/branches/2-1-1/sources/common/romfiles/ok.wav b/branches/2-1-1/sources/common/romfiles/ok.wav new file mode 100644 index 0000000..bf5149f Binary files /dev/null and b/branches/2-1-1/sources/common/romfiles/ok.wav differ diff --git a/branches/2-1-1/sources/common/version.h b/branches/2-1-1/sources/common/version.h new file mode 100644 index 0000000..2e2c72d --- /dev/null +++ b/branches/2-1-1/sources/common/version.h @@ -0,0 +1,23 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: version.h + + 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$ + *---------------------------------------------------------------------------*/ + +#ifndef VERSION_H_ +#define VERSION_H_ + +#define CONSOLE_REPAIR_VERSION_MAJOR "2" +#define CONSOLE_REPAIR_VERSION_MINOR "1" +#define CONSOLE_REPAIR_VERSION_MICRO "1" + +#endif /* VERSION_H_ */ diff --git a/branches/2-1-1/sources/common/wave.cpp b/branches/2-1-1/sources/common/wave.cpp new file mode 100644 index 0000000..a897109 --- /dev/null +++ b/branches/2-1-1/sources/common/wave.cpp @@ -0,0 +1,150 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: wave.c + + 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$ + *---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* includes */ +#include "wave.h" + +/*---------------------------------------------------------------------------*/ +/* functions */ + +/*---------------------------------------------------------------------------* + Name: LoadWave + + Description: Wave データを読み込む. + + Arguments: filepath : ファイルパス + fmt : Wave データの fmt チャンクを格納 + data : Wave データの data チャンクを格納 + + Returns: None. + *---------------------------------------------------------------------------*/ +void LoadWaveCore(nn::fs::FileReader& reader, WaveFmt * fmt, WaveData * data, bool isSizeOnly) +{ + reader.SetPosition(0); + + WaveRiff riff; // RIFF ヘッダ + WaveChunk chunk; // CHUNK + u32 readbyte = 0; // ファイル読み込みの判定に使用 + u32 fsize = reader.GetSize(); + + // RIFF ヘッダ読み込み + reader.Read((u8*)&riff, sizeof(WaveRiff)); + + // サイズを積算 + readbyte += sizeof(WaveRiff); + + // "RIFF" との一致を確認 + if (riff.tag != MAKE_WAVE_TAG_VALUE('R','I','F','F')) + { + NN_PANIC("Not RIFF format.\n"); + } + // "WAVE" との一致を確認 + if ( riff.type != MAKE_WAVE_TAG_VALUE('W','A','V','E') ) + { + NN_PANIC("Not Wave format.\n"); + } + + // ファイルサイズより大きくなるまで読み込む + while(fsize > readbyte) + { + // CHUNK の読み込み + reader.Read((u8*)&chunk, sizeof(WaveChunk)); + readbyte += sizeof(WaveChunk); + + // "fmt " + if (chunk.tag == MAKE_WAVE_TAG_VALUE('f','m','t',' ')) + { + reader.Read((u8*)fmt, sizeof(WaveFmt)); + readbyte += sizeof(WaveFmt); + + // 拡張領域があれば読み捨て + if (chunk.size > sizeof(WaveFmt)) + { + u16 ext_size; + + reader.Read((u8*)&ext_size, sizeof(ext_size)); + readbyte += sizeof(ext_size); + + readbyte += chunk.size; + if (readbyte == fsize) break; + + reader.Seek(ext_size, nn::fs::POSITION_BASE_CURRENT); + } + } + // "data" + else if (chunk.tag == MAKE_WAVE_TAG_VALUE('d','a','t','a')) + { + data->size = chunk.size; + + if (isSizeOnly) + { + return; + } + else + { + reader.Read((u8*)data->buf, data->size); + // 8-bit wav ファイルの場合は unsigned -> signed の変換が必要 + if (fmt->quantum_bits == 8) + { + s8* p = (s8*)data->buf; + for (int i = 0; i < data->size; i++) + { + p[i] -= 128; + } + } + } + readbyte += chunk.size; + } + // それ以外 + else + { + readbyte += chunk.size; + if (readbyte == fsize) break; + + // 読み飛ばす + reader.Seek(chunk.size, nn::fs::POSITION_BASE_CURRENT); + } + } +} + +#ifndef NN_BUILD_RELEASE // Release ビルドでは HostIO は使えません。 +void WriteWaveHeader(nn::hio::CTR::HostFile& hostFile, WaveFmt* fmt, s32 size) +{ + WaveRiff riff; + riff.tag = MAKE_WAVE_TAG_VALUE('R','I','F','F'); + riff.size = + + sizeof(WaveRiff) // riff header + + sizeof(WaveChunk) + sizeof(WaveFmt) // wave fmt header + + sizeof(WaveChunk) + size // wave data + - 8; + riff.type = MAKE_WAVE_TAG_VALUE('W','A','V','E'); + hostFile.Write(&riff, sizeof(WaveRiff)); + + WaveChunk chunk; + chunk.tag = MAKE_WAVE_TAG_VALUE('f','m','t',' '); + chunk.size = sizeof(WaveFmt); + hostFile.Write(&chunk, sizeof(WaveChunk)); + hostFile.Write(fmt, sizeof(WaveFmt)); + + chunk.tag = MAKE_WAVE_TAG_VALUE('d','a','t','a'); + chunk.size = size; + hostFile.Write(&chunk, sizeof(WaveChunk)); +} +#endif // NN_BUILD_RELEASE + +/*---------------------------------------------------------------------------*/ +/* end of file */ +/*---------------------------------------------------------------------------*/ diff --git a/branches/2-1-1/sources/common/wave.h b/branches/2-1-1/sources/common/wave.h new file mode 100644 index 0000000..cbaf2f3 --- /dev/null +++ b/branches/2-1-1/sources/common/wave.h @@ -0,0 +1,148 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: wave.h + + 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$ + *---------------------------------------------------------------------------*/ + +#ifndef __WAVE_HEADER__ +#define __WAVE_HEADER__ + +/*---------------------------------------------------------------------------*/ +/* includes */ +#include +#include +#ifndef NN_BUILD_RELEASE // Release ビルドでは HostIO は使えません。 +#include +#endif // NN_BUILD_RELEASE + +/*---------------------------------------------------------------------------*/ +/* constants */ + +#define MAKE_WAVE_TAG_VALUE(c1, c2, c3, c4) \ + ( c1 | (c2<<8) | (c3<<16) | (c4<<24) ) + +#define MAKE_WAVE_TAG_STRING(str, val) \ + { \ + str[3] = (char) ( (val>>24)&0xff ) ; \ + str[2] = (char) ( (val>>16)&0xff ) ; \ + str[1] = (char) ( (val>> 8)&0xff ) ; \ + str[0] = (char) ( (val )&0xff ) ; \ + str[4] = (char) ( 0 ) ; \ + } + +#define MAKE_FMT_CHUNK(ch, s) \ + { \ + ch.tag = MAKE_WAVE_TAG_VALUE('f', 'm', 't', ' '); \ + ch.size = s; \ + } + +#define MAKE_DATA_CHUNK(ch, s) \ + { \ + ch.tag = MAKE_WAVE_TAG_VALUE('d', 'a', 't', 'a'); \ + ch.size = s; \ + } + +#define saturate(v, min, max) \ + { \ + if ( v < min ) {v = min;} \ + else if ( v > max ) {v = max;} \ + } + +#define swap(v,t) swap_##t##_(v) + +#define swap_u16_(v) \ + { \ + v = (u16)(((v)>> 8)&0x00ff | \ + ((v)<< 8)&0xff00); \ + } + +#define swap_s16_(v) \ + { \ + v = (s16)(((v)>> 8)&0x00ff | \ + ((v)<< 8)&0xff00); \ + } + +#define swap_u32_(v) \ + { \ + v = (u32)(((v)>>24)&0x000000ff | \ + ((v)>> 8)&0x0000ff00 | \ + ((v)<< 8)&0x00ff0000 | \ + ((v)<<24)&0xff000000); \ + } + +#define swap_s32_(v) \ + { \ + v = (s32)(((v)>>24)&0x000000ff | \ + ((v)>> 8)&0x0000ff00 | \ + ((v)<< 8)&0x00ff0000 | \ + ((v)<<24)&0xff000000); \ + } + +/*---------------------------------------------------------------------------*/ +/* typedef */ +typedef struct _riff +{ + u32 tag; + u32 size; + u32 type; +} +WaveRiff; + +typedef struct _chunk +{ + u32 tag; + u32 size; +} +WaveChunk; + +typedef struct _fmt +{ + u16 fmt_id; + u16 channel; + u32 sample_rate; + u32 trans_rate; + u16 block_size; + u16 quantum_bits; +} +WaveFmt; + +typedef struct _data +{ + u32 size; + u8* buf; +} +WaveData; + +/*---------------------------------------------------------------------------*/ +/* prototype */ + +void LoadWaveCore(nn::fs::FileReader&, WaveFmt*, WaveData*, bool); +static inline void LoadWave(nn::fs::FileReader& reader, WaveFmt* fmt, WaveData* data) +{ + LoadWaveCore(reader, fmt, data, false); +} +static inline int GetWaveLength(nn::fs::FileReader& reader) +{ + WaveFmt fmt; + WaveData data; + LoadWaveCore(reader, &fmt, &data, true); + return data.size; +} +#ifndef NN_BUILD_RELEASE // Release ビルドでは HostIO は使えません。 +void WriteWaveHeader(nn::hio::CTR::HostFile& hostFile, WaveFmt* fmt, s32 size); +#endif // NN_BUILD_RELEASE + +#endif // __WAVE_HEADER__ + +/*---------------------------------------------------------------------------*/ +/* end of file */ +/*---------------------------------------------------------------------------*/ diff --git a/branches/2-1-1/sources/tests/ConsoleBackup/Exporter/OMakefile b/branches/2-1-1/sources/tests/ConsoleBackup/Exporter/OMakefile new file mode 100644 index 0000000..ef5f9f7 --- /dev/null +++ b/branches/2-1-1/sources/tests/ConsoleBackup/Exporter/OMakefile @@ -0,0 +1,63 @@ +#!/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-*.Process.MPCore.* + +include $(makePlatformDefsPath tests) + +SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include) +INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \ + ../../../common \ + ../../../ConsoleBackup \ + + + +TEST_COMMON_SOURCES[] = + ../../../ConsoleBackup/Exporter.cpp + ../../../common/Util.cpp + ../../../common/HeapManager.cpp + ../../../common/SdLogger.cpp + ../../../common/LogConsole.cpp + ../../../common/CommonLogger.cpp + ../../../common/SdMountManager.cpp + ../../../common/PlayHistoryManager.cpp + ../../../common/VersionDetect.cpp + ../../../common/HardwareStateManager.cpp + ../../../common/FileTransfer.cpp + ../../../common/SdReaderWriter.cpp + + +SOURCES_TEST[] = test_Exporter.cpp + +ROMFS_ROOT = ../../../common/romfiles + +TEST_ENVIRONMENT_PROCESSLIST = true +TEST_ENVIRONMENT_EMUMEM = true + +LIBS += libnn_test \ + libnn_mcu \ + libnn_ps \ + libnn_am \ + lib_demo \ + + +ROM_SPEC_FILE = ../../../ConsoleBackup/ConsoleBackup.rsf +DESCRIPTOR = $(HORIZON_ROOT)/resources/specfiles/_private/RepairTool.desc + + +include $(makePlatformDefsPath build.tests) + + +tests: $(TEST_TARGETS) diff --git a/branches/2-1-1/sources/tests/ConsoleBackup/Exporter/test_Exporter.cpp b/branches/2-1-1/sources/tests/ConsoleBackup/Exporter/test_Exporter.cpp new file mode 100644 index 0000000..486e320 --- /dev/null +++ b/branches/2-1-1/sources/tests/ConsoleBackup/Exporter/test_Exporter.cpp @@ -0,0 +1,113 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: test_Util.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 +#include +#include +#include +#include +#include +#include +#include + +#include "demo.h" + +#include "CommonLogger.h" +#include "HeapManager.h" +#include "Exporter.h" + +using namespace nn::test; + +class ExporterTest : public Suite { +public: + virtual bool InitializeSuite(); + virtual void FinalizeSuite(); + + ExporterTest() { + SUITE_NAME("TestUtil"); + TEST_ADD(ExporterTest::ExportTwlSaveData); + } +private: + void ExportTwlSaveData(); +}; + +namespace +{ + +const size_t s_GxHeapSize = 0x800000; + +} + +//------------------------------------------------------------------ +// Initialize/Finalize +//------------------------------------------------------------------ + +bool ExporterTest::InitializeSuite() +{ + // os の初期化 + nn::os::Initialize(); + + nn::fs::Initialize(); + + // amの初期化 + nn::am::InitializeForSystemMenu(); + + // ヒープの確保 + common::HeapManager::GetHeap()->Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize(), nn::os::ALLOCATE_OPTION_LINEAR); + + // RenderSystem の準備 + uptr heapForGx = reinterpret_cast(common::HeapManager::GetHeap()->Allocate(s_GxHeapSize)); + demo::RenderSystemDrawing renderSystem; + renderSystem.Initialize(heapForGx, s_GxHeapSize); + + // ログ描画の初期化 + common::Logger::GetLoggerInstance()->Initialize(common::CONSOLE_WIDTH, common::CONSOLE_HEIGHT, + common::CONSOLE_MAX_LINE, &renderSystem); + + return true; + +} + +void ExporterTest::FinalizeSuite() +{ +} + +//------------------------------------------------------------------ +// Test Util +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// Test Functions +//------------------------------------------------------------------ + +void ExporterTest::ExportTwlSaveData() +{ + NN_LOG("WriteTwlTitleData\n"); + ConsoleBackup::ExportTwlSaveData(); + + while (!ConsoleBackup::IsExportThreadFinished()) + { + nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(10)); + } + ConsoleBackup::FinalizeExportThread(); + +} + +NN_TEST_DEFINE_MAIN(ExporterTest) + +/*---------------------------------------------------------------------------* + End of file + *---------------------------------------------------------------------------*/ diff --git a/branches/2-1-1/sources/tests/ConsoleBackup/OMakefile b/branches/2-1-1/sources/tests/ConsoleBackup/OMakefile new file mode 100644 index 0000000..0b7f26b --- /dev/null +++ b/branches/2-1-1/sources/tests/ConsoleBackup/OMakefile @@ -0,0 +1,20 @@ +#!/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$ +#---------------------------------------------------------------------------- + +if $(IsTestBuild) + .SUBDIRS: Exporter + +DefineDefaultRules() diff --git a/branches/2-1-1/sources/tests/ConsoleRestore/OMakefile b/branches/2-1-1/sources/tests/ConsoleRestore/OMakefile new file mode 100644 index 0000000..19fef5c --- /dev/null +++ b/branches/2-1-1/sources/tests/ConsoleRestore/OMakefile @@ -0,0 +1,20 @@ +#!/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$ +#---------------------------------------------------------------------------- + +if $(IsTestBuild) + .SUBDIRS: TitleDownloader + +DefineDefaultRules() diff --git a/branches/2-1-1/sources/tests/ConsoleRestore/TitleDownloader/OMakefile b/branches/2-1-1/sources/tests/ConsoleRestore/TitleDownloader/OMakefile new file mode 100644 index 0000000..30f3b2d --- /dev/null +++ b/branches/2-1-1/sources/tests/ConsoleRestore/TitleDownloader/OMakefile @@ -0,0 +1,65 @@ +#!/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-*.Process.MPCore.* + +include $(makePlatformDefsPath tests) + +SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include) +INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \ + ../../../common \ + ../../../ConsoleRestore \ + + + +TEST_COMMON_SOURCES[] = + ../../../ConsoleRestore/TitleDownloader.cpp + ../../../ConsoleRestore/Shop.cpp + ../../../common/Util.cpp + ../../../common/HeapManager.cpp + ../../../common/SdLogger.cpp + ../../../common/LogConsole.cpp + ../../../common/CommonLogger.cpp + ../../../common/SdMountManager.cpp + ../../../common/PlayHistoryManager.cpp + ../../../common/VersionDetect.cpp + ../../../common/HardwareStateManager.cpp + ../../../common/FileTransfer.cpp + ../../../common/SdReaderWriter.cpp + + +SOURCES_TEST[] = test_TitleDownloader.cpp + +ROMFS_ROOT = ../../../common/romfiles + +TEST_ENVIRONMENT_PROCESSLIST = true +TEST_ENVIRONMENT_EMUMEM = true + +LIBS += libnn_test \ + libnn_mcu \ + libnn_ps \ + libnn_am \ + lib_demo \ + libnn_nim \ + + +ROM_SPEC_FILE = ../../../ConsoleRestore/ConsoleRestore.rsf +DESCRIPTOR = $(HORIZON_ROOT)/resources/specfiles/_private/RepairTool.desc + + +include $(makePlatformDefsPath build.tests) + + +tests: $(TEST_TARGETS) diff --git a/branches/2-1-1/sources/tests/ConsoleRestore/TitleDownloader/test_TitleDownloader.cpp b/branches/2-1-1/sources/tests/ConsoleRestore/TitleDownloader/test_TitleDownloader.cpp new file mode 100644 index 0000000..97adbe2 --- /dev/null +++ b/branches/2-1-1/sources/tests/ConsoleRestore/TitleDownloader/test_TitleDownloader.cpp @@ -0,0 +1,109 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: test_Util.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 +#include +#include +#include +#include +#include +#include +#include + +#include "demo.h" + +#include "common_Types.h" +#include "CommonLogger.h" +#include "HeapManager.h" +#include "TitleDownloader.h" + +using namespace nn::test; + +class TitleDownloaderTest : public Suite { +public: + virtual bool InitializeSuite(); + virtual void FinalizeSuite(); + + TitleDownloaderTest() { + SUITE_NAME("TestUtil"); + TEST_ADD(TitleDownloaderTest::ListUp); + } +private: + void ListUp(); +}; + +namespace +{ + +const size_t s_GxHeapSize = 0x800000; + +} + +//------------------------------------------------------------------ +// Initialize/Finalize +//------------------------------------------------------------------ + +bool TitleDownloaderTest::InitializeSuite() +{ + // os の初期化 + nn::os::Initialize(); + + nn::fs::Initialize(); + + // amの初期化 + nn::am::InitializeForSystemMenu(); + + // ヒープの確保 + common::HeapManager::GetHeap()->Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize(), nn::os::ALLOCATE_OPTION_LINEAR); + + // RenderSystem の準備 + uptr heapForGx = reinterpret_cast(common::HeapManager::GetHeap()->Allocate(s_GxHeapSize)); + demo::RenderSystemDrawing renderSystem; + renderSystem.Initialize(heapForGx, s_GxHeapSize); + + // ログ描画の初期化 + common::Logger::GetLoggerInstance()->Initialize(common::CONSOLE_WIDTH, common::CONSOLE_HEIGHT, + common::CONSOLE_MAX_LINE, &renderSystem); + + return true; + +} + +void TitleDownloaderTest::FinalizeSuite() +{ +} + +//------------------------------------------------------------------ +// Test Util +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// Test Functions +//------------------------------------------------------------------ + +void TitleDownloaderTest::ListUp() +{ + NN_LOG("WriteTwlTitleData\n"); + ConsoleRestore::TitleDownloader dl; + + dl.Start(); +} + +NN_TEST_DEFINE_MAIN(TitleDownloaderTest) + +/*---------------------------------------------------------------------------* + End of file + *---------------------------------------------------------------------------*/ diff --git a/branches/2-1-1/sources/tests/OMakefile b/branches/2-1-1/sources/tests/OMakefile new file mode 100644 index 0000000..970e68a --- /dev/null +++ b/branches/2-1-1/sources/tests/OMakefile @@ -0,0 +1,20 @@ +#!/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$ +#---------------------------------------------------------------------------- + +if $(IsTestBuild) + .SUBDIRS: common ConsoleBackup ConsoleRestore + +DefineDefaultRules() diff --git a/branches/2-1-1/sources/tests/common/OMakefile b/branches/2-1-1/sources/tests/common/OMakefile new file mode 100644 index 0000000..10686fc --- /dev/null +++ b/branches/2-1-1/sources/tests/common/OMakefile @@ -0,0 +1,20 @@ +#!/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$ +#---------------------------------------------------------------------------- + +if $(IsTestBuild) + .SUBDIRS: util + +DefineDefaultRules() diff --git a/branches/2-1-1/sources/tests/common/util/OMakefile b/branches/2-1-1/sources/tests/common/util/OMakefile new file mode 100644 index 0000000..825ae74 --- /dev/null +++ b/branches/2-1-1/sources/tests/common/util/OMakefile @@ -0,0 +1,55 @@ +#!/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-*.Process.MPCore.* + +include $(makePlatformDefsPath tests) + +SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include) +INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \ + ../../../common \ + + + +TEST_COMMON_SOURCES[] = + ../../../common/Util.cpp + ../../../common/HeapManager.cpp + ../../../common/SdLogger.cpp + ../../../common/LogConsole.cpp + ../../../common/CommonLogger.cpp + ../../../common/SdMountManager.cpp + ../../../common/VersionDetect.cpp + + +SOURCES_TEST[] = test_Util.cpp + +ROMFS_ROOT = ../../../common/romfiles + +TEST_ENVIRONMENT_PROCESSLIST = true +TEST_ENVIRONMENT_EMUMEM = true + +LIBS += libnn_test \ + libnn_mcu \ + libnn_ps \ + + +ROM_SPEC_FILE = ../../../ConsoleRestore/ConsoleRestore.rsf +DESCRIPTOR = $(HORIZON_ROOT)/resources/specfiles/_private/RepairTool.desc + + +include $(makePlatformDefsPath build.tests) + + +tests: $(TEST_TARGETS) diff --git a/branches/2-1-1/sources/tests/common/util/test_Util.cpp b/branches/2-1-1/sources/tests/common/util/test_Util.cpp new file mode 100644 index 0000000..9910ec5 --- /dev/null +++ b/branches/2-1-1/sources/tests/common/util/test_Util.cpp @@ -0,0 +1,174 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: test_Util.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 +#include +#include +#include +#include +#include +#include + +#include "Util.h" + +using namespace nn::test; + +class UtilTest : public Suite { +public: + virtual bool InitializeSuite(); + virtual void FinalizeSuite(); + + UtilTest() { + SUITE_NAME("TestUtil"); + TEST_ADD(UtilTest::AddCheckDigit); + TEST_ADD(UtilTest::GetSaveDataDirectoryRoot); + } +private: + void AddCheckDigit(); + void GetSaveDataDirectoryRoot(); +}; + +//------------------------------------------------------------------ +// Initialize/Finalize +//------------------------------------------------------------------ + +bool UtilTest::InitializeSuite() +{ + nn::fs::Initialize(); + + return true; +} + +void UtilTest::FinalizeSuite() +{ +} + +//------------------------------------------------------------------ +// Test Util +//------------------------------------------------------------------ + + +//------------------------------------------------------------------ +// Test Functions +//------------------------------------------------------------------ + +void UtilTest::AddCheckDigit() +{ + + // 通常チェックデジット + { + const char serialBase[] = "EJF10000445"; + const char serialWithCheckDigit[] = "EJF100004458"; + char serial[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN]; + std::memcpy(serial, serialBase, sizeof(serialBase)); + common::Util::AddCheckDigit(serial); + + NN_TEST_ASSERT_EQUAL(std::strcmp(serial, serialWithCheckDigit), 0); + } + + // チェックデジットが0になる場合 + { + const char serialBase[] = "CJF10004638"; + const char serialWithCheckDigit[] = "CJF100046380"; + char serial[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN]; + std::memcpy(serial, serialBase, sizeof(serialBase)); + common::Util::AddCheckDigit(serial); + + NN_TEST_ASSERT_EQUAL(std::strcmp(serial, serialWithCheckDigit), 0); + } +} + +void UtilTest::GetSaveDataDirectoryRoot() +{ + bit8 ivs[512]; + s64 ivsSize; + // 完全性検証SEEDの取得 + nn::Result result = nn::fs::MountSpecialArchive("nand:", nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND); + if (result.IsSuccess()) + { + nn::fs::FileInputStream fis; + + result = fis.TryInitialize(L"nand:/private/movable.sed"); + if (result.IsSuccess()) + { + ivsSize = fis.GetSize(); + s32 readSize; + result = fis.TryRead(&readSize, ivs, ivsSize); + if (result.IsFailure()) + { + NN_DBG_PRINT_RESULT(result); + NN_TEST_FAIL("Can't Read SDCI"); + } + } + else + { + NN_TEST_FAIL("Can't Initialize File"); + } + fis.Finalize(); + } + else + { + NN_TEST_FAIL("Can't Mount nand:"); + } + + wchar_t saveDataRootWStr[nn::fs::MAX_FILE_PATH_LENGTH]; + nn::fs::Directory dir; + result = dir.TryInitialize("nand:/data/"); + if(result.IsSuccess()) + { + nn::fs::DirectoryEntry entry; + s32 num; + result = dir.TryRead(&num, &entry, 1); + if(result.IsSuccess()) + { + if(num == 1) + { + std::memset(saveDataRootWStr, 0, sizeof(saveDataRootWStr)); + std::wcscpy(saveDataRootWStr, entry.entryName); + } + else + { + NN_TEST_FAIL("Unknown Directory exists"); + } + } + else + { + NN_TEST_FAIL("Can't Read nand:/data/"); + } + } + else + { + NN_TEST_FAIL("Can't Initialize nand:/data/"); + } + + // 一旦アンマウントしておく + nn::fs::Unmount("nand:"); + + std::wstring tmp(saveDataRootWStr); + char saveDataRootStr[nn::fs::MAX_FILE_PATH_LENGTH]; + std::wcstombs(saveDataRootStr, tmp.c_str(), tmp.size()); + + std::string sysSaveRoot; + common::Util::GetSaveDataDirectoryRoot(sysSaveRoot, &ivs, ivsSize); + + NN_TEST_ASSERT_EQUAL(std::strcmp(sysSaveRoot.c_str(), saveDataRootStr), 0); +} + + +NN_TEST_DEFINE_MAIN(UtilTest) + +/*---------------------------------------------------------------------------* + End of file + *---------------------------------------------------------------------------*/ diff --git a/branches/2-1-1/sources/tools/CmacAdder/AutoBoot.bsf b/branches/2-1-1/sources/tools/CmacAdder/AutoBoot.bsf new file mode 100644 index 0000000..104a94d Binary files /dev/null and b/branches/2-1-1/sources/tools/CmacAdder/AutoBoot.bsf differ diff --git a/branches/2-1-1/sources/tools/CmacAdder/CmacAdder.rsf b/branches/2-1-1/sources/tools/CmacAdder/CmacAdder.rsf new file mode 100644 index 0000000..8a8d47d --- /dev/null +++ b/branches/2-1-1/sources/tools/CmacAdder/CmacAdder.rsf @@ -0,0 +1,44 @@ +BasicInfo: + Title : CmacAdder + ProductCode: CmacAdder + 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 + + IoAccessControl: + - FsMountCardSpi + - FsMountNand + - FsMountTwln + +Option: + FreeProductCode: true + +CardInfo: + CardDevice: None + +Rom: + # ROM に含めるファイルシステムのルートパスを指定します。 + HostRoot: "$(ROMFS_ROOT)" \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/CmacAdder/OMakefile b/branches/2-1-1/sources/tools/CmacAdder/OMakefile new file mode 100644 index 0000000..a9d9428 --- /dev/null +++ b/branches/2-1-1/sources/tools/CmacAdder/OMakefile @@ -0,0 +1,64 @@ +#!/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.* +CTR_APPTYPE = BOTH +CTR_MAKE_DEVELOPMENT_IMAGE = true + +TARGET_PROGRAM = CmacAdder + +SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include) +INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \ + ../../common + +SOURCES[] = + main.cpp + ../../common/Util.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 + +CTR_BANNER_SPEC = AutoBoot.bsf + +ROMFS_ROOT = ../../common/romfiles + +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) diff --git a/branches/2-1-1/sources/tools/CmacAdder/banner/model.cbmd b/branches/2-1-1/sources/tools/CmacAdder/banner/model.cbmd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/tools/CmacAdder/banner/model.cbmd differ diff --git a/branches/2-1-1/sources/tools/CmacAdder/banner/sound.cbsd b/branches/2-1-1/sources/tools/CmacAdder/banner/sound.cbsd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/tools/CmacAdder/banner/sound.cbsd differ diff --git a/branches/2-1-1/sources/tools/CmacAdder/banner/unknown24x24.ctpk b/branches/2-1-1/sources/tools/CmacAdder/banner/unknown24x24.ctpk new file mode 100644 index 0000000..794b136 --- /dev/null +++ b/branches/2-1-1/sources/tools/CmacAdder/banner/unknown24x24.ctpk @@ -0,0 +1 @@ +888yyYyYyyyYyyYyyyyYyYy8 \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/CmacAdder/banner/unknown48x48.ctpk b/branches/2-1-1/sources/tools/CmacAdder/banner/unknown48x48.ctpk new file mode 100644 index 0000000..8c7da16 --- /dev/null +++ b/branches/2-1-1/sources/tools/CmacAdder/banner/unknown48x48.ctpk @@ -0,0 +1 @@ +Y8888ƺ8888YYyyYYޚ޺yY8YyYYޚyY8ޚ8 \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/CmacAdder/main.cpp b/branches/2-1-1/sources/tools/CmacAdder/main.cpp new file mode 100644 index 0000000..c8c1f4c --- /dev/null +++ b/branches/2-1-1/sources/tools/CmacAdder/main.cpp @@ -0,0 +1,294 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: main.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Aes_define.h" +#include "FileTransfer.h" +#include "CommonLogger.h" + +#include "demo.h" + +#include +#include + +#include "DrawSystemState.h" +#include "FileName.h" +#include "SimplePlayer.h" +#include "CommonLogger.h" +#include "SDMountManager.h" +#include "HeapManager.h" +#include "common_Types.h" +#include "VersionDetect.h" +#include "Util.h" +#include "CommonLogger.h" +#include "SdReaderWriter.h" + +namespace +{ + +// グラフィックスに割り当てるメモリ +const size_t s_GxHeapSize = 0x800000; + +const u32 CONSOLE_WIDTH = 38; +const u32 CONSOLE_HEIGHT = 24; +const u32 CONSOLE_MAX_LINE = 1000; + +const size_t ADD_CMAC_THREAD_STACK_SIZE = 0x4000; +nn::os::Thread s_AddCmacThread; +nn::os::StackBuffer s_AddCmacThreadStack; + +u32 s_AddCmacSuccess = 0; +u32 s_AddCmacFail = 0; + +} + +namespace CmacAdder +{ + +// ディレクトリ間のコピー +// アーカイブ越しのコピーが可能 +// アーカイブにマウントした状態で呼び出す必要あり +// 書き込み先のディレクトリはあらかじめ消去しておくこと。 +// 引数はスラッシュ付き +// TODO:分割して短くする +bool AddCmac(const wchar_t * from_path, void* buf, const size_t bufSize) +{ + using namespace common; + + nn::fs::Directory from_dir; + nn::fs::DirectoryEntry entry; + s32 numread = 0; + std::wostringstream target_from; + std::wostringstream target_to; + bool ret_value = true; + + nn::Result result = from_dir.TryInitialize(from_path); + + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + + while (1) + { + result = from_dir.TryRead(&numread, &entry, 1); + if (result.IsFailure() || numread != 1) + { + 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 << from_path << entry.entryName << L".cmac"; + + // ディレクトリの場合 + if (entry.attributes.isDirectory) + { + continue; + } + else if (std::wcscmp(entry.entryName, common::AP_SETTING_FILENAME) == 0) + { + continue; + } + // ファイルの場合 + // CMACが付いていないと考えてCMACを付加する + else + { + nn::fs::FileInputStream sdFile; + s64 filesize; + s32 readsize; + + // 読み込み対象ファイル開く + result = sdFile.TryInitialize(target_from.str().c_str()); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + // 読み込み対象ファイルのサイズ取得 + result = sdFile.TryGetSize(&filesize); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + result = sdFile.TryRead(&readsize, buf, bufSize); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + common::SdReaderWriter writer; + result = writer.WriteBufWithCmac(target_to.str().c_str(), buf, readsize); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + sdFile.Finalize(); + s_AddCmacSuccess++; + } + } + from_dir.Finalize(); + return ret_value; +} + + +void AddCmacThreadFunc() +{ + nn::Result result; + + COMMON_LOGGER("AddCmacThreadFunc Start\n"); + s_AddCmacFail = 0; + s_AddCmacSuccess = 0; + + result = common::SdMountManager::Mount(); + + size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2); + if(bufSize > common::FILE_COPY_HEAP_SIZE) + { + bufSize = common::FILE_COPY_HEAP_SIZE; + } + + common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + AddCmac((std::wstring(common::SDMC_ROOT_DIRECTORY_PATH).c_str()), + buf, bufSize); + } + + common::SdMountManager::Unmount(); + + COMMON_LOGGER("AddCmac Thread Finalize\n"); + + COMMON_LOGGER("\n\n"); + COMMON_LOGGER("AddCmac Finished, success = %d, fail = %d\n", s_AddCmacSuccess, s_AddCmacFail); +} + +extern "C" void nninitSetupDaemons(void) +{ +} + + +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); + + // ヒープの確保 + common::InitializeHeap(); + + // RenderSystem の準備 + common::HeapManager gxHeap(s_GxHeapSize); + uptr heapForGx = reinterpret_cast(gxHeap.GetAddr()); + demo::RenderSystemDrawing s_RenderSystem; + s_RenderSystem.Initialize(heapForGx, s_GxHeapSize); + + // ログ描画の初期化 + common::Logger::GetLoggerInstance()->Initialize(CONSOLE_WIDTH, CONSOLE_HEIGHT, CONSOLE_MAX_LINE, &s_RenderSystem); + + // RenderSystemを作ってからログが出せる + common::Logger::InitializeEjectThread(); + + COMMON_LOGGER("AddCmac Start\n"); + + // ボタン入力 + nn::hid::PadReader s_PadReader; + nn::hid::PadStatus padStatus; + + for(;;) + { + s_PadReader.ReadLatest(&padStatus); + + if(padStatus.trigger & nn::hid::BUTTON_A) + { + if(s_AddCmacThread.IsValid() && !s_AddCmacThread.IsAlive()) + { + s_AddCmacThread.Join(); + s_AddCmacThread.Finalize(); + } + s_AddCmacThread.Start(AddCmacThreadFunc, s_AddCmacThreadStack); + } + + // コンソールスクロール + 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(); + } + + s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); + 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); + } +} + +} diff --git a/branches/2-1-1/sources/tools/ExportedDataDecrypter/ExportedDataDecrypter.bsf b/branches/2-1-1/sources/tools/ExportedDataDecrypter/ExportedDataDecrypter.bsf new file mode 100644 index 0000000..104a94d Binary files /dev/null and b/branches/2-1-1/sources/tools/ExportedDataDecrypter/ExportedDataDecrypter.bsf differ diff --git a/branches/2-1-1/sources/tools/ExportedDataDecrypter/ExportedDataDecrypter.rsf b/branches/2-1-1/sources/tools/ExportedDataDecrypter/ExportedDataDecrypter.rsf new file mode 100644 index 0000000..2bd5d83 --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataDecrypter/ExportedDataDecrypter.rsf @@ -0,0 +1,44 @@ +BasicInfo: + Title : ExportedDataDecr + ProductCode: ExportedDataDecr + 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 + + IoAccessControl: + - FsMountCardSpi + - FsMountNand + - FsMountTwln + +Option: + FreeProductCode: true + +CardInfo: + CardDevice: None + +Rom: + # ROM に含めるファイルシステムのルートパスを指定します。 + HostRoot: "$(ROMFS_ROOT)" \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/ExportedDataDecrypter/OMakefile b/branches/2-1-1/sources/tools/ExportedDataDecrypter/OMakefile new file mode 100644 index 0000000..e2d5536 --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataDecrypter/OMakefile @@ -0,0 +1,64 @@ +#!/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.* +CTR_APPTYPE = BOTH +CTR_MAKE_DEVELOPMENT_IMAGE = true + +TARGET_PROGRAM = ExportedDataDecrypter + +SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include) +INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \ + ../../common + +SOURCES[] = + main.cpp + ../../common/Util.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 + +CTR_BANNER_SPEC = $(TARGET_PROGRAM).bsf + +ROMFS_ROOT = ../../common/romfiles + +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) diff --git a/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/model.cbmd b/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/model.cbmd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/model.cbmd differ diff --git a/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/sound.cbsd b/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/sound.cbsd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/sound.cbsd differ diff --git a/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/unknown24x24.ctpk b/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/unknown24x24.ctpk new file mode 100644 index 0000000..794b136 --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/unknown24x24.ctpk @@ -0,0 +1 @@ +888yyYyYyyyYyyYyyyyYyYy8 \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/unknown48x48.ctpk b/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/unknown48x48.ctpk new file mode 100644 index 0000000..8c7da16 --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataDecrypter/banner/unknown48x48.ctpk @@ -0,0 +1 @@ +Y8888ƺ8888YYyyYYޚ޺yY8YyYYޚyY8ޚ8 \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/ExportedDataDecrypter/main.cpp b/branches/2-1-1/sources/tools/ExportedDataDecrypter/main.cpp new file mode 100644 index 0000000..ee0c789 --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataDecrypter/main.cpp @@ -0,0 +1,620 @@ +/*---------------------------------------------------------------------------* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Aes_define.h" +#include "FileTransfer.h" +#include "CommonLogger.h" + +#include "demo.h" + +#include +#include + +#include "DrawSystemState.h" +#include "FileName.h" +#include "SimplePlayer.h" +#include "CommonLogger.h" +#include "SDMountManager.h" +#include "HeapManager.h" +#include "common_Types.h" +#include "VersionDetect.h" +#include "Util.h" +#include "CommonLogger.h" +#include "SdReaderWriter.h" + +namespace +{ + +// グラフィックスに割り当てるメモリ +const size_t s_GxHeapSize = 0x800000; + +const u32 CONSOLE_WIDTH = 38; +const u32 CONSOLE_HEIGHT = 24; +const u32 CONSOLE_MAX_LINE = 1000; + +const size_t DECRYPT_THREAD_STACK_SIZE = 0x4000; +nn::os::Thread s_DecryptThread; +nn::os::StackBuffer s_DecryptThreadStack; + +u32 s_VerifySuccess = 0; +u32 s_VerifyFail = 0; + +const wchar_t* const DECRYPT_ROOT_DIRECTORY_PATH = L"sdmc:/CTR_Console_Repair_Decrypt"; +const wchar_t* const SD_SAVEDATA_DECRYPT_ROOT_NAME = L"CTR_Console_Repair_Decrypt/CTRBackup/"; +const wchar_t* const SD_SAVEDATA_DECRYPT_TWL_PHOTO_ROOT_NAME = L"CTR_Console_Repair_Decrypt/TWLPhotoBackup/"; +const wchar_t* const SD_SAVEDATA_DECRYPT_TWL_SOUND_ROOT_NAME = L"CTR_Console_Repair_Decrypt/TWLSoundBackup/"; +const wchar_t* const SD_SAVEDATA_DECRYPT_TWL_ROOT_NAME = L"CTR_Console_Repair_Decrypt/TWLBackup/"; + + +} + +namespace tools +{ +namespace ExportedDataDecrypter +{ + +void GenerateNandPath(wchar_t* toPath, const wchar_t* fromPath) +{ + // 切り詰める + std::string tmp(common::GetCharStr(fromPath)); + std::string twlRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_ROOT_NAME)); + std::string twlPhotoRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME)); + std::string twlSoundRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME)); + std::string ctrRoot(common::GetCharStr(common::SD_SAVEDATA_ROOT_NAME)); + + std::string output; + + std::string::size_type size; + size = tmp.find(twlPhotoRoot.c_str()); + if(size == std::string::npos) + { + size = tmp.find(twlSoundRoot.c_str()); + if(size == std::string::npos) + { + size = tmp.find(ctrRoot.c_str()); + if(size == std::string::npos) + { + size = tmp.find(twlRoot.c_str()); + if(size == std::string::npos) + { + // 想定外のパスへの出力のためreturn + return; + } + else + { + output += std::string("twln:/title/"); + output += tmp.substr(size + twlRoot.size()); + } + } + else + { + output += std::string("nand:/data/"); + output += tmp.substr(size + ctrRoot.size()); + } + } + else + { + output += std::string("twls:/"); + output += tmp.substr(size + twlSoundRoot.size()); + } + } + else + { + output += std::string("twlp:/"); + output += tmp.substr(size + twlPhotoRoot.size()); + } + + s32 length = std::mbstowcs(toPath, output.c_str(), nn::fs::MAX_FILE_PATH_LENGTH); + if(length == -1) + { + NN_PANIC("failed mbstowcs"); + } +} + +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); + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + + if(std::memcmp(cmac, sdCmac, sizeof(cmac)) != 0) + { + NN_LOG("Faild. Expected CMAC:\n"); + for (u32 i = 0; i < sizeof(cmac); i++) + { + NN_LOG("%02X ", cmac[i]); + } + NN_LOG("\n"); + } + + return std::memcmp(cmac, sdCmac, sizeof(cmac)) == 0; +} + +// ディレクトリ間のコピー +// アーカイブ越しのコピーが可能 +// アーカイブにマウントした状態で呼び出す必要あり +// 書き込み先のディレクトリはあらかじめ消去しておくこと。 +// 引数はスラッシュ付き +// TODO:分割して短くする +bool DecryptDirectory(const wchar_t * from_path, const wchar_t* to_path, void* buf, + const size_t bufSize) +{ + using namespace common; + + nn::fs::Directory from_dir; + nn::fs::DirectoryEntry entry; + s32 numread = 0; + std::wostringstream target_from; + std::wostringstream target_to; + bool ret_value = true; + + nn::Result result = from_dir.TryInitialize(from_path); + + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + + while (1) + { + result = from_dir.TryRead(&numread, &entry, 1); + if (result.IsFailure() || numread != 1) + { + 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; + + + // ディレクトリの場合 + 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 (!DecryptDirectory(target_from.str().c_str(), target_to.str().c_str(), buf, bufSize)) + { + ret_value = false; + } + } + else + { + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + } + } + // ファイルの場合 + // SDカード上のファイルのCMACを検証する + else + { + nn::fs::FileInputStream sdFile; + nn::fs::FileOutputStream sdOutFile; + s64 sdFileSize; + + result = sdFile.TryInitialize(target_from.str().c_str()); + if(result.IsFailure()) + { + ret_value = false; + break; + } + + + result = sdFile.TryGetSize(&sdFileSize); + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + ret_value = false; + break; + } + else + { + + 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); + if (result.IsSuccess()) + { + result = sdFile.TryRead(&readSize, sdCmac, sizeof(sdCmac)); + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + } + else + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + + sdFile.SetPosition(0); + + + // 復号化しながらハッシュを計算する + nn::crypto::SwAesCtrContext swAesCtrContext; + swAesCtrContext.Initialize(iv, common::key, sizeof(key)); + + nn::crypto::Sha256Context context; + context.Initialize(); + + wchar_t nandPath[nn::fs::MAX_FILE_PATH_LENGTH]; + // sdパスからnandパスを生成する + GenerateNandPath(nandPath, target_from.str().c_str()); + + // NAND上のフルパスをハッシュに含めている + context.Update(nandPath, std::wcslen(nandPath) * sizeof(wchar_t)); + + size_t totalReadSize = 0; + + BackupDataHeader enc; + BackupDataHeader dec; + std::memset(&enc, 0, sizeof(enc)); + std::memset(&dec, 0, sizeof(dec)); + sdFile.TryRead(&readSize, &enc, sizeof(enc)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + if(result.IsFailure()) + { + ret_value = false; + break; + } + totalReadSize += readSize; + context.Update(&enc, sizeof(enc)); + swAesCtrContext.Decrypt(&dec, &enc, sizeof(enc)); + + // 書き込み対象ファイル作成 + s32 writeSize; + + result = nn::fs::TryCreateFile(target_to.str().c_str(), dec.size); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + result = sdOutFile.TryInitialize(target_to.str().c_str(), true); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + + while (1) + { + result = sdFile.TryRead(&readSize, buf, bufSize / 2); + totalReadSize += readSize; + + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + ret_value = false; + break; + } + else + { + if (readSize == 0) + { + ret_value = CalculateAndCompareCmac(&context, sdCmac); + if(!ret_value) + { + COMMON_LOGGER("********** Verification Failed ********** %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifyFail++; + } + else + { + COMMON_LOGGER("Success %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifySuccess++; + } + break; + } + else + { + bool readDone = false;; + + // 復号化 + result = swAesCtrContext.Decrypt(reinterpret_cast(buf) + bufSize / 2, buf, readSize); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + // SHA256Hash確認のためCMACまで読んだかどうか調べる + s32 readSizeforCmac = readSize; + if (sdFileSize - nn::crypto::AES_CMAC_MAC_SIZE < totalReadSize) + { + // 最大CMACぶんのサイズを減らす + readSizeforCmac -= totalReadSize - (sdFileSize - nn::crypto::AES_CMAC_MAC_SIZE); + readDone = true; + } + + if (readSizeforCmac != 0) + { + context.Update(buf, readSizeforCmac); + } + else + { + ret_value = CalculateAndCompareCmac(&context, sdCmac); + if (!ret_value) + { + COMMON_LOGGER( + "********** Verification Failed ********** %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifyFail++; + } + else + { + COMMON_LOGGER("Success %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifySuccess++; + } + break; + } + + s32 sdWriteSize = readSize; + // パディングまで読んでいたら書き込みサイズを減らす + if (dec.size + sizeof(dec) < totalReadSize) + { + sdWriteSize -= totalReadSize - (dec.size + sizeof(dec)); + } + + // 書き込み + result = sdOutFile.TryWrite(&writeSize, reinterpret_cast(buf) + bufSize / 2, sdWriteSize, + true); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + if(readDone) + { + ret_value = CalculateAndCompareCmac(&context, sdCmac); + if(!ret_value) + { + COMMON_LOGGER("********** Verification Failed ********** %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifyFail++; + } + else + { + COMMON_LOGGER("Success %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifySuccess++; + } + break; + } + } + } + } + sdFile.Finalize(); + sdOutFile.Finalize(); + } + } + } + from_dir.Finalize(); + return ret_value; +} + + +void DecryptThreadFunc() +{ + nn::Result result; + + COMMON_LOGGER("DecryptThreadFunc Start\n"); + s_VerifyFail = 0; + s_VerifySuccess = 0; + + result = common::SdMountManager::Mount(); + + size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2); + if(bufSize > common::FILE_COPY_HEAP_SIZE) + { + bufSize = common::FILE_COPY_HEAP_SIZE; + } + + common::SdReaderWriter sdWriter; + common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + result = nn::fs::TryDeleteDirectoryRecursively( + DECRYPT_ROOT_DIRECTORY_PATH); + + // ディレクトリが無ければ作る + nn::fs::Directory dir; + result = dir.TryInitialize(DECRYPT_ROOT_DIRECTORY_PATH); + if (result.IsFailure()) + { + result = nn::fs::TryCreateDirectory(DECRYPT_ROOT_DIRECTORY_PATH); + } + dir.Finalize(); + + result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + std::wstring(SD_SAVEDATA_DECRYPT_TWL_ROOT_NAME)).c_str()); + DecryptDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str(), + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(SD_SAVEDATA_DECRYPT_TWL_ROOT_NAME)).c_str(), + buf, bufSize); + + result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + std::wstring(SD_SAVEDATA_DECRYPT_TWL_SOUND_ROOT_NAME)).c_str()); + DecryptDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + ::std::wstring(common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME)).c_str(), + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + ::std::wstring(SD_SAVEDATA_DECRYPT_TWL_SOUND_ROOT_NAME)).c_str(), + buf, bufSize); + + result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + std::wstring(SD_SAVEDATA_DECRYPT_TWL_PHOTO_ROOT_NAME)).c_str()); + DecryptDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + ::std::wstring(common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME)).c_str(), + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + ::std::wstring(SD_SAVEDATA_DECRYPT_TWL_PHOTO_ROOT_NAME)).c_str(), + buf, bufSize); + + result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + std::wstring(SD_SAVEDATA_DECRYPT_ROOT_NAME)).c_str()); + DecryptDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(), + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(SD_SAVEDATA_DECRYPT_ROOT_NAME)).c_str(), + buf, bufSize); + } + + common::SdMountManager::Unmount(); + + COMMON_LOGGER("Verify Thread Finalize\n"); + + COMMON_LOGGER("\n\n"); + COMMON_LOGGER("Verify Finished, success = %d, fail = %d\n", s_VerifySuccess, s_VerifyFail); +} + + +} // namespace ExportedDataDecrypter +} // namespace tools + +extern "C" void nninitSetupDaemons(void) +{ +} + + +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); + + // ヒープの確保 + common::InitializeHeap(); + + // RenderSystem の準備 + common::HeapManager gxHeap(s_GxHeapSize); + uptr heapForGx = reinterpret_cast(gxHeap.GetAddr()); + demo::RenderSystemDrawing s_RenderSystem; + s_RenderSystem.Initialize(heapForGx, s_GxHeapSize); + + // ログ描画の初期化 + common::Logger::GetLoggerInstance()->Initialize(CONSOLE_WIDTH, CONSOLE_HEIGHT, CONSOLE_MAX_LINE, &s_RenderSystem); + + // RenderSystemを作ってからログが出せる + common::Logger::InitializeEjectThread(); + + COMMON_LOGGER("Decrypt Start\n"); + + // ボタン入力 + nn::hid::PadReader s_PadReader; + nn::hid::PadStatus padStatus; + + for(;;) + { + s_PadReader.ReadLatest(&padStatus); + + if(padStatus.trigger & nn::hid::BUTTON_A) + { + // SDにコピーするためのスレッドの作成 + if(s_DecryptThread.IsValid() && !s_DecryptThread.IsAlive()) + { + s_DecryptThread.Join(); + s_DecryptThread.Finalize(); + } + s_DecryptThread.Start(tools::ExportedDataDecrypter::DecryptThreadFunc, s_DecryptThreadStack); + } + + // コンソールスクロール + 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(); + } + + s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); + 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); + } +} diff --git a/branches/2-1-1/sources/tools/ExportedDataVerifier/ExportedDataVerifier.bsf b/branches/2-1-1/sources/tools/ExportedDataVerifier/ExportedDataVerifier.bsf new file mode 100644 index 0000000..104a94d Binary files /dev/null and b/branches/2-1-1/sources/tools/ExportedDataVerifier/ExportedDataVerifier.bsf differ diff --git a/branches/2-1-1/sources/tools/ExportedDataVerifier/ExportedDataVerifier.rsf b/branches/2-1-1/sources/tools/ExportedDataVerifier/ExportedDataVerifier.rsf new file mode 100644 index 0000000..f14df4d --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataVerifier/ExportedDataVerifier.rsf @@ -0,0 +1,44 @@ +BasicInfo: + Title : ExportedDataVeri + ProductCode: ExportedDataVeri + 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 + + IoAccessControl: + - FsMountCardSpi + - FsMountNand + - FsMountTwln + +Option: + FreeProductCode: true + +CardInfo: + CardDevice: None + +Rom: + # ROM に含めるファイルシステムのルートパスを指定します。 + HostRoot: "$(ROMFS_ROOT)" \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/ExportedDataVerifier/OMakefile b/branches/2-1-1/sources/tools/ExportedDataVerifier/OMakefile new file mode 100644 index 0000000..bd3d669 --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataVerifier/OMakefile @@ -0,0 +1,64 @@ +#!/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.* +CTR_APPTYPE = BOTH +CTR_MAKE_DEVELOPMENT_IMAGE = true + +TARGET_PROGRAM = ExportedDataVerifier + +SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include) +INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \ + ../../common + +SOURCES[] = + main.cpp + ../../common/Util.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 + +CTR_BANNER_SPEC = $(TARGET_PROGRAM).bsf + +ROMFS_ROOT = ../../common/romfiles + +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) diff --git a/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/model.cbmd b/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/model.cbmd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/model.cbmd differ diff --git a/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/sound.cbsd b/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/sound.cbsd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/sound.cbsd differ diff --git a/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/unknown24x24.ctpk b/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/unknown24x24.ctpk new file mode 100644 index 0000000..794b136 --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/unknown24x24.ctpk @@ -0,0 +1 @@ +888yyYyYyyyYyyYyyyyYyYy8 \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/unknown48x48.ctpk b/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/unknown48x48.ctpk new file mode 100644 index 0000000..8c7da16 --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataVerifier/banner/unknown48x48.ctpk @@ -0,0 +1 @@ +Y8888ƺ8888YYyyYYޚ޺yY8YyYYޚyY8ޚ8 \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/ExportedDataVerifier/main.cpp b/branches/2-1-1/sources/tools/ExportedDataVerifier/main.cpp new file mode 100644 index 0000000..0394d1b --- /dev/null +++ b/branches/2-1-1/sources/tools/ExportedDataVerifier/main.cpp @@ -0,0 +1,510 @@ +/*---------------------------------------------------------------------------* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Aes_define.h" +#include "FileTransfer.h" +#include "CommonLogger.h" + +#include "demo.h" + +#include +#include + +#include "DrawSystemState.h" +#include "FileName.h" +#include "SimplePlayer.h" +#include "CommonLogger.h" +#include "SDMountManager.h" +#include "HeapManager.h" +#include "common_Types.h" +#include "VersionDetect.h" +#include "Util.h" +#include "CommonLogger.h" + +namespace +{ + +// グラフィックスに割り当てるメモリ +const size_t s_GxHeapSize = 0x800000; + +const u32 CONSOLE_WIDTH = 38; +const u32 CONSOLE_HEIGHT = 24; +const u32 CONSOLE_MAX_LINE = 1000; + +const size_t VERIFY_THREAD_STACK_SIZE = 0x4000; +nn::os::Thread s_VerifyThread; +nn::os::StackBuffer s_VerifyThreadStack; + +u32 s_VerifySuccess = 0; +u32 s_VerifyFail = 0; + +} + +void GenerateNandPath(wchar_t* toPath, const wchar_t* fromPath) +{ + // 切り詰める + std::string tmp(common::GetCharStr(fromPath)); + std::string twlRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_ROOT_NAME)); + std::string twlPhotoRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME)); + std::string twlSoundRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME)); + std::string ctrRoot(common::GetCharStr(common::SD_SAVEDATA_ROOT_NAME)); + + std::string output; + + std::string::size_type size; + size = tmp.find(twlPhotoRoot.c_str()); + if(size == std::string::npos) + { + size = tmp.find(twlSoundRoot.c_str()); + if(size == std::string::npos) + { + size = tmp.find(ctrRoot.c_str()); + if(size == std::string::npos) + { + size = tmp.find(twlRoot.c_str()); + if(size == std::string::npos) + { + // 想定外のパスへの出力のためreturn + return; + } + else + { + output += std::string("twln:/title/"); + output += tmp.substr(size + twlRoot.size()); + } + } + else + { + output += std::string("nand:/data/"); + output += tmp.substr(size + ctrRoot.size()); + } + } + else + { + output += std::string("twls:/"); + output += tmp.substr(size + twlSoundRoot.size()); + } + } + else + { + output += std::string("twlp:/"); + output += tmp.substr(size + twlPhotoRoot.size()); + } + + s32 length = std::mbstowcs(toPath, output.c_str(), nn::fs::MAX_FILE_PATH_LENGTH); + if(length == -1) + { + NN_PANIC("failed mbstowcs"); + } +} + +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); + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + + if(std::memcmp(cmac, sdCmac, sizeof(cmac)) != 0) + { + NN_LOG("Faild. Expected CMAC:\n"); + for (u32 i = 0; i < sizeof(cmac); i++) + { + NN_LOG("%02X ", cmac[i]); + } + NN_LOG("\n"); + } + + return std::memcmp(cmac, sdCmac, sizeof(cmac)) == 0; +} + +// ディレクトリ間のコピー +// アーカイブ越しのコピーが可能 +// アーカイブにマウントした状態で呼び出す必要あり +// 書き込み先のディレクトリはあらかじめ消去しておくこと。 +// 引数はスラッシュ付き +// TODO:分割して短くする +bool VerifyDirectory(const wchar_t * from_path, void* buf, + const size_t bufSize) +{ + using namespace common; + + nn::fs::Directory from_dir; + nn::fs::DirectoryEntry entry; + s32 numread = 0; + std::wostringstream target_from; + bool ret_value = true; + + nn::Result result = from_dir.TryInitialize(from_path); + + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + + while (1) + { + result = from_dir.TryRead(&numread, &entry, 1); + if (result.IsFailure() || numread != 1) + { + 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; + + // ディレクトリの場合 + if (entry.attributes.isDirectory) + { + { + target_from << L"/"; + + + // 再帰処理 + if (!VerifyDirectory(target_from.str().c_str(), buf, bufSize)) + { + ret_value = false; + } + } + } + // ファイルの場合 + // SDカード上のファイルのCMACを検証する + else + { + nn::fs::FileInputStream sdFile; + s64 sdFileSize; + + result = sdFile.TryInitialize(target_from.str().c_str()); + if(result.IsFailure()) + { + ret_value = false; + break; + } + + result = sdFile.TryGetSize(&sdFileSize); + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + ret_value = false; + break; + } + else + { + + 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); + if (result.IsSuccess()) + { + result = sdFile.TryRead(&readSize, sdCmac, sizeof(sdCmac)); + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + } + else + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + + sdFile.SetPosition(0); + + + // 復号化しながらハッシュを計算する + nn::crypto::SwAesCtrContext swAesCtrContext; + swAesCtrContext.Initialize(iv, common::key, sizeof(key)); + + nn::crypto::Sha256Context context; + context.Initialize(); + + wchar_t nandPath[nn::fs::MAX_FILE_PATH_LENGTH]; + // sdパスからnandパスを生成する + GenerateNandPath(nandPath, target_from.str().c_str()); + + // NAND上のフルパスをハッシュに含めている + context.Update(nandPath, std::wcslen(nandPath) * sizeof(wchar_t)); + + size_t totalReadSize = 0; + + BackupDataHeader enc; + BackupDataHeader dec; + std::memset(&enc, 0, sizeof(enc)); + std::memset(&dec, 0, sizeof(dec)); + sdFile.TryRead(&readSize, &enc, sizeof(enc)); + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + if(result.IsFailure()) + { + ret_value = false; + break; + } + totalReadSize += readSize; + context.Update(&enc, sizeof(enc)); + swAesCtrContext.Decrypt(&dec, &enc, sizeof(enc)); + + while (1) + { + result = sdFile.TryRead(&readSize, buf, bufSize); + totalReadSize += readSize; + + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + ret_value = false; + break; + } + else + { + if (readSize == 0) + { + ret_value = CalculateAndCompareCmac(&context, sdCmac); + if(!ret_value) + { + COMMON_LOGGER("********** Verification Failed ********** %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifyFail++; + } + else + { + COMMON_LOGGER("Success %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifySuccess++; + } + break; + } + else + { + bool readDone = false;; + // CMACまで読んだかどうか + if (sdFileSize - nn::crypto::AES_CMAC_MAC_SIZE < totalReadSize) + { + readSize -= totalReadSize - (sdFileSize - nn::crypto::AES_CMAC_MAC_SIZE); + readDone = true; + } + context.Update(buf, readSize); + + if(readDone) + { + ret_value = CalculateAndCompareCmac(&context, sdCmac); + if(!ret_value) + { + COMMON_LOGGER("********** Verification Failed ********** %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifyFail++; + } + else + { + COMMON_LOGGER("Success %s\n", common::GetCharStr(target_from.str().c_str())); + s_VerifySuccess++; + } + break; + } + } + } + } + sdFile.Finalize(); + } + } + } + from_dir.Finalize(); + return ret_value; +} + + +void VerifyThreadFunc() +{ + nn::Result result; + + COMMON_LOGGER("VerifyThreadFunc Start\n"); + s_VerifyFail = 0; + s_VerifySuccess = 0; + + result = common::SdMountManager::Mount(); + + size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2); + if(bufSize > common::FILE_COPY_HEAP_SIZE) + { + bufSize = common::FILE_COPY_HEAP_SIZE; + } + + common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + + VerifyDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str(), + buf, bufSize); + + VerifyDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + ::std::wstring(common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME)).c_str(), buf, bufSize); + + VerifyDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + ::std::wstring(common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME)).c_str(), buf, bufSize); + + VerifyDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(), + buf, bufSize); + } + + common::SdMountManager::Unmount(); + + COMMON_LOGGER("Verify Thread Finalize\n"); + + COMMON_LOGGER("\n\n"); + COMMON_LOGGER("Verify Finished, success = %d, fail = %d\n", s_VerifySuccess, s_VerifyFail); +} + +extern "C" void nninitSetupDaemons(void) +{ +} + + +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); + + // ヒープの確保 + common::InitializeHeap(); + + // RenderSystem の準備 + common::HeapManager gxHeap(s_GxHeapSize); + uptr heapForGx = reinterpret_cast(gxHeap.GetAddr()); + demo::RenderSystemDrawing s_RenderSystem; + s_RenderSystem.Initialize(heapForGx, s_GxHeapSize); + + // ログ描画の初期化 + common::Logger::GetLoggerInstance()->Initialize(CONSOLE_WIDTH, CONSOLE_HEIGHT, CONSOLE_MAX_LINE, &s_RenderSystem); + + // RenderSystemを作ってからログが出せる + common::Logger::InitializeEjectThread(); + + COMMON_LOGGER("Verify Start\n"); + + // ボタン入力 + nn::hid::PadReader s_PadReader; + nn::hid::PadStatus padStatus; + + for(;;) + { + s_PadReader.ReadLatest(&padStatus); + + if(padStatus.trigger & nn::hid::BUTTON_A) + { + // SDにコピーするためのスレッドの作成 + if(s_VerifyThread.IsValid() && !s_VerifyThread.IsAlive()) + { + s_VerifyThread.Join(); + s_VerifyThread.Finalize(); + } + s_VerifyThread.Start(VerifyThreadFunc, s_VerifyThreadStack); + } + + // コンソールスクロール + 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(); + } + + s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); + 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); + } +} diff --git a/branches/2-1-1/sources/tools/FatDataEncrypter/FatDataEncrypter.bsf b/branches/2-1-1/sources/tools/FatDataEncrypter/FatDataEncrypter.bsf new file mode 100644 index 0000000..104a94d Binary files /dev/null and b/branches/2-1-1/sources/tools/FatDataEncrypter/FatDataEncrypter.bsf differ diff --git a/branches/2-1-1/sources/tools/FatDataEncrypter/FatDataEncrypter.rsf b/branches/2-1-1/sources/tools/FatDataEncrypter/FatDataEncrypter.rsf new file mode 100644 index 0000000..014621e --- /dev/null +++ b/branches/2-1-1/sources/tools/FatDataEncrypter/FatDataEncrypter.rsf @@ -0,0 +1,44 @@ +BasicInfo: + Title : FatDataEncrypter + ProductCode: FatDataEncrypter + 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 + + IoAccessControl: + - FsMountCardSpi + - FsMountNand + - FsMountTwln + +Option: + FreeProductCode: true + +CardInfo: + CardDevice: None + +Rom: + # ROM に含めるファイルシステムのルートパスを指定します。 + HostRoot: "$(ROMFS_ROOT)" \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/FatDataEncrypter/OMakefile b/branches/2-1-1/sources/tools/FatDataEncrypter/OMakefile new file mode 100644 index 0000000..569542e --- /dev/null +++ b/branches/2-1-1/sources/tools/FatDataEncrypter/OMakefile @@ -0,0 +1,64 @@ +#!/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.* +CTR_APPTYPE = BOTH +CTR_MAKE_DEVELOPMENT_IMAGE = true + +TARGET_PROGRAM = FatDataEncrypter + +SAMPLED_DEMOS_COMMON_INCLUDE_DIR = $(dir $(HORIZON_ROOT)/../CTR/SampleDemos/common/include) +INCLUDES += $(SAMPLED_DEMOS_COMMON_INCLUDE_DIR) \ + ../../common + +SOURCES[] = + main.cpp + ../../common/Util.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 + +CTR_BANNER_SPEC = $(TARGET_PROGRAM).bsf + +ROMFS_ROOT = ../../common/romfiles + +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) diff --git a/branches/2-1-1/sources/tools/FatDataEncrypter/banner/model.cbmd b/branches/2-1-1/sources/tools/FatDataEncrypter/banner/model.cbmd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/tools/FatDataEncrypter/banner/model.cbmd differ diff --git a/branches/2-1-1/sources/tools/FatDataEncrypter/banner/sound.cbsd b/branches/2-1-1/sources/tools/FatDataEncrypter/banner/sound.cbsd new file mode 100644 index 0000000..f1c7b62 Binary files /dev/null and b/branches/2-1-1/sources/tools/FatDataEncrypter/banner/sound.cbsd differ diff --git a/branches/2-1-1/sources/tools/FatDataEncrypter/banner/unknown24x24.ctpk b/branches/2-1-1/sources/tools/FatDataEncrypter/banner/unknown24x24.ctpk new file mode 100644 index 0000000..794b136 --- /dev/null +++ b/branches/2-1-1/sources/tools/FatDataEncrypter/banner/unknown24x24.ctpk @@ -0,0 +1 @@ +888yyYyYyyyYyyYyyyyYyYy8 \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/FatDataEncrypter/banner/unknown48x48.ctpk b/branches/2-1-1/sources/tools/FatDataEncrypter/banner/unknown48x48.ctpk new file mode 100644 index 0000000..8c7da16 --- /dev/null +++ b/branches/2-1-1/sources/tools/FatDataEncrypter/banner/unknown48x48.ctpk @@ -0,0 +1 @@ +Y8888ƺ8888YYyyYYޚ޺yY8YyYYޚyY8ޚ8 \ No newline at end of file diff --git a/branches/2-1-1/sources/tools/FatDataEncrypter/main.cpp b/branches/2-1-1/sources/tools/FatDataEncrypter/main.cpp new file mode 100644 index 0000000..f09c8e1 --- /dev/null +++ b/branches/2-1-1/sources/tools/FatDataEncrypter/main.cpp @@ -0,0 +1,433 @@ +/*---------------------------------------------------------------------------* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Aes_define.h" +#include "FileTransfer.h" +#include "CommonLogger.h" + +#include "demo.h" + +#include +#include + +#include "DrawSystemState.h" +#include "FileName.h" +#include "SimplePlayer.h" +#include "CommonLogger.h" +#include "SDMountManager.h" +#include "HeapManager.h" +#include "common_Types.h" +#include "VersionDetect.h" +#include "Util.h" +#include "CommonLogger.h" + +namespace +{ + +// グラフィックスに割り当てるメモリ +const size_t s_GxHeapSize = 0x800000; + +const u32 CONSOLE_WIDTH = 38; +const u32 CONSOLE_HEIGHT = 24; +const u32 CONSOLE_MAX_LINE = 1000; + +const size_t VERIFY_THREAD_STACK_SIZE = 0x4000; +nn::os::Thread s_EncryptThread; +nn::os::StackBuffer s_EncryptThreadStack; + +u32 s_EncryptSuccess = 0; +u32 s_EncryptFail = 0; + +} + +void GenerateNandPath(wchar_t* toPath, const wchar_t* fromPath) +{ + // 切り詰める + std::string tmp(common::GetCharStr(fromPath)); + std::string twlRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_ROOT_NAME)); + std::string twlPhotoRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME)); + std::string twlSoundRoot(common::GetCharStr(common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME)); + std::string ctrRoot(common::GetCharStr(common::SD_SAVEDATA_ROOT_NAME)); + + std::string output; + + std::string::size_type size; + size = tmp.find(twlPhotoRoot.c_str()); + if(size == std::string::npos) + { + size = tmp.find(twlSoundRoot.c_str()); + if(size == std::string::npos) + { + size = tmp.find(ctrRoot.c_str()); + if(size == std::string::npos) + { + size = tmp.find(twlRoot.c_str()); + if(size == std::string::npos) + { + // 想定外のパスへの出力のためreturn + return; + } + else + { + output += std::string("twln:/title/"); + output += tmp.substr(size + twlRoot.size()); + } + } + else + { + output += std::string("nand:/data/"); + output += tmp.substr(size + ctrRoot.size()); + } + } + else + { + output += std::string("twls:/"); + output += tmp.substr(size + twlSoundRoot.size()); + } + } + else + { + output += std::string("twlp:/"); + output += tmp.substr(size + twlPhotoRoot.size()); + } + + s32 length = std::mbstowcs(toPath, output.c_str(), nn::fs::MAX_FILE_PATH_LENGTH); + if(length == -1) + { + NN_PANIC("failed mbstowcs"); + } +} + +// ディレクトリ間のコピー +// アーカイブ越しのコピーが可能 +// アーカイブにマウントした状態で呼び出す必要あり +// 書き込み先のディレクトリはあらかじめ消去しておくこと。 +// 引数はスラッシュ付き +// TODO:分割して短くする +bool EncryptDirectory(const wchar_t * from_path, void* buf, + const size_t bufSize) +{ + using namespace common; + + nn::fs::Directory from_dir; + nn::fs::DirectoryEntry entry; + s32 numread = 0; + std::wostringstream target_from; + bool ret_value = true; + + nn::Result result = from_dir.TryInitialize(from_path); + + if (result.IsFailure()) + { + COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); + return false; + } + + while (1) + { + result = from_dir.TryRead(&numread, &entry, 1); + if (result.IsFailure() || numread != 1) + { + 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; + + // ディレクトリの場合 + if (entry.attributes.isDirectory) + { + { + target_from << L"/"; + + + // 再帰処理 + if (!EncryptDirectory(target_from.str().c_str(), buf, bufSize)) + { + ret_value = false; + } + } + } + // ファイルの場合 + // SDカード上のファイルを暗号化してCMACを出力する + else + { + nn::fs::FileInputStream sdFile; + s64 filesize; + s32 readsize; + + // 読み込み対象ファイル開く + result = sdFile.TryInitialize(target_from.str().c_str()); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + // 読み込み対象ファイルのサイズ取得 + result = sdFile.TryGetSize(&filesize); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + nn::crypto::SwAesCtrContext swAesCtrContext; + swAesCtrContext.Initialize(iv, common::key, sizeof(key)); + + size_t totalReadSize = 0; + nn::crypto::Sha256Context context; + context.Initialize(); + + // ファイルサイズをヘッダに書いておく + { + wchar_t nandPath[nn::fs::MAX_FILE_PATH_LENGTH]; + // sdパスからnandパスを生成する + GenerateNandPath(nandPath, target_from.str().c_str()); + + // 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 = filesize; + result = swAesCtrContext.Encrypt(&enc, &header, sizeof(header)); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + context.Update(&enc, sizeof(enc)); + } + + while (1) + { + // バッファの後半半分を暗号・復号用に使う + result = sdFile.TryRead(&readsize, buf, bufSize / 2); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + totalReadSize += readsize; + + if (readsize == 0) + { + { + 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); + + NN_LOG("cmac:\n"); + for(u32 i = 0; i < sizeof(cmac); i++) + { + NN_LOG("%02X ", cmac[i]); + } + NN_LOG("\n"); + } + + break; + } + else + { + { + NN_LOG("EncryptSize = %d\n", readsize); + + u8 paddingSize = 0; + common::AddPkcsPadding(&paddingSize, reinterpret_cast(buf), bufSize / 2, &readsize); + + // 暗号化後SHA256を計算しつつ書き込み + result = swAesCtrContext.Encrypt(reinterpret_cast(buf) + bufSize / 2, buf, readsize); + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + context.Update(reinterpret_cast(buf) + bufSize / 2, readsize); + + // 事前計算したファイルサイズに一致させるためパディング分減算 + readsize -= paddingSize; + } + + COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result); + + } + } + sdFile.Finalize(); + } + } + from_dir.Finalize(); + return ret_value; +} + + +void EncryptThreadFunc() +{ + nn::Result result; + + COMMON_LOGGER("EncryptThreadFunc Start\n"); + s_EncryptFail = 0; + s_EncryptSuccess = 0; + + result = common::SdMountManager::Mount(); + + size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2); + if(bufSize > common::FILE_COPY_HEAP_SIZE) + { + bufSize = common::FILE_COPY_HEAP_SIZE; + } + + common::HeapManager heap(bufSize, AES_BLOCK_SIZE * 2); + void* buf = heap.GetAddr(); + if (buf != NULL) + { + + EncryptDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str(), + buf, bufSize); + + EncryptDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + ::std::wstring(common::SD_SAVEDATA_TWL_SOUND_ROOT_NAME)).c_str(), buf, bufSize); + + EncryptDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + + ::std::wstring(common::SD_SAVEDATA_TWL_PHOTO_ROOT_NAME)).c_str(), buf, bufSize); + + EncryptDirectory( + (std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME)).c_str(), + buf, bufSize); + } + + common::SdMountManager::Unmount(); + + COMMON_LOGGER("Encrypt Thread Finalize\n"); + + COMMON_LOGGER("\n\n"); + COMMON_LOGGER("Encrypt Finished, success = %d, fail = %d\n", s_EncryptSuccess, s_EncryptFail); +} + +extern "C" void nninitSetupDaemons(void) +{ +} + + +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); + + // ヒープの確保 + common::InitializeHeap(); + + // RenderSystem の準備 + common::HeapManager gxHeap(s_GxHeapSize); + uptr heapForGx = reinterpret_cast(gxHeap.GetAddr()); + demo::RenderSystemDrawing s_RenderSystem; + s_RenderSystem.Initialize(heapForGx, s_GxHeapSize); + + // ログ描画の初期化 + common::Logger::GetLoggerInstance()->Initialize(CONSOLE_WIDTH, CONSOLE_HEIGHT, CONSOLE_MAX_LINE, &s_RenderSystem); + + // RenderSystemを作ってからログが出せる + common::Logger::InitializeEjectThread(); + + COMMON_LOGGER("Encrypt Start\n"); + + // ボタン入力 + nn::hid::PadReader s_PadReader; + nn::hid::PadStatus padStatus; + + for(;;) + { + s_PadReader.ReadLatest(&padStatus); + + if(padStatus.trigger & nn::hid::BUTTON_A) + { + // SDにコピーするためのスレッドの作成 + if(s_EncryptThread.IsValid() && !s_EncryptThread.IsAlive()) + { + s_EncryptThread.Join(); + s_EncryptThread.Finalize(); + } + s_EncryptThread.Start(EncryptThreadFunc, s_EncryptThreadStack); + } + + // コンソールスクロール + 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(); + } + + s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); + 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); + } +} diff --git a/branches/2-1-1/sources/tools/OMakefile b/branches/2-1-1/sources/tools/OMakefile new file mode 100644 index 0000000..2d83e1f --- /dev/null +++ b/branches/2-1-1/sources/tools/OMakefile @@ -0,0 +1,16 @@ +#!/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: $(glob D, *)