ctr_Repair/trunk/CardSaveData/ToSD/body/source/main.cpp

692 lines
22 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*---------------------------------------------------------------------------*
Project: Horizon
File: main.cpp
Copyright (C)2010 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.
*---------------------------------------------------------------------------*/
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <nn.h>
//#include <nn/os.h>
#include <nn/applet.h>
#include <nn/ndm.h>
//#include <nn/ndm/ndm_DebugControl.h>
#include <nn/fs/ctr/mpcore/fs_FileSystemBasePrivate.h>
#include <nn/fs/fs_Parameters.h>
#include "../../../common/savefile/savefile.h"
#include "../../../common/savefile/savedata.h"
#include "../../../common/savefile/sdmc.h"
#include "../../../common/common.h"
#include "./screen/screen.h"
nn::fnd::ExpHeap appHeap;
uptr heapForGx;
myResult errRes;
SaveData savedata;
nn::os::LightEvent ejectEvnt(false);
nn::os::LightEvent insEvnt(false);
Sdmc exsave;
nn::os::LightEvent ejectEvntSd(false);
nn::os::LightEvent insEvntSd(false);
//バックアップの状態
bool Active,Formatted;
bool exActive;
tArcInfo arcInfo,arcInfo_ex;//アーカイブ情報
//Top画面エラー表示
int tmerr;
//結果
typedef enum {
SUCCESS
,ERROR
,CANCEL
,INSEXIT
}RetCode;
//挿抜イベント時に設定
typedef enum {
InEx_None
,InEx_InsCard
,InEx_EjcCard
,InEx_InsSd
,InEx_EjcSd
}tIsInsEject;
tIsInsEject isInsEject;
extern u8 scr_evnt;
void WaitUI();
void PutError(ErcDev dev,int cd=0);
bool CheckInsExit();
//終了処理
void endfunc()
{
nn::fs::UnregisterCardEjectedEvent();
nn::fs::UnregisterCardInsertedEvent();
ejectEvnt.Finalize();
insEvnt.Finalize();
nn::fs::UnregisterSdmcEjectedEvent();
nn::fs::UnregisterSdmcInsertedEvent();
ejectEvntSd.Finalize();
insEvntSd.Finalize();
savedata.Finalize();
exsave.Finalize();
ScrFinalize();
}
//エラー停止
void failstop()
{
NN_LOG("fail %d,stop\n",errRes);
finish();
}
char sts[128];
//エラー表示
void PutError(ErcDev dev,int cd)
{
int desc,code;
nn::Result res;
switch (dev)
{
case ERC_DEV_CARD: res = savedata.LastNnResult;break;
case ERC_DEV_OUT: res = exsave.LastNnResult;break;
}
if ((cd ==0 ) && (dev != ERC_DEV_OTHER))
{
desc = res.GetDescription();
if (desc < 100 ) code = ERC_UNKNOWN;//キー検索完了 .. ありえない
else if (desc < 180 ) code = ERC_READ;//ファイルが見つからないか不正
else if (desc < 200 ) code = ERC_WRITE_OW;//ファイルが存在 .. 削除失敗?
else if (desc < 220 ) code = ERC_WRITE_NS;//空きが無い
else if (desc < 260 ) code = ERC_ACCESS;//操作拒否
else if (desc < 280 ) code = ERC_WRITE_PROTECT;//書き込み禁止
else if (desc < 340 ) code = ERC_ACCESS;//アクセスエラー
else if (desc < 390 ) code = ERC_FORMAT;//フォーマットエラー
else if (desc < 400 ) code = ERC_SDK_VERIFI;//改竄
else if (desc < 580 ) code = ERC_ROM;//ROM情報エラー
else if (desc < 590 ) code = ERC_RETRY;//リトライ要求
else if (desc < 600 ) code = ERC_UNKNOWN;//CCI,CXI不正 .. ありえない
else if (desc < 900 ) code = ERC_EXEC;//実行時エラー、ソフトバグ
else code = ERC_FATAL;//本体に問題の可能性
}else code = cd;
if (desc>=600){
sprintf(sts,"desc %d",desc);
}else{
sprintf(sts,"ERROR %d",dev+code);
}
scr_Status(sts,COLOR_RED);
}
wchar_t file_pathw[MAX_PATH_LENGTH];
char file_path[MAX_PATH_LENGTH];
//ドライバの仕様で速度的に4バイトアラインした方がいい(SDK 0.14.23 時点)
char fileBuffer[512] NN_ATTRIBUTE_ALIGN(4);//検証が512単位なので
char fileBuffer_ex[512] NN_ATTRIBUTE_ALIGN(4);
#define FILEBUFF_SIZE sizeof(fileBuffer)
//デバグ用ウエイト
void waitSec(int sec)
{
nn::os::Tick tm,tn;
tm = nn::os::Tick::GetSystemCurrent();
while(1)
{
tn = nn::os::Tick::GetSystemCurrent()-tm;
if(tn.ToTimeSpan().GetSeconds() > sec)break;
}
}
//保存先のディレクトリ削除
bool TryDeleteDir()
{
nn::Result resbk = exsave.LastNnResult;
if(exsave.Delete()==false)
{
//フォルダ削除に失敗したら手削除
strcpy(sts,"Please delete folder[ ");
strcat(sts,exsave.DirName);//フォルダ名
strcat(sts," ]");
scr_Status(sts,COLOR_RED);
return false;
}
exsave.LastNnResult = resbk;
return true;
}
//------------------------------------------------------------- Verifi
bool Verifi()
{
myResult res;
int ct=0,msize,rsize,i;
s64 total=0;
if (arcInfo.FileCount == 0)return true;//ファイル無し
//セーブデータのマウント
scr_Status("Mount SaveData",COLOR_YELLO);
res = savedata.Mount();
if(res != RESULT_OK)return false;
scr_Status("Mount SD",COLOR_YELLO);
res = exsave.Mount();
if(res != RESULT_OK)return false;
//ファイル比較
scr_Status("file compairing",COLOR_YELLO);
savedata.ResetPath();
s64 fsize;
res = RESULT_OK;
while(res==RESULT_OK){
if(CheckInsExit())break;//挿抜による中断
res = savedata.GetPath(file_pathw);
if (res != RESULT_OK)break;
if (file_pathw[0] == 0)break;//root then end
if (ct>=arcInfo.FileCount)
{
res = RESULT_FAIL;
break;
}
if(CheckInsExit())break;//挿抜による中断
scr_CountPerMax(ct,arcInfo.FileCount);
if (savedata.Open(file_pathw)==false)
{
res = RESULT_FAIL_OPEN;
break;
}
fsize = savedata.FileSize;
total += fsize;
if(CheckInsExit())break;//挿抜による中断
if (exsave.Open(file_pathw)==false)
{
res = RESULT_FAIL_OPEN;
break;
}
msize=fsize;
while(fsize)
{
if(msize > FILEBUFF_SIZE * 2){//サイズが大きい場合にゲージ表示
scr_CountPerMax2(msize-fsize,msize,0);
}
if (fsize>FILEBUFF_SIZE)
{
rsize = FILEBUFF_SIZE;
fsize -= FILEBUFF_SIZE;
}else{
rsize = fsize;
fsize = 0;
}
if(CheckInsExit())break;//挿抜による中断
if(savedata.Read(fileBuffer,rsize) != rsize )
{
if(nn::fs::ResultVerificationFailed::Includes(savedata.LastNnResult))
{
for ( i = 0; i < rsize; i++)
{
fileBuffer[i] = 0;//0埋め
}
}else{
res = RESULT_FAIL_READ;
break;
}
}
if(CheckInsExit())break;//挿抜による中断
if(exsave.Read(fileBuffer_ex,rsize) != rsize )
{
res = RESULT_FAIL_READ;
break;
}
}
savedata.Close();
exsave.Close();
if (res != RESULT_OK)break;
if(isInsEject != InEx_None )break;//挿抜による中断
for (i=0;i<rsize;i++)if (fileBuffer[i]!=fileBuffer_ex[i]){
res = RESULT_FAIL;
break;
}
ct++;
}
savedata.Close();
exsave.Close();
savedata.Unmount();
exsave.Unmount();
return res == RESULT_OK;
}
//---------------------------------------------------------------------- CARD to SD
RetCode Card2Sd()
{
myResult res;
int ct=0,msize,rsize;
s64 total=0;
scr_BackupYesNo();//実行確認
WaitUI();//入力待ち
if(isInsEject != InEx_None )return INSEXIT;//挿抜による中断
if (scr_evnt != EVNT_YES)return CANCEL;//キャンセル
scr_Backup();//画面表示
scr_Status("Mount SaveData",COLOR_YELLO);
//セーブデータのマウント
res = savedata.Mount();
if(res != RESULT_OK){
PutError(ERC_DEV_CARD);
return ERROR;
}
scr_Status("Get Dir",COLOR_YELLO);
if(savedata.GetInfo(&arcInfo)==false)
{
savedata.Unmount();
PutError(ERC_DEV_CARD);
return ERROR;
}
if (arcInfo.FileCount == 0)//ファイルが無い
{
scr_Status("no files",COLOR_YELLO);
savedata.Unmount();
return SUCCESS;//何もしない
}else{
//保存先ディレクトリ作成
scr_Status("Create Dir",COLOR_YELLO);
if (exsave.Create() == false)
{
savedata.Unmount();
if(TryDeleteDir())PutError(ERC_DEV_OUT);
return ERROR;
}
//ファイルコピー
scr_Status("file copying",COLOR_SKY);
savedata.ResetPath();
s64 fsize;
res = RESULT_OK;
while(res==RESULT_OK){
if(CheckInsExit())break;//挿抜による中断
res = savedata.GetPath(file_pathw);
if (res != RESULT_OK)
{
if (res == RESULT_DIR_LEVEL_OVER){
PutError(ERC_DEV_CARD,ERC_DIRDEPTH);
break;
}
if (res == RESULT_PATH_LENGTH_OVER){
PutError(ERC_DEV_CARD,ERC_PATH);
break;
}
res = RESULT_FAIL_OPEN;
break;
}
if (file_pathw[0] == 0)break;//root then end
if (ct>=arcInfo.FileCount)
{
res = RESULT_FAIL;
break;
}
if(CheckInsExit())break;//挿抜による中断
scr_CountPerMax(ct,arcInfo.FileCount);
if (savedata.Open(file_pathw)==false)
{
res = RESULT_FAIL_OPEN;
break;
}
fsize = savedata.FileSize;
total += fsize;
if(CheckInsExit())break;//挿抜による中断
if (exsave.OpenW(file_pathw,fsize)==false)
{
res = RESULT_FAIL_OPENW;
break;
}
msize=fsize;
while(fsize)
{
if(msize > FILEBUFF_SIZE * 2){//サイズが大きい場合にゲージ表示
scr_CountPerMax2(msize-fsize,msize,0);
}
if (fsize>FILEBUFF_SIZE)
{
rsize = FILEBUFF_SIZE;
fsize -= FILEBUFF_SIZE;
}else{
rsize = fsize;
fsize = 0;
}
if(CheckInsExit())break;//挿抜による中断
if(savedata.Read(fileBuffer,rsize) != rsize )
{
//中身のデータが作成サイズに満たない場合に検証エラーとなる対策
//読めないブロックは置き換える
//検証は512単位でされるので読めてるとこまで置き換えないよう
//リードサイズは512にしておく
if(nn::fs::ResultVerificationFailed::Includes(savedata.LastNnResult))
{
for (int i = 0; i < rsize; i++)
{
fileBuffer[i] = 0;//0埋め
}
}else{
res = RESULT_FAIL_READ;
break;
}
}
if(CheckInsExit())break;//挿抜による中断
if(exsave.Write(fileBuffer,rsize) != rsize )
{
res = RESULT_FAIL_WRITE;
break;
}
}
savedata.Close();
exsave.CloseW();
if(isInsEject != InEx_None )break;//挿抜による中断
ct++;
}
savedata.Close();
exsave.CloseW();
}
savedata.Unmount();
exsave.Unmount();
//結果
if(isInsEject != InEx_None )
{//挿抜による中断
TryDeleteDir();
return INSEXIT;
}else{
if (res == RESULT_OK)
{
if(Verifi())
{
if (exsave.WriteSys(&arcInfo))
{//フォーマットパラメータなど情報ファイル
if(CheckInsExit()==false)
{
if (exsave.GetInfo(&arcInfo_ex))
{ //リードチェック
if ((arcInfo.DirEntry != arcInfo_ex.DirEntry) ||
(arcInfo.FileEntry != arcInfo_ex.FileEntry) ||
(arcInfo.DirCount != arcInfo_ex.DirCount) ||
(arcInfo.FileCount != arcInfo_ex.FileCount) ||
(arcInfo.Dup != arcInfo_ex.Dup))res = RESULT_FAIL_WRITE;
}else res = RESULT_FAIL_WRITE;
}else res = RESULT_FAIL_WRITE;
}else res = RESULT_FAIL_WRITE;
}else res = RESULT_FAIL_VERIFI;
}
if (res != RESULT_OK)
{
if (TryDeleteDir())
{
if ((res == RESULT_FAIL_WRITE) || (res== RESULT_FAIL_OPENW)) PutError(ERC_DEV_OUT);
else if ((res == RESULT_FAIL_READ) || (res== RESULT_FAIL_OPEN)) PutError(ERC_DEV_CARD);
else if (res == RESULT_FAIL_VERIFI) PutError(ERC_DEV_OUT,ERC_VERIFI);
else PutError(ERC_DEV_OTHER);
}
}else
{
strcpy(sts,"output folder [ ");
strcat(sts,exsave.DirName);//保存先
strcat(sts," ]");
scr_Status(sts,COLOR_WHITE);
scr_CountPerMax(ct,arcInfo.FileCount);//ファイル数
scr_CountPerMax2(0,0,total);//総サイズ
return SUCCESS;
}
}
return ERROR;
}
bool mkdir;
//--------------------------------------------------------------- セーブデータの情報取得
//呼ぶ前に tmerr のクリアを忘れない事
void CheckSaveDataState()
{
myResult myres;
Formatted = false;//フォーマット
Active = false;
//failveri = false;
if (savedata.GetPrdCode())
{
myres = savedata.IsExist();
if (myres != RESULT_FAIL)
{
Active = true;//アクセス可能
switch(myres){
case RESULT_OK:
Formatted=true;
break;
case RESULT_NO_MEDIA:
tmerr |= SDATA_ERRPUT_MEDIA;
break;
case RESULT_NOT_FAUND:
break;
case RESULT_SDK_VERIFI:
//failveri = true;
tmerr |= SDATA_ERRPUT_VERIFI;
break;
default:
break;
}
}
}
scr_PrdCode(savedata.PrdCode);
}
void CheckExSaveState()
{
exActive = nn::fs::IsSdmcInserted();
}
//------------------------------------------------------------ 挿抜チェック
bool CheckInsExit()
{
if (ejectEvnt.TryWait()){
//CARD抜け
CheckSaveDataState();
isInsEject = InEx_EjcCard;
return true;
}
if (insEvnt.TryWait()){
//CARD挿入
CheckSaveDataState();
isInsEject = InEx_InsCard;
return true;
}
if (ejectEvntSd.TryWait()){
//SD抜け
CheckExSaveState();
isInsEject = InEx_EjcSd;
return true;
}
if (insEvntSd.TryWait()){
//SD挿入
CheckExSaveState();
isInsEject = InEx_InsSd;
return true;
}
return false;
}
//---------------------------------------------------------------- 入力待ち
void WaitUI()
{
tmerr = 0;
scr_Draw();//画面更新
scr_evnt = EVNT_NONE;
while(scr_evnt == EVNT_NONE)
{
nn::os::Thread::Yield();//スレッド実行
//scr_GetEvnt();//入力イベント
CheckSysBreak();//中断処理
// int i = nn::ndm::GetDaemonStatus( nn::ndm::DN_CEC );
// if (i !=3 )NN_LOG("DN_CEC %d\n",i);
// i = nn::ndm::GetDaemonStatus( nn::ndm::DN_BOSS );
// if (i !=3 )NN_LOG("DN_BOSS %d\n",i);
// i = nn::ndm::GetDaemonStatus( nn::ndm::DN_NIM );
// if (i !=3 )NN_LOG("DN_NIM %d\n",i);
// i = nn::ndm::GetDaemonStatus( nn::ndm::DN_FRIENDS );
// if (i !=3 )NN_LOG("DN_FRIENDS %d\n",i);
//挿抜を検知したら中断して抜ける
//トップ以外ではトップメニューへ戻るようする
if (CheckInsExit())return;
}
ScrClr();//画面消去
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(500));//チャタ対策
}
//---------------------- main loop --------------------------
void nnMain()
{
RetCode retc;
isInsEject = InEx_None;
//NN_LOG("Start\n");
nn::os::Initialize();
nn::fs::Initialize();
//DEA-SUPにて推奨のフリーズ暫定対策無線デーモンを停止 (2011.3.1 現在)
//ただし、スリープ時は止まらない
//心配なら本体スイッチで切っとく
nn::ndm::Initialize();
nn::ndm::SuspendScheduler();
//中断処理の準備
InitSysBreak((uptr)endfunc);
// グラフィックスライブラリの初期化は、以降で行わなければならない
// 他、アプリケーションの初期化処理
nn::applet::DisableSleep();//スリープ非対応
//Heap
appHeap.Initialize(nn::os::GetDeviceMemoryAddress(),
nn::os::GetDeviceMemorySize(), nn::os::ALLOCATE_OPTION_LINEAR);
const u32 GxHeapSize = 0x800000;
heapForGx = reinterpret_cast<uptr>(appHeap.Allocate(GxHeapSize));
//画面初期化
if (ScrInitialize(heapForGx,GxHeapSize) == false)failstop();
ejectEvnt.ClearSignal();
insEvnt.ClearSignal();
nn::fs::RegisterCardEjectedEvent(&ejectEvnt);
nn::fs::RegisterCardInsertedEvent(&insEvnt);
ejectEvntSd.ClearSignal();
insEvntSd.ClearSignal();
nn::fs::RegisterSdmcEjectedEvent(&ejectEvntSd);
nn::fs::RegisterSdmcInsertedEvent(&insEvntSd);
// スリープ要求に対する返答を有効にする
// また、蓋の状態チェックを行い蓋が閉じられているならスリープ要求が発生する
//nn::applet::EnableSleep(true);
extern u8 scr_evnt;
while(1)
{
tmerr = 0;
CheckSaveDataState(); //セーブデータの状態取得
CheckExSaveState(); //SD挿入状態
scr_TopMenu(Formatted,Active,exActive,tmerr);
WaitUI();//入力待ち
if (isInsEject != InEx_None){
ScrClr();//画面消去
isInsEject= InEx_None;
}else
switch(scr_evnt)
{
case EVNT_SEL_READ://リード
NN_LOG("select read\n");
retc = Card2Sd();
switch (retc)
{
case SUCCESS:
//CheckExSaveState(); //状態の更新
scr_ResultQuit("Success",COLOR_GREEN);//成功とQuitボタン
break;
case INSEXIT:
//scr_InsExitQuit();//挿抜検知表示 & Quit
ScrClr();//画面消去
scr_Backup();
if (isInsEject == InEx_EjcCard)PutError(ERC_DEV_CARD,ERC_DEVICE);
else if (isInsEject == InEx_EjcSd)PutError(ERC_DEV_OUT,ERC_DEVICE);
else PutError(ERC_DEV_OTHER);
scr_ResultQuit("Break",COLOR_RED);//エラーとQuitボタン
break;
default://errors
scr_ResultQuit("Failed",COLOR_RED);//エラーとQuitボタン
break;
}
if (retc == CANCEL)break;
while(1){
WaitUI();
if (isInsEject != InEx_None){
isInsEject = InEx_None;
}
if(scr_evnt==EVNT_QUIT)break;
if(scr_evnt==EVNT_PUSH_B)break;
}
break;
case EVNT_PUSH_LEFT_X:// ------------------------------------- LEFT + X
//バックアップ削除
scr_DelConf();//実行確認
WaitUI();
if (scr_evnt != EVNT_YES)break;
exsave.DeleteAll();//全削除
//CheckExSaveState(); //状態更新
break;
}
}//while()
}
/*---------------------------------------------------------------------------*
End of file
*---------------------------------------------------------------------------*/