ctr_Repair/trunk/CardSaveDataMover/body/source/savefile/savedata.cpp

446 lines
14 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.

#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();
}