mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
446 lines
14 KiB
C++
446 lines
14 KiB
C++
#include <wchar.h>
|
||
#include <string.h>
|
||
#include <nn/fs.h>
|
||
#include "savedata.h"
|
||
#include <nn/fs/fs_ResultPrivate.h>
|
||
//#include <../fs/fs_ApiSysSaveData.h>
|
||
//#include <../fs/ctr/mpcore/fs_FileSystemBasePrivate.h>
|
||
#include <nn/fs/CTR/MPCore/fs_ApiForHwCheck.h>
|
||
#include <nn/am/am_ApiSystemMenu.h>
|
||
#include <nn/am/am_ApiLocalImporter.h>
|
||
|
||
#define MAX_LEVEL 256
|
||
//static nn::fs::DirectoryEntry dcEntry[MAX_LEVEL];
|
||
//static nn::fs::Directory dc[MAX_LEVEL];
|
||
int dc_readed[MAX_LEVEL];//リード済みエントリ数
|
||
|
||
//生成時のデバイス名を超えるとパス長上限をこえる
|
||
//可能性があるので1文字にする(無用な心配かも)
|
||
const wchar_t *sdataRoot_w = L"s:/";
|
||
#define ROOTLENGTH 3
|
||
const char *sdataName = "s:";
|
||
const wchar_t *Dummy_w = L"ncltool";
|
||
//char path[512];//パス名
|
||
static bool IsMounted;
|
||
wchar_t path_w[MAX_PATH_LENGTH];//パス名
|
||
wchar_t pathu_w[MAX_LEVEL][MAX_PATH_LENGTH];//パス名履歴
|
||
wchar_t pathw_w[MAX_PATH_LENGTH];//パス名ワーク
|
||
|
||
//#define SysSaveId 0x20300
|
||
|
||
//セーブ作成、成功時はマウント状態
|
||
myResult SaveData::Format(tArcInfo *pinfo)
|
||
{
|
||
if ( IsMounted )return RESULT_ALREADY_MOUNT;
|
||
#ifdef USE_SYS_SAVE
|
||
LastNnResult = nn::fs::CreateSystemSaveData(
|
||
SysSaveId,pinfo->FileEntry,pinfo->DirEntry,0x100000,pinfo->Dup);
|
||
if (LastNnResult.IsFailure())return RESULT_FAIL_FORMAT;
|
||
#else
|
||
LastNnResult = nn::fs::FormatCtrCardSaveData(pinfo->FileEntry,pinfo->DirEntry,pinfo->Dup);
|
||
if (LastNnResult.IsFailure())return RESULT_FAIL_FORMAT;
|
||
#endif
|
||
if ( Mount() != RESULT_OK )return RESULT_FAIL_MOUNT;
|
||
IsMounted = true;
|
||
return RESULT_OK;
|
||
}
|
||
|
||
void SaveData::ResetPath()
|
||
{
|
||
s_lv=0;
|
||
s_serch = false;
|
||
wcscpy(path_w,sdataRoot_w);
|
||
for (int n = 0;n<MAX_LEVEL;n++)dc_readed[n] = 0;
|
||
//wcscpy(pathu_w,path_w);
|
||
}
|
||
|
||
myResult SaveData::GetPath(wchar_t *path)
|
||
{
|
||
static nn::fs::DirectoryEntry dcEntryl;
|
||
static nn::fs::Directory dcl;
|
||
|
||
int n,ct;
|
||
while(1){
|
||
LastNnResult = dcl.TryInitialize(path_w);//Open
|
||
if (LastNnResult.IsFailure()){
|
||
return RESULT_FAIL;
|
||
}
|
||
if (dc_readed[s_lv] != 0)for(n=0;n<dc_readed[s_lv];n++)dcl.Read(&dcEntryl,1);
|
||
n = (dcl.Read(&dcEntryl,1));
|
||
dc_readed[s_lv]++;
|
||
dcl.Finalize();
|
||
if ( n==0 )//終端
|
||
{
|
||
if (s_lv == 0){path[0]=0;return RESULT_OK;}// ---- rootなら終了
|
||
s_lv--;//上の層に戻る
|
||
wcscpy(path_w,pathu_w[s_lv]);//パス戻す
|
||
}else{
|
||
if(dcEntryl.attributes.isDirectory){//ディレクトリ
|
||
//m_info.DirCount++;
|
||
wcscpy(pathu_w[s_lv],path_w);//パス保存
|
||
wcscat(path_w,dcEntryl.entryName);//次のディレクトリパス
|
||
wcscat(path_w,L"/");
|
||
if (++s_lv == MAX_LEVEL)return RESULT_DIR_LEVEL_OVER;
|
||
}else{//ファイル
|
||
//m_info.FileCount++;
|
||
wcscpy(path,pPathTop);
|
||
ct =wcslen(path) + wcslen(dcEntryl.entryName);
|
||
if (ct>MAX_PATH_LENGTH - 1)return RESULT_PATH_LENGTH_OVER;
|
||
wcscat(path,dcEntryl.entryName);
|
||
return RESULT_OK;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//アンマウント
|
||
void SaveData::Unmount()
|
||
{
|
||
if(IsMounted){
|
||
IsMounted = false;
|
||
nn::fs::Unmount(sdataName);
|
||
}
|
||
}
|
||
|
||
//バックアップの存在チェック
|
||
myResult SaveData::IsExist(){
|
||
myResult res;
|
||
res = Mount();
|
||
Unmount();
|
||
return res;
|
||
}
|
||
/*
|
||
//アーカイブ情報の取得
|
||
bool SaveData::GetInfo(tArcInfo *pinfo)
|
||
{
|
||
|
||
//strcpy(path,readerRoot);
|
||
s_lv=0;
|
||
m_info.DirCount = 0;
|
||
m_info.FileCount = 0;
|
||
m_info.DirEntry = 0;
|
||
m_info.FileEntry = 0;
|
||
m_info.Dup = false;
|
||
wcscpy(path_w,sdataRoot_w);
|
||
//wcscpy(pathu_w,path_w);
|
||
|
||
int n;
|
||
int lv = 0;
|
||
bool cont = true;
|
||
while(cont){
|
||
LastNnResult = dc[lv].TryInitialize(path_w);//Open
|
||
if (LastNnResult.IsFailure())return false;
|
||
while(1){
|
||
n = (dc[lv].Read(&dcEntry[lv],1));
|
||
if ( n==0 )//終端
|
||
{
|
||
dc[lv].Finalize();
|
||
if (lv == 0){cont=false;break;}// ---- 終了
|
||
lv--;//上の層に戻る
|
||
wcscpy(path_w,pathu_w[lv]);//パス戻す
|
||
}else{
|
||
if(dcEntry[lv].attributes.isDirectory){//ディレクトリ
|
||
m_info.DirCount++;
|
||
wcscpy(pathu_w[lv],path_w);//パス保存
|
||
wcscat(path_w,dcEntry[lv].entryName);//次のディレクトリパス
|
||
wcscat(path_w,L"/");
|
||
if (++lv == MAX_LEVEL)return false;
|
||
break;
|
||
}else{//ファイル
|
||
m_info.FileCount++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifndef INFO_API_USE
|
||
//アーカイブのエントリ数
|
||
// .. APIまでの暫定
|
||
m_info.DirEntry = m_info.DirCount;
|
||
m_info.FileEntry = m_info.FileCount;
|
||
#else
|
||
//API使用
|
||
#ifdef USE_SYS_SAVE
|
||
size_t sz;
|
||
LastNnResult = nn::fs::GetSystemSaveDataFormatInfo(SysSaveId, &m_info.FileEntry, &m_info.DirEntry, &sz, &m_info.Dup);
|
||
#else
|
||
//LastNnResult = nn::fs::GetSaveDataFormatInfo(&m_info.FileEntry,&m_info.DirEntry,&m_info.Dup);
|
||
LastNnResult = nn::fs::GetCtrCardSaveDataFormatInfo(&m_info.FileEntry,&m_info.DirEntry,&m_info.Dup);
|
||
#endif
|
||
if (LastNnResult.IsFailure())return false;
|
||
|
||
#endif
|
||
|
||
*pinfo = m_info;//構造体コピー
|
||
return true;
|
||
|
||
}
|
||
*/
|
||
//アーカイブ情報の取得
|
||
bool SaveData::GetInfo(tArcInfo *pinfo)
|
||
{
|
||
static nn::fs::DirectoryEntry dcEntryl;
|
||
static nn::fs::Directory dcl;
|
||
|
||
//strcpy(path,readerRoot);
|
||
s_lv=0;
|
||
m_info.DirCount = 0;
|
||
m_info.FileCount = 0;
|
||
m_info.DirEntry = 0;
|
||
m_info.FileEntry = 0;
|
||
m_info.Dup = false;
|
||
wcscpy(path_w,sdataRoot_w);
|
||
//wcscpy(pathu_w,path_w);
|
||
|
||
int n;
|
||
int lv = 0;
|
||
for (n = 0;n<MAX_LEVEL;n++)dc_readed[n] = 0;
|
||
bool cont = true;
|
||
while(cont){
|
||
LastNnResult = dcl.TryInitialize(path_w);//Open
|
||
if (LastNnResult.IsFailure())return false;
|
||
if (dc_readed[lv] != 0)for(n=0;n<dc_readed[lv];n++)dcl.Read(&dcEntryl,1);
|
||
while(1){
|
||
n = (dcl.Read(&dcEntryl,1));
|
||
dc_readed[lv]++;
|
||
if ( n==0 )//終端
|
||
{
|
||
if (lv == 0){cont=false;break;}// ---- 終了
|
||
lv--;//上の層に戻る
|
||
wcscpy(path_w,pathu_w[lv]);//パス戻す
|
||
break;
|
||
}else{
|
||
if(dcEntryl.attributes.isDirectory){//ディレクトリ
|
||
m_info.DirCount++;
|
||
wcscpy(pathu_w[lv],path_w);//パス保存
|
||
wcscat(path_w,dcEntryl.entryName);//次のディレクトリパス
|
||
wcscat(path_w,L"/");
|
||
if (++lv == MAX_LEVEL)return false;
|
||
break;
|
||
}else{//ファイル
|
||
m_info.FileCount++;
|
||
}
|
||
}
|
||
}
|
||
dcl.Finalize();
|
||
}
|
||
for (n = 0;n<MAX_LEVEL;n++)dc_readed[n] = 0;
|
||
|
||
#ifndef INFO_API_USE
|
||
//アーカイブのエントリ数
|
||
// .. APIまでの暫定
|
||
m_info.DirEntry = m_info.DirCount;
|
||
m_info.FileEntry = m_info.FileCount;
|
||
#else
|
||
//API使用
|
||
#ifdef USE_SYS_SAVE
|
||
size_t sz;
|
||
LastNnResult = nn::fs::GetSystemSaveDataFormatInfo(SysSaveId, &m_info.FileEntry, &m_info.DirEntry, &sz, &m_info.Dup);
|
||
#else
|
||
//LastNnResult = nn::fs::GetSaveDataFormatInfo(&m_info.FileEntry,&m_info.DirEntry,&m_info.Dup);
|
||
LastNnResult = nn::fs::GetCtrCardSaveDataFormatInfo(&m_info.FileEntry,&m_info.DirEntry,&m_info.Dup);
|
||
#endif
|
||
if (LastNnResult.IsFailure())return false;
|
||
|
||
#endif
|
||
|
||
*pinfo = m_info;//構造体コピー
|
||
return true;
|
||
|
||
}
|
||
|
||
|
||
|
||
//プロダクトコード
|
||
//結果は PrdCord に格納
|
||
bool SaveData::GetPrdCode()
|
||
{
|
||
PrdCode[0] = 0;//clear
|
||
s32 numPrograms;
|
||
nn::ProgramId programId;
|
||
|
||
LastNnResult = nn::am::InitializeForLocalImporter();
|
||
//LastNnResult = nn::am::InitializeForSystemMenu();
|
||
if (LastNnResult.IsFailure()){
|
||
//NN_LOG("%d",LastNnResult.GetDescription());
|
||
//nn::am::FinalizeForSystemMenu();
|
||
nn::am::FinalizeForLocalImporter();
|
||
return false;
|
||
}
|
||
LastNnResult = nn::am::GetProgramList(&numPrograms, &programId, 1, nn::fs::MEDIA_TYPE_CTRCARD);
|
||
if (LastNnResult.IsFailure()){
|
||
//NN_LOG("%d",LastNnResult.GetDescription());
|
||
//nn::am::FinalizeForSystemMenu();
|
||
nn::am::FinalizeForLocalImporter();
|
||
return false;
|
||
}
|
||
LastNnResult = nn::am::GetProductCode( (nn::ProductCode*)&PrdCode,nn::fs::MEDIA_TYPE_CTRCARD,programId);
|
||
//nn::am::FinalizeForSystemMenu();
|
||
nn::am::FinalizeForLocalImporter();
|
||
PrdCode[sizeof(nn::ProductCode)] = 0;//表示時のオーバラン対策
|
||
return LastNnResult.IsSuccess();
|
||
}
|
||
|
||
//マウント&アーカイブ情報の取得
|
||
myResult SaveData::Mount()
|
||
{
|
||
if (IsMounted)return RESULT_ALREADY_MOUNT;
|
||
|
||
#ifdef USE_SYS_SAVE
|
||
LastNnResult=nn::fs::MountSystemSaveData(sdataName,SysSaveId);
|
||
#else
|
||
//LastNnResult=nn::fs::MountSaveDataOnCard(sdataName);//FileSystemBasePrivate
|
||
LastNnResult = nn::fs::MountCtrCardSaveDataForCheck(sdataName);//ApiForHwCheck
|
||
#endif
|
||
IsMounted = LastNnResult.IsSuccess();
|
||
if (IsMounted)return RESULT_OK;
|
||
if (nn::fs::ResultMediaNotFound().Includes(LastNnResult))return RESULT_NO_MEDIA;
|
||
if (nn::fs::ResultFatNotFound().Includes(LastNnResult))return RESULT_NOT_FAUND;//書けるのか?
|
||
if (nn::fs::ResultNotFormatted().Includes(LastNnResult))return RESULT_NOT_FORMAT;
|
||
if (nn::fs::ResultBadFormat().Includes(LastNnResult))return RESULT_BAD_FORMAT;
|
||
if (nn::fs::ResultVerificationFailed().Includes(LastNnResult))return RESULT_SDK_VERIFI;
|
||
|
||
return RESULT_FAIL;
|
||
}
|
||
|
||
//システムセーブのデリート
|
||
//API実装までのテスト用データを消す用
|
||
#ifdef USE_SYS_SAVE
|
||
void SaveData::Delete()
|
||
{
|
||
LastNnResult=nn::fs::DeleteSystemSaveData(SysSaveId);
|
||
}
|
||
#endif
|
||
|
||
|
||
//ファイルリード
|
||
s32 SaveData::Read(char *buffer,size_t size)
|
||
{
|
||
//if (IsMounted==false)return 0;
|
||
s32 ct;
|
||
LastNnResult = reader.TryRead(&ct,(void*)buffer,size);
|
||
if(LastNnResult.IsFailure())ct=0;
|
||
return ct;
|
||
}
|
||
|
||
|
||
void SaveData::Close()
|
||
{
|
||
reader.Finalize();
|
||
}
|
||
|
||
void SaveData::CloseW()
|
||
{
|
||
writer.Finalize();
|
||
}
|
||
|
||
//ファイルを開く
|
||
//パス指定はルート以降
|
||
//(ex)data:/dir/file -> dir/file
|
||
bool SaveData::Open(wchar_t *path)
|
||
{
|
||
wcscpy(pathw_w,sdataRoot_w);
|
||
wcscat(pathw_w,path);
|
||
LastNnResult = reader.TryInitialize(pathw_w);
|
||
if (LastNnResult.IsSuccess())
|
||
{
|
||
LastNnResult = reader.TryGetSize(&FileSize);
|
||
if (LastNnResult.IsSuccess())return true;
|
||
else Close();
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool SaveData::OpenW(wchar_t *path,s64 size,bool *mkdir)
|
||
{
|
||
int pos,pos2;
|
||
|
||
wcscpy(path_w,sdataRoot_w);
|
||
wcscat(path_w,path);
|
||
*mkdir = false;
|
||
//while(1){
|
||
LastNnResult = nn::fs::TryCreateFile(path_w,size);
|
||
if(LastNnResult.IsSuccess())
|
||
{
|
||
LastNnResult = writer.TryInitialize(path_w,false);
|
||
return LastNnResult.IsSuccess();
|
||
}
|
||
//ディレクトリがなければディレクトリを作成
|
||
pos = GetPosDelmLast(path_w,ROOTLENGTH);//ファイルが存在するディレクトリ
|
||
if (pos <= 0)return false;//rootかパスが不正
|
||
//while (1){
|
||
wcscpy(pathw_w,path_w);//ワークにコピー
|
||
while (LastNnResult.IsFailure()){//ディレクトリ作成できるまで遡る
|
||
if(LastNnResult.GetDescription()!=nn::fs::DESCRIPTION_DBM_DIRECTORY_NOT_FOUND)return false;
|
||
pos2 = GetPosDelmLast(pathw_w,ROOTLENGTH);//境界位置を探す
|
||
if (pos2 == 0)return false;//root到達
|
||
pathw_w[pos2] = 0;//境界まで削除 (例) dir1/dir2/file -> dir1/dir2 -> dir1
|
||
LastNnResult = nn::fs::TryCreateDirectory(pathw_w);
|
||
}
|
||
//作成ディレクトリ多いと画面止まるので、作成ごとに抜ける
|
||
*mkdir = true; // 帰値:false で mkdir=true ならディレクトリ作成のみ
|
||
return false;
|
||
//if (pos2 == pos)break;//配置ディレクトリなら抜ける
|
||
//todo:ディレクトリが深いとき時間がかかるなら、無駄なTryCreateを省く
|
||
//案)直上から最初の成功までのデリミタ位置を記録
|
||
//先に全ディレクトリ作っておくのがよさげ
|
||
//}
|
||
//}
|
||
//LastNnResult = writer.TryInitialize(path_w,false);
|
||
//return LastNnResult.IsSuccess();
|
||
}
|
||
|
||
|
||
//ファイルライト
|
||
s32 SaveData::Write(char *buffer,size_t size)
|
||
{
|
||
s32 ct;
|
||
LastNnResult = writer.TryWrite(&ct,(void*)buffer,size);
|
||
if(LastNnResult.IsFailure())ct=0;
|
||
return ct;
|
||
}
|
||
|
||
//コミット
|
||
bool SaveData::Commit()
|
||
{
|
||
#ifdef USE_SYS_SAVE
|
||
LastNnResult=nn::fs::CommitSystemSaveData(sdataName);
|
||
#else
|
||
LastNnResult=nn::fs::CommitSaveData(sdataName);
|
||
#endif
|
||
return LastNnResult.IsSuccess();
|
||
}
|
||
|
||
|
||
|
||
//コンストラクタ
|
||
SaveData::SaveData()
|
||
{
|
||
IsMounted = false;
|
||
s_lv=0;
|
||
PrdCode[0] = 0;
|
||
m_info.DirCount = 0;
|
||
m_info.FileCount = 0;
|
||
m_info.DirEntry = 0;
|
||
m_info.FileEntry = 0;
|
||
wcscpy(path_w,sdataRoot_w);
|
||
//wcscpy(pathu_w,path_w);
|
||
pPathTop = (wchar_t*)((u32)&path_w+strlen(sdataName)*2+2);
|
||
|
||
}
|
||
|
||
void SaveData::Finalize()
|
||
{
|
||
Close();
|
||
Unmount();
|
||
}
|
||
//デストラクタ
|
||
SaveData::~SaveData()
|
||
{
|
||
Finalize();
|
||
}
|
||
|
||
|
||
|