/* Horizon/tools/SaveDataFiler で読めるファイルを作成 ライトのみアーカイブ使用 */ #include #include #include #include #include #include #include #include #include "sdmcwo.h" const char *devName = "sdmcwo:"; const wchar_t *devName_w = L"sdmcwo:"; #define PATHLENGTH_MAX_SD 512 wchar_t sdmcRoot_w[MAX_PATH_LENGTH];//filer/UserSaveData/YearMtDtHrMtSc/00000000 #define ROOTLENGTH_SD 51 wchar_t expath_w[MAX_PATH_LENGTH];//パス名 wchar_t expathw_w[MAX_PATH_LENGTH];//パス名ワーク wchar_t latestPath_w[MAX_PATH_LENGTH];//filer/UserSaveData/YearMtDtHrMtSc bool created; bool IsMounted; //SDKツールのSaveFilerのフォーマットに合わせる //------------ sources\tools\NandFiler\nandf_Dialog.h 参照 const wchar_t *SDMC_ROOT_DIR_NAME = L"/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 Sdmcwo::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(); } bit64 ChangeId(bit64 id, bit64 key) { return id ^ key ^ 0xce8a4d52f7105339; } //----------------------------- //ディレクトリ作成 //ディレクトリオープンも出来ないので、ライト試行 bool CreateDir(const wchar_t *dirName) { nn::Result result = nn::fs::TryCreateDirectory(dirName); if(result.IsSuccess())return true; return nn::fs::ResultAlreadyExists::Includes(result); } //SDMCにライト専用アーカイブ //ディレクトリもファイルも読めない //直前のCreateで作成したDateTimeフォルダ削除 bool Sdmcwo::Delete() { if (created==false)return true; if (Mount() == RESULT_FAIL_MOUNT)return false; LastNnResult = nn::fs::TryDeleteDirectoryRecursively(latestPath_w); Unmount(); return LastNnResult.IsSuccess(); } //全削除 bool Sdmcwo::DeleteAll() { if (Mount() == RESULT_FAIL_MOUNT)return false; std::wostringstream woss; woss << devName << SDMC_ROOT_DIR_NAME;//sdmc:/filer LastNnResult = nn::fs::TryDeleteDirectoryRecursively(woss.str().c_str()); Unmount(); return LastNnResult.IsSuccess(); } //保存先のディレクトリ作成 //成功時はマウント状態 bool Sdmcwo::Create() { std::wostringstream woss; created = false; if (Mount() == RESULT_FAIL_MOUNT)return false; woss << devName << SDMC_ROOT_DIR_NAME;//sdmc:/filer if (CreateDir(woss.str().c_str())) { woss << L"/" << L"UserSaveData";//sdmc:/filer/UserSaveData if ( CreateDir(woss.str().c_str()) ) { DateDirName = GetDateName(); woss << L"/" << DateDirName;//sdmc:/filer/UserSaveData/YearMtDtHrMtSc if ( CreateDir(woss.str().c_str()) ) { wcscpy(latestPath_w,woss.str().c_str()); created = true;//日時ディレクトリ作成フラグ //コピー先ルート woss << L"/" << "00000000";//sdmc:/filer/UserSaveData/YearMtDtHrMtSc/00000000 if ( CreateDir(woss.str().c_str()) ) { woss << L"/";//sdmc:/filer/UserSaveData/YearMtDtHrMtSc/00000000/ wcscpy(sdmcRoot_w,woss.str().c_str());//格納先パス保存 return true; } } } } Unmount(); return false; } //格納先パスの取得 //先にCreateしとくこと void Sdmcwo::GetRootPath(wchar_t *path) { wcscpy(path,sdmcRoot_w); } //マウント myResult Sdmcwo::Mount() { if ( IsMounted )return RESULT_ALREADY_MOUNT; LastNnResult = nn::fs::MountSdmcWriteOnly(devName); if (LastNnResult.IsFailure()){ return RESULT_FAIL_MOUNT; } IsMounted = true; return RESULT_OK; } void Sdmcwo::Unmount() { IsMounted = false; nn::fs::Unmount(devName); } //ライト属性ファイルを閉じる void Sdmcwo::CloseW() { writer.Finalize(); } //ファイルライト s32 Sdmcwo::Write(char *buffer,size_t size) { s32 ct; LastNnResult = writer.TryWrite(&ct,(void*)buffer,size); if(LastNnResult.IsFailure())ct=0; return ct; } //ライトでオープン bool Sdmcwo::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 Sdmcwo::OpenVnfW(wchar_t *path,s64 size) { s32 sz; tVnf vnf; //パス名&オフセット用ファイル wcscpy(expath_w,latestPath_w); wcscat(expath_w,L"/00000000.vnf"); 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 Sdmcwo::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(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(); return true; } //コンストラクタ Sdmcwo::Sdmcwo() { IsMounted = false; } void Sdmcwo::Finalize() { CloseW(); Unmount(); } //デストラクタ Sdmcwo::~Sdmcwo() { Finalize(); }