mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
459 lines
14 KiB
C++
459 lines
14 KiB
C++
/*
|
||
|
||
Horizon/tools/SaveDataFiler で読めるファイルを作成
|
||
|
||
*/
|
||
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <cstdio>
|
||
#include <iomanip>
|
||
#include <wchar.h>
|
||
#include <string.h>
|
||
#include <nn/fs.h>
|
||
//#include <../fs/fs_ResultPrivate.h>
|
||
#include "sdmc.h"
|
||
|
||
const char *sdmcName = "sdmc:";
|
||
#define PATHLENGTH_MAX_SD 512
|
||
|
||
wchar_t sdmcRoot_w[MAX_PATH_LENGTH];//sdmc:/filer/UserSaveData/YearMtDtHrMtSc/00000000
|
||
#define ROOTLENGTH_SD 49
|
||
wchar_t fp_path[MAX_PATH_LENGTH];
|
||
wchar_t ti_path[MAX_PATH_LENGTH];
|
||
wchar_t expath_w[MAX_PATH_LENGTH];//パス名
|
||
//wchar_t expathu_w[100][PATHLENGTH_MAX_SD];//上層パス名
|
||
wchar_t expathw_w[MAX_PATH_LENGTH];//パス名ワーク
|
||
wchar_t latestPath_w[MAX_PATH_LENGTH];//sdmc:/filer/UserSaveData/YearMtDtHrMtSc
|
||
bool created;
|
||
bool IsMounted;
|
||
|
||
//SDKツールのSaveFilerのフォーマットに合わせる
|
||
//------------ sources\tools\NandFiler\nandf_Dialog.h 参照
|
||
const wchar_t SDMC_ROOT_DIR_NAME[] = L"sdmc:/filer";
|
||
|
||
struct FormatParameters
|
||
{
|
||
size_t m_LimitSize;
|
||
size_t m_MaxDir;
|
||
size_t m_MaxFile;
|
||
s32 m_IconSize;
|
||
bit8 *m_pIconData;
|
||
bool m_Duplicate;
|
||
|
||
FormatParameters()
|
||
: m_LimitSize(0),m_IconSize(0), m_pIconData(0) {}
|
||
//オリジナルはLinitSize不定
|
||
};
|
||
|
||
struct AdditionalInfo
|
||
{
|
||
bit64 m_Version;
|
||
bit64 m_Id;
|
||
bit64 m_Reserved[128];//オリジナルは乱数埋
|
||
AdditionalInfo()
|
||
: m_Version(0), m_Id(0) {}
|
||
};
|
||
//--------------------------- nandf_util.cpp 参照
|
||
std::wstring Sdmc::GetDateName()
|
||
{
|
||
nn::fnd::DateTime tm = nn::fnd::DateTime::GetNow();
|
||
|
||
std::wostringstream name;
|
||
name << std::setw(4) << std::setfill(L'0') << tm.GetYear()
|
||
<< std::setw(2) << std::setfill(L'0') << tm.GetMonth()
|
||
<< std::setw(2) << std::setfill(L'0') << tm.GetDay()
|
||
<< std::setw(2) << std::setfill(L'0') << tm.GetHour()
|
||
<< std::setw(2) << std::setfill(L'0') << tm.GetMinute()
|
||
<< std::setw(2) << std::setfill(L'0') << tm.GetSecond();
|
||
|
||
|
||
//char型 :表示で使う
|
||
wcstombs(DirName, name.str().c_str(), 14);
|
||
DirName[14] = 0;
|
||
return name.str();
|
||
}
|
||
|
||
nn::Result CreateDirIfNotExists(const wchar_t *dirName)
|
||
{
|
||
nn::fs::Directory dir;
|
||
nn::Result result = dir.TryInitialize(dirName);
|
||
NN_LOG("%d",result.GetDescription());
|
||
if (!nn::fs::ResultAlreadyExists::Includes(result) && result.IsFailure())
|
||
{
|
||
result = nn::fs::TryCreateDirectory(dirName);
|
||
}
|
||
dir.Finalize();
|
||
return result;
|
||
}
|
||
|
||
bit64 ChangeId(bit64 id, bit64 key)
|
||
{
|
||
return id ^ key ^ 0xce8a4d52f7105339;
|
||
}
|
||
|
||
//-----------------------------
|
||
|
||
|
||
//SDMCにライト専用アーカイブ
|
||
//ディレクトリもファイルも読めない
|
||
|
||
//直前のCreateで作成したDateTimeフォルダ削除
|
||
bool Sdmc::Delete()
|
||
{
|
||
if (created==false)return true;
|
||
if (Mount() == RESULT_FAIL_MOUNT)return false;
|
||
LastNnResult = nn::fs::TryDeleteDirectoryRecursively(latestPath_w);
|
||
Unmount();
|
||
return LastNnResult.IsSuccess();
|
||
}
|
||
|
||
//全削除
|
||
bool Sdmc::DeleteAll()
|
||
{
|
||
if (Mount() == RESULT_FAIL_MOUNT)return false;
|
||
LastNnResult = nn::fs::TryDeleteDirectoryRecursively(SDMC_ROOT_DIR_NAME);
|
||
Unmount();
|
||
return LastNnResult.IsSuccess();
|
||
}
|
||
|
||
|
||
//保存先のディレクトリ作成
|
||
//成功時はマウント状態
|
||
bool Sdmc::Create()
|
||
{
|
||
std::wostringstream woss;
|
||
created = false;
|
||
if (Mount() == RESULT_FAIL_MOUNT)return false;
|
||
|
||
LastNnResult = CreateDirIfNotExists(SDMC_ROOT_DIR_NAME);//sdmc:/filer
|
||
if (LastNnResult.IsSuccess())
|
||
{
|
||
woss << SDMC_ROOT_DIR_NAME << L"/" << L"UserSaveData";//sdmc:/filer/UserSaveData
|
||
LastNnResult = CreateDirIfNotExists(woss.str().c_str());
|
||
if (LastNnResult.IsSuccess())
|
||
{
|
||
DateDirName = GetDateName();
|
||
woss << L"/" << DateDirName;//sdmc:/filer/UserSaveData/YearMtDtHrMtSc
|
||
LastNnResult = nn::fs::TryCreateDirectory(woss.str().c_str());
|
||
if (LastNnResult.IsSuccess())
|
||
{
|
||
wcscpy(latestPath_w,woss.str().c_str());
|
||
created = true;//日時ディレクトリ作成フラグ
|
||
//コピー先ルート
|
||
woss << L"/" << "00000000";//sdmc:/filer/UserSaveData/YearMtDtHrMtSc/00000000
|
||
LastNnResult = nn::fs::TryCreateDirectory(woss.str().c_str());
|
||
if (LastNnResult.IsSuccess())
|
||
{
|
||
woss << L"/";//sdmc:/filer/UserSaveData/YearMtDtHrMtSc/00000000/
|
||
wcscpy(sdmcRoot_w,woss.str().c_str());
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
Unmount();
|
||
return false;
|
||
}
|
||
|
||
//格納先パスの取得
|
||
//先にCreateしとくこと
|
||
void Sdmc::GetRootPath(wchar_t *path)
|
||
{
|
||
wcscpy(path,sdmcRoot_w);
|
||
}
|
||
|
||
|
||
//マウント
|
||
myResult Sdmc::Mount()
|
||
{
|
||
if ( IsMounted )return RESULT_ALREADY_MOUNT;
|
||
LastNnResult = nn::fs::MountSdmc(sdmcName);
|
||
if (LastNnResult.IsFailure()){
|
||
return RESULT_FAIL_MOUNT;
|
||
}
|
||
IsMounted = true;
|
||
return RESULT_OK;
|
||
}
|
||
void Sdmc::Unmount()
|
||
{
|
||
IsMounted = false;
|
||
nn::fs::Unmount(sdmcName);
|
||
}
|
||
//ライト属性ファイルを閉じる
|
||
void Sdmc::CloseW()
|
||
{
|
||
writer.Finalize();
|
||
}
|
||
|
||
//ファイルライト
|
||
s32 Sdmc::Write(char *buffer,size_t size)
|
||
{
|
||
s32 ct;
|
||
LastNnResult = writer.TryWrite(&ct,(void*)buffer,size);
|
||
if(LastNnResult.IsFailure())ct=0;
|
||
return ct;
|
||
}
|
||
|
||
|
||
/*
|
||
//ライト属性ファイルを開く
|
||
bool Sdmc::OpenW(wchar_t *path,s64 size)
|
||
{
|
||
int pos,pos2;
|
||
wcscpy(expath_w,sdmcRoot_w);
|
||
wcscat(expath_w,path);
|
||
|
||
while(1){
|
||
LastNnResult = nn::fs::TryCreateFile(expath_w,size);
|
||
if(LastNnResult.IsSuccess())break;
|
||
if(nn::fs::ResultNotFound::Includes(LastNnResult)==false)return false;
|
||
NN_LOG("%d\n",LastNnResult.GetDescription());
|
||
//ディレクトリがなければディレクトリを作成
|
||
pos = GetPosDelmLast(expath_w,ROOTLENGTH_SD);//ファイルが存在するディレクトリ
|
||
if (pos <= 0)return false;//rootかパスが不正
|
||
wcscpy(expathw_w,expath_w);//ワークにコピー
|
||
while (LastNnResult.IsFailure())
|
||
{//ディレクトリ作成できるまで遡る
|
||
if(nn::fs::ResultNotFound::Includes(LastNnResult)==false)return false;
|
||
pos2 = GetPosDelmLast(expathw_w,ROOTLENGTH_SD);//境界位置を探す
|
||
if (pos2 == 0)return false;//root到達
|
||
expathw_w[pos2] = 0;//境界まで削除 (例) dir1/dir2/file -> dir1/dir2 -> dir1
|
||
LastNnResult = nn::fs::TryCreateDirectory(expathw_w);
|
||
}
|
||
}
|
||
|
||
LastNnResult = writer.TryInitialize(expath_w,false);
|
||
return LastNnResult.IsSuccess();
|
||
}
|
||
*/
|
||
|
||
bool Sdmc::OpenW(wchar_t *path,s64 size,bool *mkdir)
|
||
{
|
||
int pos,pos2;
|
||
|
||
wcscpy(expath_w,sdmcRoot_w);
|
||
wcscat(expath_w,path);
|
||
*mkdir = false;
|
||
LastNnResult = nn::fs::TryCreateFile(expath_w,size);
|
||
if(LastNnResult.IsSuccess())
|
||
{
|
||
LastNnResult = writer.TryInitialize(expath_w,false);
|
||
return LastNnResult.IsSuccess();
|
||
}
|
||
//ディレクトリがなければディレクトリを作成
|
||
pos = GetPosDelmLast(expath_w,ROOTLENGTH_SD);//ファイルが存在するディレクトリ
|
||
if (pos <= 0)return false;//rootかパスが不正
|
||
wcscpy(expathw_w,expath_w);//ワークにコピー
|
||
while (LastNnResult.IsFailure()){//ディレクトリ作成できるまで遡る
|
||
//if(LastNnResult.GetDescription()!=nn::fs::DESCRIPTION_DBM_DIRECTORY_NOT_FOUND)return false;
|
||
if(nn::fs::ResultNotFound::Includes(LastNnResult)==false)return false;
|
||
pos2 = GetPosDelmLast(expathw_w,ROOTLENGTH_SD);//境界位置を探す
|
||
if (pos2 == 0)return false;//root到達
|
||
expathw_w[pos2] = 0;//境界まで削除 (例) dir1/dir2/file -> dir1/dir2 -> dir1
|
||
LastNnResult = nn::fs::TryCreateDirectory(expathw_w);
|
||
}
|
||
//作成ディレクトリ多いと画面止まるので、作成ごとに抜ける
|
||
*mkdir = true; // 帰値:false で mkdir=true ならディレクトリ作成のみ
|
||
return false;
|
||
}
|
||
|
||
|
||
//パス名エラーで作成できない場合の退避先
|
||
//例:FAT規約違反、"/ test"->"/test"、SD格納先ディレクトリでパス長オーバー
|
||
bool Sdmc::OpenVnfW(wchar_t *path,s64 size)
|
||
{
|
||
s32 sz;
|
||
tVnf vnf;
|
||
//パス名&オフセット用ファイル
|
||
wcscpy(expath_w,latestPath_w);
|
||
wcscat(expath_w,L"/00000000.vnf");
|
||
if(reader.TryInitialize(expath_w).IsSuccess())
|
||
{
|
||
Close();
|
||
LastNnResult = writer.TryInitialize(expath_w,false);
|
||
if (LastNnResult.IsSuccess())
|
||
LastNnResult = writer.TrySeek(0,nn::fs::POSITION_BASE_END);//追記
|
||
}else LastNnResult = writer.TryInitialize(expath_w,true);//新規
|
||
if (LastNnResult.IsSuccess())
|
||
{
|
||
wcscpy(vnf.path,path);
|
||
vnf.size = size;
|
||
LastNnResult = writer.TryWrite(&sz,&vnf,sizeof(tVnf));//ヘッダ格納
|
||
}
|
||
if (LastNnResult.IsFailure())
|
||
{
|
||
writer.Finalize();
|
||
return false;
|
||
}
|
||
return true;
|
||
|
||
}
|
||
|
||
//退避ファイルをリード用に開く
|
||
//成功時はパス名のデータ先頭位置にシーク
|
||
bool Sdmc::OpenVnf(wchar_t *path)
|
||
{
|
||
s32 sz;
|
||
tVnf vnf;
|
||
wcscpy(expath_w,latestPath_w);
|
||
wcscat(expath_w,L"/00000000.vnf");
|
||
if(reader.TryInitialize(expath_w).IsSuccess())
|
||
{
|
||
while(1)
|
||
{
|
||
LastNnResult = reader.TryRead(&sz, &vnf, sizeof(vnf));//ヘッダ
|
||
if (LastNnResult.IsSuccess() && (sz == sizeof(tVnf)))
|
||
{
|
||
vnf.path[MAX_PATH_LENGTH-1] = 0;//念の為、終端
|
||
if(wcscmp(vnf.path,path) ==0)return true;//パス名一致
|
||
LastNnResult = reader.TrySeek(vnf.size,nn::fs::POSITION_BASE_CURRENT);//次
|
||
if (LastNnResult.IsFailure())return false;
|
||
}else return false;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
|
||
//情報ファイル
|
||
//
|
||
bool Sdmc::WriteSys(tArcInfo *ifo)
|
||
{//SaveFilerで読むためのファイル
|
||
std::wostringstream woss;
|
||
if (Mount() == RESULT_FAIL_MOUNT)return false;
|
||
woss << latestPath_w << L"/00000000";
|
||
// FormatParameter を保存
|
||
LastNnResult = writer.TryInitialize( (woss.str() + L".dat").c_str(), true);
|
||
if (LastNnResult.IsFailure()){Unmount();return false;}
|
||
s32 size;
|
||
FormatParameters Fparam;
|
||
Fparam.m_MaxDir = ifo->DirEntry;
|
||
Fparam.m_MaxFile = ifo->FileEntry;
|
||
Fparam.m_Duplicate = ifo->Dup;
|
||
LastNnResult = writer.TryWrite(&size, &Fparam, sizeof(FormatParameters));
|
||
if (LastNnResult.IsFailure()){Unmount();return false;}
|
||
LastNnResult = writer.TryFlush();
|
||
if (LastNnResult.IsFailure()){Unmount();return false;}
|
||
writer.Finalize();
|
||
//AdditionalInfoを保存
|
||
AdditionalInfo Ainfo;
|
||
LastNnResult = writer.TryInitialize((woss.str() + L"_.dat").c_str(), true);
|
||
if (LastNnResult.IsFailure()){ Unmount();return false;}
|
||
Ainfo.m_Version = 0;
|
||
Ainfo.m_Id = ChangeId(Ainfo.m_Id, static_cast<bit64>(std::wcstoll(DateDirName.c_str(), NULL, 10)));
|
||
LastNnResult = writer.TryWrite(&size, &Ainfo, sizeof(AdditionalInfo));
|
||
if (LastNnResult.IsFailure()){ Unmount();return false;}
|
||
LastNnResult = writer.TryFlush();
|
||
if (LastNnResult.IsFailure()){ Unmount();return false;}
|
||
writer.Finalize();
|
||
//ツールが使うファイル
|
||
std::wostringstream woss2;
|
||
woss2 << latestPath_w << L"/toolinfo.dat";
|
||
LastNnResult = writer.TryInitialize(woss2.str().c_str(), true);
|
||
if (LastNnResult.IsFailure()){ Unmount();return false;}
|
||
LastNnResult = writer.TryWrite(&size, ifo, sizeof(tArcInfo));
|
||
if (LastNnResult.IsFailure()){ Unmount();return false;}
|
||
LastNnResult = writer.TryFlush();
|
||
if (LastNnResult.IsFailure()){ Unmount();return false;}
|
||
writer.Finalize();
|
||
Unmount();
|
||
|
||
woss << L".dat";
|
||
wcscpy(fp_path,woss.str().c_str());
|
||
wcscpy(ti_path,woss2.str().c_str());
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
//アーカイブ情報の取得
|
||
bool Sdmc::GetInfo(tArcInfo *pinfo)
|
||
{
|
||
s32 size;
|
||
|
||
if (Mount() == RESULT_FAIL_MOUNT)return false;
|
||
|
||
// FormatParameter .. SaveFiler用ファイル
|
||
// FormatParameter を保存
|
||
LastNnResult = reader.TryInitialize( fp_path);
|
||
if (LastNnResult.IsFailure()){Unmount();return false;}
|
||
FormatParameters Fparam;
|
||
LastNnResult = reader.TryRead(&size, &Fparam, sizeof(FormatParameters));
|
||
if (LastNnResult.IsFailure()){Unmount();return false;}
|
||
reader.Finalize();
|
||
|
||
//ツール情報
|
||
LastNnResult = reader.TryInitialize( ti_path);
|
||
if (LastNnResult.IsFailure()){ Unmount();return false;}
|
||
LastNnResult = reader.TryRead(&size, &m_info, sizeof(tArcInfo));
|
||
if (LastNnResult.IsFailure()){ Unmount();return false;}
|
||
reader.Finalize();
|
||
|
||
//両ファイル共通パラメータのチェック
|
||
if((Fparam.m_MaxDir != m_info.DirEntry) ||
|
||
(Fparam.m_MaxFile != m_info.FileEntry) ||
|
||
(Fparam.m_Duplicate != m_info.Dup))return false;
|
||
|
||
*pinfo = m_info;
|
||
return true;
|
||
|
||
}
|
||
|
||
|
||
//ファイルを開く
|
||
//パス指定はルート以降
|
||
//(ex)data:/dir/file -> dir/file
|
||
bool Sdmc::Open(wchar_t *path)
|
||
{
|
||
wcscpy(expathw_w,sdmcRoot_w);
|
||
wcscat(expathw_w,path);
|
||
LastNnResult = reader.TryInitialize(expathw_w);
|
||
if (LastNnResult.IsSuccess())
|
||
{
|
||
LastNnResult = reader.TryGetSize(&FileSize);
|
||
if (LastNnResult.IsSuccess())return true;
|
||
else Close();
|
||
}
|
||
NN_LOG("sdmc:Open %d",LastNnResult.GetDescription());
|
||
return false;
|
||
}
|
||
|
||
|
||
void Sdmc::Close()
|
||
{
|
||
reader.Finalize();
|
||
}
|
||
|
||
//ファイルリード
|
||
s32 Sdmc::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;
|
||
}
|
||
|
||
|
||
//コンストラクタ
|
||
Sdmc::Sdmc()
|
||
{
|
||
IsMounted = false;
|
||
}
|
||
|
||
void Sdmc::Finalize()
|
||
{
|
||
CloseW();
|
||
Close();
|
||
Unmount();
|
||
}
|
||
//デストラクタ
|
||
Sdmc::~Sdmc()
|
||
{
|
||
Finalize();
|
||
}
|
||
|