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

1126 lines
36 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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/crypto.h>
#include <nn/ndm.h>
#include <nn/cfg.h>
#include <nn/cfg/ctr/cfg_apiinit.h>
//#include <nn/ndm/ndm_DebugControl.h>
#include <nn/ndm/ndm_UserControl.h>
#include <nn/fs/ctr/mpcore/fs_FileSystemBasePrivate.h>
#include <nn/fs/fs_Parameters.h>
//#include <nn/fs/fs_ApiProcessInfo.h>
#include "./screen/screen.h"
#include "../ver.h"
#include "../../../common/common.h"
#include "sub.h"
#include "main.h"
nn::fnd::ExpHeap appHeap;
uptr heapForGx;
myResult errRes;
bool alive_Sd;//SD有効フラグ
TgtDev BkupDev = TGT_MEM;//バックアップ先(MEM or SD)
bool forceSD = false;//強制でSD使用
//バックアップの状態
bool Active,Formatted;//カードあり、セーブあり
bool Effective = false;//リード済み
tArcInfo arcInfo,arcInfo2;//アーカイブ情報
tDcList dcList,dcList2;//ディレクトリ格納
//動作モード
bool CopyMode=false;
//セーブデータを扱うクラス
CsmSaveFile save;
//Top画面表示
int tm_err,tm_mode;
//結果
typedef enum {
SUCCESS
,ERROR
,CANCEL
,INSEJECT
}RetCode;
//挿抜イベント時に設定
#define InEj_None 0
#define InEj_InsCard 1
#define InEj_EjcCard 2
#define InEj_InsSd 4
#define InEj_EjcSd 8
#define InEj_Sd (InEj_InsSd + InEj_EjcSd)
#define InEj_Card (InEj_InsCard + InEj_EjcCard)
//メッセージ用タグ
enum eMesTag{
MT_Compair,//コンペア時
MT_ChkCard,//ユーザセーブの存在チェック時
MT_ChkBkup,//バックアップ先の存在チェック時
MT_CrtBkup,//保存先の作成
MT_FileNot,//ユーザセーブのマウント成功したがファイルが無い
MT_Reading,//リード中
MT_Complate,//終了
MT_CardFormat,//ユーザセーブのフォーマット時
MT_FormatOnly,//フォーマットのみ行ったとき(ファイルなし時)
MT_Writing,//ライト中
MT_CrtDir,//ディレクトリ作成中
MT_Copy,// ファイルコピー
MT_Failed,//失敗
MT_Break,//中断
MT_Success,//成功
MT_ExIcn1,//"" 実行中アイコン1
MT_ExIcn2,//" | " 同2(1,2 交互に表示)
MT_END
};
tChar* MES_NULL = L"";
//メモリ or SD 判定用
#define MEM_BKUP_LIMIT (MEM_BKUP_SIZE - 1024*1024)
//文字数(終端込)
#define MESS_SIZE 32
//メッセージ格納
wchar_t Mess[MT_END*MESS_SIZE];
wchar_t MessWork[MESS_SIZE];
wchar_t MessWork2[MESS_SIZE];
//メッセージ位置
int MessPos[MT_END];
#define MessTxt(i) (wchar_t*)&Mess[MessPos[i]]
int isInsEject;
extern u8 scr_evnt;
s64 sSize;
wchar_t wk_dir[20];//拡張セーブ上のリネームファイル用ディレクトリ
int rename_n =0;//リネーム番号
wchar_t file_pathw[MAX_PATH_LENGTH];
wchar_t file_pathw2[MAX_PATH_LENGTH];
char file_path[MAX_PATH_LENGTH];
u8 WaitUI();
void PutError(TgtDev dev,int cd=0);
void failstop();
myResult OpenWork(TgtDev dev);
void Delete();
void InsEjcErrPut();
void Evt_SdInEx();
void DeleteWork();
//------------------------------------------------------------ 挿抜チェック
//イベント
nn::os::LightEvent ejectEvnt(false);
nn::os::LightEvent insEvnt(false);
#ifndef CSM_FLAG_DEBUG
nn::os::LightEvent ejectEvntSd(true);//SDは自動クリアなし
nn::os::LightEvent insEvntSd(true);
#else
nn::os::LightEvent ejectEvntSd(false);//挿抜あり
nn::os::LightEvent insEvntSd(false);
#endif
void InitInsEject()
{
//挿抜イベント
//クラス関数内だと登録が上手くいかない(謎)
isInsEject = InEj_None;
ejectEvnt.ClearSignal();
insEvnt.ClearSignal();
ejectEvntSd.ClearSignal();
insEvntSd.ClearSignal();
nn::fs::RegisterCardEjectedEvent(&ejectEvnt);
nn::fs::RegisterCardInsertedEvent(&insEvnt);
nn::fs::RegisterSdmcEjectedEvent(&ejectEvntSd);
nn::fs::RegisterSdmcInsertedEvent(&insEvntSd);
}
bool CheckInsEjectCard()
{
if (ejectEvnt.TryWait()){
isInsEject |= InEj_EjcCard;
return true;
}
if (insEvnt.TryWait()){
isInsEject |= InEj_InsCard;
return true;
}
return false;
}
bool CheckInsEjectSD()
{
//if(alive_Sd){
if (ejectEvntSd.TryWait()){
isInsEject |= InEj_EjcSd;
return true;
}
if (insEvntSd.TryWait()){
isInsEject |= InEj_InsSd;
return true;
}
// }
return false;
}
bool CheckInsEject()
{
CheckInsEjectSD();
CheckInsEjectCard();
return (isInsEject != InEj_None);
}
//--------------------- 表示更新
void UpdateStatus(){
CheckInsEject();//挿抜チェック
if (isInsEject & InEj_Sd) Evt_SdInEx();//SD挿抜
Active = save.stsActive(TGT_CARD);//内部でGetPrdCode
if (Active)Formatted = save.stsFormatted(TGT_CARD);
else Formatted = false;
if (Effective==false ) arcInfo.Pcode[0] = 0;//プロダクト(ワーク側)表示を消す
if(Active){//カードあり
if (Effective)
{//リードあり
if (strcmp(save.PrdCode,arcInfo.Pcode)==0)
{//プロダクトコード一致
tm_mode = SCR_MENU_WRITE;//ライトメニュー
tm_err = SCR_ERRPUT_NONE;
}else
{
tm_mode = SCR_MENU_NONE;
tm_err = SCR_ERRPUT_PCODE;//プロダクトコードが違う
}
}else
{//なし
if (Formatted){//セーブ存在
tm_mode = SCR_MENU_READ;//リードメニュー
tm_err = SCR_ERRPUT_NONE;
}else{
tm_mode = SCR_MENU_NONE;
tm_err = SCR_ERRPUT_MEDIA;//セーブが読めない
}
}
}else{
tm_mode = SCR_MENU_NONE;
tm_err = SCR_ERRPUT_CARD;//カードが入ってない
}
isInsEject = InEj_None;//フラグクリア
scr_PrdCode(save.PrdCode);//プロダクトコード表示
scr_PrdCodeEx(arcInfo.Pcode);//プロダクトコード表示
}
//SD挿抜
void Evt_SdInEx()
{
#ifdef CSM_FLAG_DEBUG
save.Unmount(TGT_SD);//再マウント
save.Mount(TGT_SD);
#else
ScrClr();
scr_InsEjectSD();
failstop();//停止
#endif
}
//---------------------------------------------------------------- 終了処理
void endfunc()
{
nn::fs::UnregisterCardEjectedEvent();
nn::fs::UnregisterCardInsertedEvent();
ejectEvnt.Finalize();
insEvnt.Finalize();
nn::fs::UnregisterSdmcEjectedEvent();
nn::fs::UnregisterSdmcInsertedEvent();
ejectEvntSd.Finalize();
insEvntSd.Finalize();
save.Finalize();
save.Unmount();
ScrFinalize();
}
//エラー停止
void failstop()
{
NN_LOG("fail %d,stop\n",errRes);
save.Finalize();
while(1){
CheckSysBreak();
}
}
//エラー表示
tChar sts[64];
void PutError(TgtDev dev,int cd)
{
GetErrorStr(dev,save.LastNnResult(dev),cd,sts);
scr_Status(sts,COLOR_RED);
}
//表示テキストの読込(eMessTagの順)
//テキストはSJISやASCII不可、U-16で保存し文字列は改行(0a0d)で終える
//BOM(先頭2バイトのゴミ ^^; )は付けない事
void LoadMessText(wchar_t* path)
{
const size_t ROMFS_BUFFER_SIZE = 1024*8;
static char buffer[ROMFS_BUFFER_SIZE];
NN_LOG("reqsize = %d",nn::fs::GetRomRequiredMemorySize(8,8));
nn::fs::MountRom(4, 4, buffer, ROMFS_BUFFER_SIZE);
nn::fs::FileReader Reader;
if(Reader.TryInitialize(path).IsFailure())
{
NN_LOG("fail to read file $s\n",path);
endfunc();
}
const u32 size = (u32)Reader.GetSize();
if (size > (MT_END*MESS_SIZE*2))
{
NN_LOG("textfile:size over\n");
endfunc();
}
Reader.Read(Mess,size);
int i,n;
for (i=0;i<MT_END;i++)MessPos[i]=0;
//for (i=0;i<(MT_END*MESS_SIZE);i++)Mess[i]=0;
//Mess[0] = 0;MessPos[0]=0;//先頭(FEFF)をNULLに差替..BOMありのとき
//i=1;n=1;
i=0;n=0;
bool b=true;//最初の改行以外から開始
while( n < (size/2))
{
if ((Mess[n] == 0x0a)||(Mess[n] == 0x0d)){//改行?
Mess[n]=0;//終端に置換
b =true;
} else{
if(b){//改行直後の文字を先頭とみなす
MessPos[i]=n;
i++;
if (i == MT_END)break;
b=false;
}
}
n++;
}
if (i < MT_END){
NN_LOG("textfile: few strings\n");
endfunc();
}
//最後の文字列に終端付ける
n = MessPos[i-1]+1;
while( n < (size/2))
{
if ((Mess[n] == 0x000d) || (Mess[n] == 0x000a)){//改行?
Mess[n]=0;//終端に置換
//break;
}
n++;
}
Mess[size/2] = 0;//念の為、最後に終端
Reader.Finalize();
nn::fs::Unmount("rom:");
}
//動作中アイコン
//あらかじめMessWorkに入ってる文字列に付ける
int IconCt=0;
void Icon(eColor col){
wcscpy(MessWork2,MessWork);
if(++IconCt & 1) wcscat(MessWork2,MessTxt(MT_ExIcn1));//"-"
else wcscat(MessWork2,MessTxt(MT_ExIcn2));//"|"
scr_Status(MessWork2,col);
}
//ワークはルートに置く
//起動時リードするには
// アーカイブ情報や空ディレクトリも含めないとダメ
wchar_t WorkPath[] = L"/work.bin";
u32 WorkNumber=0,WorkNumberBkup=0;
#define WORK_HEADER_SIZE 4
struct tWorkInfo
{
wchar_t path[MAX_PATH_LENGTH];
u32 size;//max 4Gbyte
};
tWorkInfo work_info;
#define WORK_INFO_SIZE sizeof(tWorkInfo)
//ワークファイル作成
bool CreateWork(TgtDev dev,tArcInfo *ai)
{
s64 size;
bool res;
//int n;
if (Effective || (dev == TGT_CARD))return false;//無効
DeleteWork();//ワーク削除
//n = save.LastNnResult(dev).GetDescription();
//NN_LOG("%d\n",n);
size = ai->total + WORK_HEADER_SIZE + (WORK_INFO_SIZE * ai->FileCount);
if (dev == TGT_SD){
res = save.CreateFile(dev,WorkPath,size);//拡張セーブはOpen前にCreate必要、MEMはOpenWに含
//NN_LOG("%d\n",save.LastNnResult(dev).GetDescription());
}else{
res = (save.Create(dev,1,1) == RESULT_OK);//MEMはファイル単位消去無いのでアーカイブごと
}
if (res)
if (save.OpenW(dev,WorkPath,size)){
while(1){ //先頭に乱数セット
nn::crypto::GenerateRandomBytes( (char*)&WorkNumber,WORK_HEADER_SIZE );
//、FFFFFFFF、前回と同じ値 は使わない
if ( (WorkNumber != 0) && (WorkNumber != 0xffffffff)
&& (WorkNumber != WorkNumberBkup))break;
}
WorkNumberBkup = WorkNumber;
NN_LOG("create work,number = %4x\n",WorkNumber);
if (save.Write(dev,(char*)&WorkNumber,WORK_HEADER_SIZE)
== WORK_HEADER_SIZE) Effective = true;
else save.CloseW(dev);
}
return Effective;
}
//ワーク開く
myResult OpenWork(TgtDev dev)
{
int num;
if(CheckInsEject())return RESULT_INSEJECT;//挿抜検出
if (save.Open(dev,WorkPath )){
if(save.Read(dev,(char*)&num,WORK_HEADER_SIZE) == WORK_HEADER_SIZE)
{
//記録時のヘッダと一致するか
if (num==WorkNumber)return RESULT_OK;
}
save.Close(dev);
}
NN_LOG("%d\n",save.LastNnResult(dev).GetDescription());
return RESULT_FAIL_WORK;
}
//ワーク削除
void DeleteWork(){
//SD,MEM両方消す
if(alive_Sd){
save.Close(TGT_SD);//オープンしたままだと削除できない
save.CloseW(TGT_SD);
save.DeleteFile(TGT_SD,WorkPath);//SDはファイルのみ
}
save.Delete(TGT_MEM);//メモリはアーカイブごと
Effective = false;
}
//-------------------------------------------------- Verifi
myResult Verifi(TgtDev dest,TgtDev src)
{
myResult res;
int ct,i;
s64 total=0;
TgtDev dev;//ワークのデバイス
if (dest == src)return RESULT_FAIL;//デバイスが同じ
if (dest == TGT_CARD)dev = src;
else if(src == TGT_CARD)dev = dest;
else return RESULT_FAIL; //片方は必ずCARDでないとダメ
wcscpy(MessWork,MessTxt(MT_Compair));//"Verifi"メッセージ
Icon(COLOR_YELLO);
scr_Vsnc();
//セーブデータのマウント
res = save.Mount(TGT_CARD);
if(res != RESULT_OK)return res;
//カード上のディレクトリ確認
//空ディレクトリもチェックするアプリ対策(マリカ7)
//ファイルなし状態ありえるので先に確認
if( dcList.num >0 )
{
nn::fs::Directory dc;
for(i=0;i<dcList.num;i++)
{
if(CheckInsEject() ||
dc.TryInitialize(dcList.name[i]).IsFailure())
{//ディレクトリ開けない
dc.Finalize();
save.Unmount(TGT_CARD);
return RESULT_FAIL_OPEN;
}
dc.Finalize();//開いたディレクトリを閉じる
}
}
ct =0;;
if (arcInfo.FileCount == 0)//ファイルが無い
{
save.Unmount(TGT_CARD);
return RESULT_OK;
}else{
//ワークを開く
res = OpenWork(dev);
if(res != RESULT_OK){
save.Unmount(TGT_CARD);
return res;
}
res = RESULT_OK;
while(res==RESULT_OK){
if(CheckInsEject())res = RESULT_INSEJECT;//挿抜チェック
else{
i = save.Read(dev,(char*)&work_info,WORK_INFO_SIZE);//ファイル情報
if (i != WORK_INFO_SIZE){
if (i) res = RESULT_FAIL_WORK;//リードエラー
else break;//終端 or 読めなかった
}else{
if (work_info.path[0] == 0)res = RESULT_FAIL_WORK;//無効データ
else if (ct >= arcInfo.FileCount)res = RESULT_FAIL;//ファイル数オーバ
else{//Open
if (save.Open(TGT_CARD,work_info.path)==false)res = RESULT_FAIL_OPEN;
else{
if (work_info.size != save.FileSize(TGT_CARD))res = RESULT_FAIL_VERIFI;
else{
scr_CountPerMax(ct,arcInfo.FileCount);//ファイルカウンタ
res = save.OpnCmp(dest,src,work_info.size);//比較
if (res == RESULT_OK){
total += work_info.size;
ct++;
}
}
}
save.Close(TGT_CARD);
}
}
}
}
if((res==RESULT_OK) && ct != arcInfo.FileCount)res=RESULT_FAIL;//異常なループ抜け
}
save.Close(dev);
scr_Status(MessTxt(MT_ChkCard),COLOR_YELLO);//ユーザセーブの確認
scr_Vsnc();//画面更新待ち
//セーブ前後で構成が一致するか
if((res == RESULT_OK) && (dest == TGT_CARD)){//読み込み時は不要
if(save.GetInfo(&arcInfo2,&dcList2)==false)res = RESULT_FAIL_VERIFI;
else if (arcInfo.total != arcInfo2.total)res = RESULT_FAIL_VERIFI;
else if (arcInfo.DirEntry != arcInfo2.DirEntry)res = RESULT_FAIL_VERIFI;
else if (arcInfo.DirCount != arcInfo2.DirCount)res = RESULT_FAIL_VERIFI;
else if (arcInfo.FileEntry != arcInfo2.FileEntry)res = RESULT_FAIL_VERIFI;
else if (arcInfo.FileCount != arcInfo2.FileCount)res = RESULT_FAIL_VERIFI;
else if (arcInfo.Dup != arcInfo2.Dup)res = RESULT_FAIL_VERIFI;
if (res == RESULT_OK)
{
int j,k=0;
if(dcList.num != dcList2.num)res=RESULT_FAIL_VERIFI;
else {
for(i=0;i<dcList.num;i++){//いずれかに一致するか
for(j=0;j<dcList.num;j++){
if (CmpPathW(dcList.name[i],dcList2.name[j])){k++;break;}
}
}
if (k != dcList.num)res=RESULT_FAIL_VERIFI;//全一致?
}
}
}
save.Unmount(TGT_CARD);
scr_Total(total);
scr_CountPerMax(ct,arcInfo.FileCount);
return res;
}
//結果からエラー表示
RetCode PutResltErr(myResult res,TgtDev rdev,TgtDev wdev)
{
int err_code;
TgtDev err_tgt;
switch(res)
{
case RESULT_OK:
scr_Status(MessTxt(MT_Complate),COLOR_WHITE);
return SUCCESS;
case RESULT_INSEJECT:
return INSEJECT;
case RESULT_FAIL_WRITE:
case RESULT_FAIL_OPENW:
err_tgt = wdev;err_code = ERC_WRITE;
break;
case RESULT_FAIL_READ:
case RESULT_FAIL_OPEN:
err_tgt = rdev;err_code = ERC_READ;
break;
case RESULT_WORK_OVER:
err_tgt = TGT_CTR;err_code = ERC_WORK;
break;
case RESULT_FAIL_WORK:
if (rdev != TGT_CARD)err_tgt = rdev;
else err_tgt = wdev;
err_code = ERC_WORK;
break;
default:
err_tgt = TGT_CTR;err_code= ERC_EXEC;
break;
}
PutError(err_tgt,err_code);
return ERROR;
}
//---------------------------------------------------------------------- save to Work file
//Cardマウント、ワークファイルオープンして呼ぶ
myResult Save2Work(TgtDev dev,u32 num)
{
s64 total = 0;
int ct=0;
myResult res;
if (num == 0)return RESULT_FAIL;//パラメータエラー
res = RESULT_OK;
save.ResetPath(TGT_CARD);
while(res==RESULT_OK){
CheckSysBreak();//Home,電源ボタンによる中断処理
if(CheckInsEject())res = RESULT_INSEJECT;//挿抜チェック
else{
res = save.GetPath(TGT_CARD,work_info.path);//パス名取得
if (res != RESULT_OK)
{
if ((res == RESULT_DIR_LEVEL_OVER)
|| (res == RESULT_PATH_LENGTH_OVER)) res = RESULT_WORK_OVER;
else res = RESULT_FAIL_OPEN;
}else{
if (work_info.path[0] == 0)break;//root then end
if (ct >= num)res = RESULT_FAIL;//ファイル数オーバ
else{
//コピー元オープン
if (save.Open(TGT_CARD,work_info.path)==false)res = RESULT_FAIL_OPEN;
else{
//ファイル情報を格納
work_info.size = save.FileSize(TGT_CARD);
if(save.Write(dev,(char*)&work_info,WORK_INFO_SIZE) == WORK_INFO_SIZE)
{//データ格納
scr_CountPerMax(ct,num);//カウンタ表示
res = save.OpnCpy(dev,TGT_CARD,work_info.size);//ワークへ書き出す
if (res == RESULT_OK){
total += work_info.size;
ct++;
}
}else res= RESULT_FAIL_WRITE;
save.Close(TGT_CARD);
}
}
}
}
}
save.CloseW(dev);//Close & Flush
save.Unmount(TGT_CARD);
scr_Total(total);//サイズ表示
scr_CountPerMax(ct,num);//カウンタ表示
if ((res == RESULT_OK) && (ct != num))res = RESULT_FAIL;//指定したファイル数と一致しない
return res;
}
//---------------------------------------------------------------------- restore from Work file
//ワークのファイル情報チェック
//  サイズチェックに使うので保存時のtArcInfoを参照
bool InfoChk(tWorkInfo *wi)
{
int i;
if (wi->path[0]==0)return false;//空文字
//バッファオーバ予防、終端確認
for (i = 1;i<MAX_PATH_LENGTH;i++)if (wi->path[i]==0)break;
if (i==MAX_PATH_LENGTH)return false;
if((wi->size < arcInfo.min) || (wi->size > arcInfo.max))return false;
return true;
}
//--------------------------------------------------------- make save by work file
//Cardマウント、ワークファイルオープンして呼ぶ
//ファイル無(num=0) -> コミットのみ
myResult Work2Save(TgtDev dev,u32 num)
{
s64 total = 0;
int ct=0;
myResult res;
res = RESULT_OK;
while((res==RESULT_OK) && (ct < num)){
CheckSysBreak();//Home,電源ボタンによる中断処理
if(CheckInsEject())res = RESULT_INSEJECT;//挿抜チェック
else{
if(save.Read(dev,(char*)&work_info,WORK_INFO_SIZE) != WORK_INFO_SIZE)
{
res= RESULT_FAIL_READ;
}else{
if (InfoChk(&work_info)==false)res = RESULT_FAIL_READ;//無効なファイル情報
else{
//作成付オープン
//if (save.OpenW(TGT_CARD,work_info.path)==false)res = RESULT_FAIL_OPENW;
//大容量では先にCreateしとく方が断然速く終わる(2012.9月現在、SDK4.2.3にて)
if (save.CreateFile(TGT_CARD,work_info.path,work_info.size)==false)res = RESULT_FAIL_OPENW;
if (save.OpenW(TGT_CARD,work_info.path)==false)res = RESULT_FAIL_OPENW;
else{
scr_CountPerMax(ct,arcInfo.FileCount);//カウンタ表示
res = save.OpnCpy(TGT_CARD,dev,work_info.size);//dev -> Card
if (res == RESULT_OK){
total += save.FileSize(TGT_CARD);
ct++;
if (ct == num)break;//終了
}
save.CloseW(TGT_CARD);//Close & flush
}
}
}
}
}
save.Close(dev);//Close
if (res==RESULT_OK){
if(ct != num)res = RESULT_FAIL;//異常なループ抜け
else if(save.Commit()==false)res = RESULT_FAIL_WRITE;
}
save.Unmount(TGT_CARD);
scr_Total(total);//サイズ表示
scr_CountPerMax(ct,num);//カウンタ表示
return res;
}
//------------------------------------------------------- Card -> CTR
RetCode Card2Ctr()
{
BkupDev = TGT_MEM;//デフォはメモリ
//実行確認
scr_BackupYesNo();
u8 evt = WaitUI();//入力待ち
if (evt == EVNT_INEX)return INSEJECT;//挿抜による中断
if (evt != EVNT_YES)return CANCEL;//キャンセル
//画面表示
scr_Backup();
scr_Status(MessTxt(MT_ChkCard),COLOR_YELLO);//"カード確認中"表示
scr_Vsnc();//画面更新待ち
//マウント&ディレクトリ情報取得
if( save.Mount(TGT_CARD) != RESULT_OK ){PutError(TGT_CARD);return ERROR;}
if(save.GetInfo(&arcInfo,&dcList)==false){PutError(TGT_CARD);save.Unmount(TGT_CARD);return ERROR;}
if ((arcInfo.FileCount > arcInfo.FileEntry)
|| (arcInfo.DirCount > arcInfo.DirEntry)){PutError(TGT_CTR,ERC_EXEC);save.Unmount(TGT_CARD);return ERROR;}
if(arcInfo.DirCount >= MAX_DCLIST){PutError(TGT_MEM,ERC_EXEC);save.Unmount(TGT_CARD);return ERROR;}
//ワーク作成先の判定
if (forceSD && alive_Sd) BkupDev = TGT_SD;//強制SD
else{//総サイズがメモリに収まるか?
if (arcInfo.total > MEM_BKUP_LIMIT)
{
if (alive_Sd)BkupDev = TGT_SD;//SD
else {//メモリオーバ
PutError(TGT_MEM,ERC_NOSPACE);
save.Unmount(TGT_CARD);
return ERROR;
}
}
}
//ワークファイル作成
scr_Status(MessTxt(MT_CrtBkup),COLOR_YELLO);
scr_Vsnc();
if (CreateWork(BkupDev,&arcInfo)==false)
{
PutError(BkupDev);
save.Unmount(TGT_CARD);
return ERROR;
}
if (arcInfo.FileCount == 0)
{//ファイルなし(ディレクトリ作成は必要なので書戻しで忘れない!!)
scr_Status(MessTxt(MT_FileNot),COLOR_YELLO);//"ファイルなし"警告
save.CloseW(TGT_SD);
save.Unmount(TGT_CARD);
strcpy(arcInfo.Pcode,save.PrdCode);
return SUCCESS;
}
wcscpy(MessWork,MessTxt(MT_Reading));//"Reading"メッセージ
//if (BkupDev == TGT_SD)wcscat(MessWork,L"(to SD)");
myResult res = Save2Work(BkupDev,arcInfo.FileCount);//Card -> Work
if (res == RESULT_OK){
res = Verifi(BkupDev,TGT_CARD);
if (res == RESULT_OK){
strcpy(arcInfo.Pcode,save.PrdCode);
}
}
return PutResltErr(res,TGT_CARD,BkupDev);//結果表示&リターン
}
//------------------------------------------------------- CTR -> Card
RetCode Ctr2Card()
{
//Card2CtrでBkupDevにワークファイル作成済み前提
//実行確認
scr_RestoreYesNo();
u8 evt = WaitUI();//入力待ち
if (evt == EVNT_INEX)return INSEJECT;//挿抜による中断
if (evt != EVNT_YES)return CANCEL;//キャンセル
//画面表示
scr_Restore();
//セーブデータのフォーマット(マウント込)
scr_Status(MessTxt(MT_CardFormat),COLOR_YELLO);
scr_Vsnc();
if(save.Format(&arcInfo) != RESULT_OK)
{
PutError(TGT_CARD);
save.Unmount(TGT_CARD);
return ERROR;
}
//ディレクトリ作成
//空ディレクトリもチェックするゲームあるので(マリカ7)
//ファイルの存在と関係なく作成
if(dcList.num >0)
{
int i;
bool mkdir,err = false;
wcscpy(MessWork,MessTxt(MT_CrtDir));
for (i=0;i<dcList.num;i++)
{
while(err==false){
Icon(COLOR_YELLO);
if(CheckInsEject())err =true;//挿抜チェック
else{
if (save.MakeDir(TGT_CARD,dcList.name[i],&mkdir))break;
if(mkdir==false)err = true;
}
}
if (err)break;
else if (mkdir){err = true;break;}//異常なループ抜け
}
if (err)
{
PutError(TGT_CARD);
save.Unmount(TGT_CARD);
return ERROR;
}
}
//ワーク開く
if(OpenWork(BkupDev) != RESULT_OK){
PutError(BkupDev);
save.Unmount(TGT_CARD);
return ERROR;
}
wcscpy(MessWork,MessTxt(MT_Writing));//"Writing"
//if (BkupDev == TGT_SD)wcscat(MessWork,L"(from SD)");
myResult res = Work2Save(BkupDev,arcInfo.FileCount);// Work -> CARD
if (res == RESULT_OK){
res = Verifi(TGT_CARD,BkupDev);//ベリファイ
if(res != RESULT_OK){
//表示の都合でVerifiのエラーはrdevをCARDにする
return PutResltErr(res,TGT_CARD,BkupDev);
}
}
return PutResltErr(res,BkupDev,TGT_CARD);//結果表示&リターン
}
//---------------------------------------------------------------- 入力待ち
u8 WaitUI()
{
scr_Draw();//画面更新
scr_evnt = EVNT_NONE;
while(scr_evnt == EVNT_NONE)
{
//nn::os::Thread::Yield();//スレッド実行
//scr_GetEvnt();//入力イベント
CheckSysBreak();//Home,電源ボタンによる中断処理
//挿抜チェック
//SD:停止
//Card:トップメニューでは無視、リードライト中はトップメニューへ戻る
if(CheckInsEject()){
return EVNT_INEX;
}
nn::os::Thread::Yield();//スレッド実行..タッチ&ボタン取得
}
ScrClr();//画面消去
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(500));//チャタ対策
return scr_evnt;
}
void InsEjcErrPut()
{
if (isInsEject & InEj_Sd) Evt_SdInEx();
else if (isInsEject & InEj_Card) PutError(TGT_CARD,ERC_PULLOUT);
else {
PutError(TGT_CTR,ERC_EXEC);
failstop();//stop running
}
}
//起動時のモード選択ボタン
#ifndef CSM_FLAG_DEBUG
#define STUP_BTN_COPYMODE (nn::hid::BUTTON_X | nn::hid::BUTTON_B)
#define STUP_BTN_FSD (nn::hid::BUTTON_Y | nn::hid::BUTTON_B)
#else
#define STUP_BTN_COPYMODE nn::hid::BUTTON_UP
#define STUP_BTN_FSD nn::hid::BUTTON_Y
#endif
//初期化
void Init()
{
//NN_LOG("Start\n");
//nn::os::Initialize();//SDK4.2 より不要、入れると止まる
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));
//挿抜イベント
InitInsEject();
//SD確認
//終了までマウント継続、差替タイミング出来るのでリマウント避ける
alive_Sd = nn::fs::IsSdmcWritable();
if (alive_Sd){
if(save.Mount(TGT_SD) != RESULT_OK){
if(save.Create(TGT_SD,1,1) != RESULT_OK)alive_Sd = false;
}//とりあえず時間優先で省くが、すでにある場合消して再作成がいいかも
}
//ボタン押し起動チェック
{
nn::hid::Initialize();
nn::hid::PadReader padR;
nn::hid::PadStatus padS;
while (padR.ReadLatest(&padS) == false){};
NN_LOG("PAD = %x",padS.hold);
#ifdef CSM_FLAG_FORCE_SD
forceSD = alive_Sd;
#else
forceSD = false;
#endif
CopyMode = false;
switch(padS.hold){
case STUP_BTN_COPYMODE:
CopyMode = true;
break;
case STUP_BTN_FSD:
if (alive_Sd){
forceSD = true;
}else NN_LOG("mode cancel,no detect SD");
break;
case STUP_BTN_COPYMODE | STUP_BTN_FSD:
if (alive_Sd){
CopyMode = true;
forceSD = true;
}else NN_LOG("mode cancel,no detect SD");
break;
}
if (CopyMode) NN_LOG("Copy mode\n");
if (forceSD) NN_LOG("force SD\n");
}
{//テキスト設定
#ifdef CSM_FLAG_DEBUG
//リリース品と区別するためタイトルに[debug]を付ける(非セキュア品の流出予防)
u8 flg = SCR_FLG_DBG;
#else
u8 flg = 0;
#endif
if(forceSD)flg += SCR_FLG_FSD;//"強制SD"
else if(alive_Sd==false)flg += SCR_FLG_NOSD;//"SDなし"
if(CopyMode)flg += SCR_FLG_CP;//コピーモード
//言語コードで日英メッセージ切替
nn::cfg::CTR::init::Initialize();//descにcfg::u が無いので、initから呼ぶ
nn::cfg::CTR::CfgLanguageCode lcd = nn::cfg::CTR::GetLanguage();
nn::cfg::CTR::init::Finalize();
//メッセージ用テキストの読み込み
if (lcd == nn::cfg::CFG_LANGUAGE_JAPANESE)
{
LoadMessText(L"rom:/lang_jp.mes");
flg += SCR_FLG_JP;
}
else{
LoadMessText(L"rom:/lang_en.mes");
}
//画面初期化
if (ScrInitialize(heapForGx,GxHeapSize,flg) == false)finish();
}
}
//---------------------- main loop --------------------------
void nnMain()
{
u8 evt;
RetCode retc;
Init();//初期化
// スリープ要求有効
// ファイル操作中のキャンセルなど諸々面倒なので非対応
//nn::applet::EnableSleep(true);
while(1)
{
UpdateStatus();//デバイス状態で表示更新
scr_TopMenu(tm_mode,tm_err);
scr_Vsnc();
evt = WaitUI();//入力待ち
switch(evt)
{
case EVNT_INEX:
//SDなら即停止、ここ来るのはカード挿抜
//tm_mode =SCR_MENU_NONE;
//tm_err =SCR_ERRPUT_CARD2;//"Checking"
//scr_TopMenu(tm_mode,tm_err);
//scr_Vsnc();
//break;
case EVNT_PUSH_B:
case EVNT_PUSH_R:
case EVNT_PUSH_Y:
case EVNT_NONE:
break;
case EVNT_SEL_READ://**************************** リード
NN_LOG("select read\n");
retc = Card2Ctr();
break;
case EVNT_SEL_WRITE:// **************************** リストア
NN_LOG("select write\n");
retc = Ctr2Card();
break;
case EVNT_PUSH_LEFT_X:// ------------------------------------- LEFT + X
//バックアップ削除
scr_DelConf();//実行確認
if (WaitUI() != EVNT_YES)break;
DeleteWork();
break;
default://通常ここには来ない
scr_TopMenu(SCR_MENU_NONE,SCR_ERRPUT_EXEC);//実行エラー
failstop();
break;
}
//scr_PrdCode(save.PrdCode);//プロダクトコード表示
//3tscr_PrdCodeEx(arcInfo.Pcode);//プロダクトコード表示
if ( ((evt == EVNT_SEL_WRITE) || (evt == EVNT_SEL_READ))
&& (retc != CANCEL))
{
switch (retc){
case SUCCESS:
scr_ResultQuit(MessTxt(MT_Success),COLOR_GREEN);//成功とQuitボタン
//コピーモードでなければライト成功時にワーク消す
if ((evt == EVNT_SEL_WRITE) && (CopyMode == false))DeleteWork();
break;
case INSEJECT:
ScrClr();//画面消去
if(evt==EVNT_SEL_READ)scr_Backup();
else scr_Restore();
InsEjcErrPut();
scr_ResultQuit(MessTxt(MT_Break),COLOR_RED);//エラーとQuitボタン
break;
default://error or else
if (isInsEject != InEj_None)InsEjcErrPut();//抜差イベント発生
else if (CheckInsEject())InsEjcErrPut();//抜差チェック
scr_ResultQuit(MessTxt(MT_Failed),COLOR_RED);//エラーとQuitボタン
break;
}
if ((retc != SUCCESS) && (evt == EVNT_SEL_READ))DeleteWork();//リード失敗ならワーク削除
//戻るボタン待ち
while(1){
UpdateStatus();
evt = WaitUI();
if ((evt==EVNT_QUIT) || (evt==EVNT_PUSH_B))break;
}
}
}//while()
}
/*---------------------------------------------------------------------------*
End of file
*---------------------------------------------------------------------------*/