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

604 lines
20 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/sdmcwo.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);
Sdmcwo 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];
wchar_t file_pathw2[MAX_PATH_LENGTH];
char file_path[MAX_PATH_LENGTH];
//カゲマイ報告の速度実測でFSでバイトアライン有利(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;
}
//---------------------------------------------------------------------- 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 Directry",COLOR_YELLO);
if(savedata.GetInfo(&arcInfo)==false)
{
savedata.Unmount();
PutError(ERC_DEV_CARD);
return ERROR;
}
strcpy(arcInfo.Pcode,savedata.PrdCode);
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;//ルートなら終了
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;//挿抜による中断
//SDで支障あるパス名の場合は別ファイルに格納する
exsave.GetRootPath(file_pathw2);//格納先ルート取得
wcscat(file_pathw2,file_pathw);//実パス名に変換
if (CheckPath(file_pathw2)==false)//パス名チェック
{
if (exsave.OpenVnfW(file_pathw,fsize)==false)//退避ファイル
{
res = RESULT_FAIL_OPENW;
break;
}
}else{
bool mkdir;
int rev;
while(1){
if (exsave.OpenW(file_pathw,fsize,&mkdir)==false)
{
if(mkdir)//ディレクトリ作成のみ
{//深いと作成に時間かかるので画面に変化つける
rev++;
if (rev & 1)scr_MessOnCount2("Create Directry -");
else scr_MessOnCount2("Create Directry |");
}else{
NN_LOG("%d\n",exsave.LastNnResult.GetDescription());
if(nn::fs::ResultInvalidArgument::Includes(exsave.LastNnResult))
{//パス名エラー
if (exsave.OpenVnfW(file_pathw,fsize)==false)//退避ファイル
{
res = RESULT_FAIL_OPENW;
}
break;
}else{
res = RESULT_FAIL_OPENW;
break;
}
}
}else break;
}
if (res != RESULT_OK)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 )
{//挿抜による中断
if(TryDeleteDir())return INSEXIT;
return ERROR;//デリート失敗表示
}else{
if (res == RESULT_OK)
{
if (ct == arcInfo.FileCount)//ファイル数一致?
{
if(exsave.WriteSys(&arcInfo))//フォーマット情報
{
//成功
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;
}
}else{
NN_LOG("file count error\n");
res = RESULT_FAIL;
}
}
//失敗
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);
}
}
return ERROR;
}
//--------------------------------------------------------------- セーブデータの情報取得
//呼ぶ前に 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();//中断処理
//挿抜を検知したら中断して抜ける
//トップ以外ではトップメニューへ戻るようする
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 現在)
//スリープ中は止まらないので、本体スイッチ切るのが確実
//SDK2.2以降で対策不要となったが、点滅が鬱陶しいので残しとく
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
*---------------------------------------------------------------------------*/