ctr_Repair/trunk/CardSaveData/common/savefile/sdmc.cpp

459 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

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.

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