/* Horizon/tools/SaveDataFiler で読めるファイルを作成 */ #include #include #include #include #include #include #include #include //#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(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(); }