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

356 lines
11 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[PATHLENGTH_MAX_SD];//sdmc:/filer/UserSaveData/YearMtDtHrMtSc/00000000
#define ROOTLENGTH_SD 49
wchar_t fp_path[PATHLENGTH_MAX_SD];
wchar_t ti_path[PATHLENGTH_MAX_SD];
wchar_t expath_w[PATHLENGTH_MAX_SD];//パス名
//wchar_t expathu_w[100][PATHLENGTH_MAX_SD];//上層パス名
wchar_t expathw_w[PATHLENGTH_MAX_SD];//パス名ワーク
wchar_t latestPath_w[PATHLENGTH_MAX_SD];//sdmc:/filer/UserSaveData/YearMtDtHrMtSc
bool created;
//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;
}
//マウント
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;
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(LastNnResult.GetDescription()!=nn::fs::DESCRIPTION_DBM_DIRECTORY_NOT_FOUND)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::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();
}
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();
Unmount();
}
//デストラクタ
Sdmc::~Sdmc()
{
Finalize();
}