diff --git a/rpcs3/Emu/FS/vfsStream.h b/rpcs3/Emu/FS/vfsStream.h index b7a640d8c3..8af37bd825 100644 --- a/rpcs3/Emu/FS/vfsStream.h +++ b/rpcs3/Emu/FS/vfsStream.h @@ -24,16 +24,16 @@ public: virtual u64 Write(const void* src, u64 size); - template __forceinline bool Write(const T& data) + template __forceinline bool SWrite(const T& data, u64 size = sizeof(T)) { - return Write(&data, sizeof(T)) == sizeof(T); + return Write(&data, size) == size; } virtual u64 Read(void* dst, u64 size); - template __forceinline bool Read(T& data) + template __forceinline bool SRead(T& data, u64 size = sizeof(T)) { - return Read(&data, sizeof(T)) == sizeof(T); + return Read(&data, size) == size; } virtual u64 Seek(s64 offset, vfsSeekMode mode = vfsSeekSet); @@ -41,4 +41,4 @@ public: virtual bool Eof(); virtual bool IsOpened() const; -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp index 2b05a74fb4..85c7cab81d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp @@ -311,6 +311,16 @@ __noinline s32 savedata_op( u32 userId, vm::ptr funcDone) { + // TODO: check arguments + + // try to lock the mutex (not sure how it originally works; std::try_to_lock makes it non-blocking) + std::unique_lock lock(g_savedata_dialog->mutex, std::try_to_lock); + + if (!lock) + { + return CELL_SAVEDATA_ERROR_BUSY; + } + static const std::string base_dir = "/dev_hdd0/home/00000001/savedata/"; // TODO: Get the path of the current or specified user vm::stackvar result(CPU); @@ -370,7 +380,7 @@ __noinline s32 savedata_op( save_entry.isNew = false; save_entry.size = 0; - for (const auto& entry2 : vfsDir(base_dir + entry->name)) + for (const auto entry2 : vfsDir(base_dir + entry->name)) { save_entry.size += entry2->size; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.h b/rpcs3/Emu/SysCalls/Modules/cellSaveData.h index 1bf9103637..224f8a9a9f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.h @@ -282,6 +282,8 @@ struct SaveDataEntry struct SaveDataDialogInstance { + std::mutex mutex; + SaveDataDialogInstance(); virtual ~SaveDataDialogInstance() = default; }; diff --git a/rpcs3/Gui/SaveDataDialog.cpp b/rpcs3/Gui/SaveDataDialog.cpp new file mode 100644 index 0000000000..ddd9d8b78e --- /dev/null +++ b/rpcs3/Gui/SaveDataDialog.cpp @@ -0,0 +1,4 @@ +#include "stdafx_gui.h" +#include "Emu/Memory/Memory.h" + +#include "SaveDataDialog.h" diff --git a/rpcs3/Gui/SaveDataDialog.h b/rpcs3/Gui/SaveDataDialog.h new file mode 100644 index 0000000000..ab113cc084 --- /dev/null +++ b/rpcs3/Gui/SaveDataDialog.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Emu/SysCalls/Modules/cellSaveData.h" + +class SaveDataDialogFrame : public SaveDataDialogInstance +{ +public: + +}; diff --git a/rpcs3/Loader/PSF.cpp b/rpcs3/Loader/PSF.cpp index f050301c65..838463a3d7 100644 --- a/rpcs3/Loader/PSF.cpp +++ b/rpcs3/Loader/PSF.cpp @@ -5,66 +5,126 @@ bool PSFLoader::Load(vfsStream& stream) { - Close(); + Clear(); - // Load Header - if (stream.Read(&m_header, sizeof(PSFHeader)) != sizeof(PSFHeader) || !m_header.CheckMagic()) + // load header + if (!stream.SRead(m_header)) { return false; } - m_psfindxs.resize(m_header.psf_entries_num); - m_entries.resize(m_header.psf_entries_num); - - // Load Indices - for (u32 i = 0; i < m_header.psf_entries_num; ++i) + // check magic + if (m_header.magic != *(u32*)"\0PSF") { - if (!stream.Read(m_psfindxs[i])) + LOG_ERROR(LOADER, "PSFLoader::Load() failed: unknown magic (0x%x)", m_header.magic); + return false; + } + + // check version + if (m_header.version != 0x101) + { + LOG_ERROR(LOADER, "PSFLoader::Load() failed: unknown version (0x%x)", m_header.version); + return false; + } + + // load indices + std::vector indices; + + indices.resize(m_header.entries_num); + + if (!stream.SRead(indices[0], sizeof(PSFDefTable) * m_header.entries_num)) + { + return false; + } + + // load key table + if (m_header.off_key_table > m_header.off_data_table) + { + LOG_ERROR(LOADER, "PSFLoader::Load() failed: off_key_table=0x%x, off_data_table=0x%x", m_header.off_key_table, m_header.off_data_table); + return false; + } + + const u32 key_table_size = m_header.off_data_table - m_header.off_key_table; + + std::unique_ptr keys(new char[key_table_size + 1]); + + stream.Seek(m_header.off_key_table); + + if (stream.Read(keys.get(), key_table_size) != key_table_size) + { + return false; + } + + keys.get()[key_table_size] = 0; + + // fill entries + m_entries.resize(m_header.entries_num); + + for (u32 i = 0; i < m_header.entries_num; ++i) + { + m_entries[i].fmt = indices[i].param_fmt; + + if (indices[i].key_off >= key_table_size) { return false; } - m_entries[i].fmt = m_psfindxs[i].psf_param_fmt; - } + m_entries[i].name = keys.get() + indices[i].key_off; - // Load Key Table - for (u32 i = 0; i < m_header.psf_entries_num; ++i) - { - stream.Seek(m_header.psf_offset_key_table + m_psfindxs[i].psf_key_table_offset); + // load data + stream.Seek(m_header.off_data_table + indices[i].data_off); - int c_pos = 0; - - while (c_pos < sizeof(m_entries[i].name) - 1) + if (indices[i].param_fmt == PSF_PARAM_INT && indices[i].param_len == 4 && indices[i].param_max == 4) { - char c; + // load int data - if (!stream.Read(c) || !c) + if (!stream.SRead(m_entries[i].vint)) { - break; + return false; + } + } + else if (indices[i].param_fmt == PSF_PARAM_STR && indices[i].param_max >= indices[i].param_len) + { + // load str data + + const u32 size = indices[i].param_len; + + std::unique_ptr str(new char[size + 1]); + + if (stream.Read(str.get(), size) != size) + { + return false; } - m_entries[i].name[c_pos++] = c; + str.get()[size] = 0; + + m_entries[i].vstr = str.get(); + } + else + { + LOG_ERROR(LOADER, "PSFLoader::Load() failed: (i=%d) fmt=0x%x, len=0x%x, max=0x%x", i, indices[i].param_fmt, indices[i].param_len, indices[i].param_max); + return false; } - - m_entries[i].name[c_pos] = 0; - } - - // Load Data Table - for (u32 i = 0; i < m_header.psf_entries_num; ++i) - { - stream.Seek(m_header.psf_offset_data_table + m_psfindxs[i].psf_data_tbl_offset); - stream.Read(m_entries[i].param, m_psfindxs[i].psf_param_len); - memset(m_entries[i].param + m_psfindxs[i].psf_param_len, 0, m_psfindxs[i].psf_param_max_len - m_psfindxs[i].psf_param_len); } return (m_loaded = true); } -void PSFLoader::Close() +bool PSFLoader::Save(vfsStream& stream) +{ + // TODO: Construct m_header + + m_loaded = true; + + // TODO: Save data + + return true; +} + +void PSFLoader::Clear() { m_loaded = false; m_header = {}; - m_psfindxs.clear(); m_entries.clear(); } @@ -81,26 +141,61 @@ const PSFEntry* PSFLoader::SearchEntry(const std::string& key) const return nullptr; } +PSFEntry& PSFLoader::AddEntry(const std::string& key, u16 fmt) +{ + for (auto& entry : m_entries) + { + if (key == entry.name) + { + entry.fmt = fmt; + return entry; + } + } + + PSFEntry new_entry = {}; + new_entry.fmt = fmt; + new_entry.name = key; + m_entries.push_back(new_entry); + + return m_entries.back(); +} + std::string PSFLoader::GetString(const std::string& key, std::string def) const { if (const auto entry = SearchEntry(key)) { - return entry->FormatString(); - } - else - { - return def; + if (entry->fmt == PSF_PARAM_STR) + { + return entry->vstr; + } } + + return def; } -u32 PSFLoader::GetInteger(const std::string& key, u32 def) const +s32 PSFLoader::GetInteger(const std::string& key, s32 def) const { if (const auto entry = SearchEntry(key)) { - return entry->FormatInteger(); - } - else - { - return def; + if (entry->fmt == PSF_PARAM_INT) + { + return entry->vint; + } } + + return def; +} + +void PSFLoader::SetString(const std::string& key, std::string value) +{ + auto& entry = AddEntry(key, PSF_PARAM_STR); + + entry.vstr = value; +} + +void PSFLoader::SetInteger(const std::string& key, s32 value) +{ + auto& entry = AddEntry(key, PSF_PARAM_INT); + + entry.vint = value; } diff --git a/rpcs3/Loader/PSF.h b/rpcs3/Loader/PSF.h index 9c0275d41b..4725bfc203 100644 --- a/rpcs3/Loader/PSF.h +++ b/rpcs3/Loader/PSF.h @@ -4,54 +4,42 @@ struct vfsStream; struct PSFHeader { - u32 psf_magic; - u32 psf_version; - u32 psf_offset_key_table; - u32 psf_offset_data_table; - u32 psf_entries_num; - - bool CheckMagic() const { return psf_magic == *(u32*)"\0PSF"; } + u32 magic; + u32 version; + u32 off_key_table; + u32 off_data_table; + u32 entries_num; }; -struct PSFDefTbl +struct PSFDefTable { - u16 psf_key_table_offset; - u16 psf_param_fmt; - u32 psf_param_len; - u32 psf_param_max_len; - u32 psf_data_tbl_offset; + u16 key_off; + u16 param_fmt; + u32 param_len; + u32 param_max; + u32 data_off; +}; + +enum : u16 +{ + PSF_PARAM_UNK = 0x0004, + PSF_PARAM_STR = 0x0204, + PSF_PARAM_INT = 0x0404, }; struct PSFEntry { - char name[128]; u16 fmt; - char param[4096]; + std::string name; - std::string FormatString() const - { - switch(fmt) - { - default: - case 0x0400: - case 0x0402: - return std::string(param); - case 0x0404: - return fmt::Format("0x%x", FormatInteger()); - } - } - - u32 FormatInteger() const - { - return *(u32*)param; - } + s32 vint; + std::string vstr; }; class PSFLoader { bool m_loaded = false; PSFHeader m_header = {}; - std::vector m_psfindxs; std::vector m_entries; public: @@ -64,7 +52,9 @@ public: bool Load(vfsStream& stream); - void Close(); + bool Save(vfsStream& stream); + + void Clear(); operator bool() const { @@ -72,6 +62,14 @@ public: } const PSFEntry* SearchEntry(const std::string& key) const; + + PSFEntry& PSFLoader::AddEntry(const std::string& key, u16 type); + std::string GetString(const std::string& key, std::string def = "") const; - u32 GetInteger(const std::string& key, u32 def = 0) const; + + s32 GetInteger(const std::string& key, s32 def = 0) const; + + void SetString(const std::string& key, std::string value); + + void SetInteger(const std::string& key, s32 value); }; diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index c457b915f1..2af0677da0 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -22,8 +22,8 @@ #include "Emu/Io/XInput/XInputPadHandler.h" #endif -#include "Emu/SysCalls/Modules/cellMsgDialog.h" #include "Gui/MsgDialog.h" +#include "Gui/SaveDataDialog.h" #include "Gui/GLGSFrame.h" #include @@ -41,9 +41,10 @@ wxDEFINE_EVENT(wxEVT_DBG_COMMAND, wxCommandEvent); IMPLEMENT_APP(Rpcs3App) Rpcs3App* TheApp; -std::string simplify_path(const std::string& path, bool is_dir); +extern std::string simplify_path(const std::string& path, bool is_dir); extern std::unique_ptr g_msg_dialog; +extern std::unique_ptr g_savedata_dialog; bool Rpcs3App::OnInit() { @@ -137,6 +138,7 @@ bool Rpcs3App::OnInit() }); g_msg_dialog.reset(new MsgDialogFrame); + g_savedata_dialog.reset(new SaveDataDialogFrame); TheApp = this; SetAppName(_PRGNAME_); diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 5ec09d62b6..24f977e5a7 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -183,6 +183,7 @@ + @@ -224,6 +225,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 82eaf2b9ea..5fe6acdcb5 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -99,6 +99,9 @@ Gui + + Gui + @@ -200,8 +203,8 @@ Gui - + Gui - + \ No newline at end of file