mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
1126 lines
36 KiB
C++
1126 lines
36 KiB
C++
/*---------------------------------------------------------------------------*
|
||
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 );
|
||
//0、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
|
||
*---------------------------------------------------------------------------*/
|
||
|