diff --git a/core/libs/prx/libSceSaveData.native/Export.cpp b/core/libs/prx/libSceSaveData.native/Export.cpp index b09e7deaa..58e898833 100644 --- a/core/libs/prx/libSceSaveData.native/Export.cpp +++ b/core/libs/prx/libSceSaveData.native/Export.cpp @@ -810,9 +810,10 @@ int APS5_VABI sceSaveDataCancel() { return 0; } -int APS5_VABI sceSaveDataDirNameSearch2() { - NotImplemented_nid_no_patch(__func__); - return 0; +int APS5_VABI sceSaveDataDirNameSearch2(const SaveDataDirNameSearchCond* cond, SaveDataDirNameSearchResult* result) { + const int rc = dirNameSearch(cond, result); + SAVEDATA_TRACE("dirNameSearch2 user=%d pattern=%s hit=%u set=%u -> 0x%08x", cond != nullptr ? cond->user_id : -1, cond != nullptr && cond->dir_name != nullptr ? cond->dir_name->data : "(all)", result != nullptr ? result->hit_num : 0u, result != nullptr ? result->set_num : 0u, static_cast(rc)); + return rc; } APS5_EXPORT("RvID8BVeg+g", sceSaveDataUnknown_RvID8BVeg); diff --git a/core/libs/tests/GuestSaveDataSearch.cpp b/core/libs/tests/GuestSaveDataSearch.cpp index 9cc13cdee..53d0cc506 100644 --- a/core/libs/tests/GuestSaveDataSearch.cpp +++ b/core/libs/tests/GuestSaveDataSearch.cpp @@ -12,6 +12,7 @@ extern "C" { int APS5_VABI sceSaveDataDirNameSearch(const SaveDataDirNameSearchCond*, SaveDataDirNameSearchResult*); +int APS5_VABI sceSaveDataDirNameSearch2(const SaveDataDirNameSearchCond*, SaveDataDirNameSearchResult*); int APS5_VABI sceSaveDataMount3(const SaveDataMount3*, SaveDataMountResult*); int APS5_VABI sceSaveDataUmount2(std::uint32_t, const SaveDataMountPoint*); int APS5_VABI sceSaveDataSetParam(const SaveDataMountPoint*, std::uint32_t, const void*, std::size_t); @@ -71,6 +72,22 @@ static void SortByKey() { Require(Search(1, 1, 3, &hits) == Names{"SORT_A", "SORT_C", "SORT_B"}, "user parameters must sort descending"); Require(Search(3, 0, 3, &hits) == Names{"SORT_B", "SORT_A", "SORT_C"}, "modification times must sort ascending"); Require(Search(3, 1, 1, &hits) == Names{"SORT_C"} && hits == 3, "the newest save must come first in descending modification time"); + SceSaveDataDirName pattern{}; + std::snprintf(pattern.data, sizeof(pattern.data), "SORT_%%"); + SaveDataDirNameSearchCond second{}; + second.user_id = 1; + second.dir_name = &pattern; + second.key = 1; + second.order = 1; + std::array secondNames{}; + SaveDataDirNameSearchResult secondResult{}; + secondResult.dir_names = secondNames.data(); + secondResult.dir_names_num = 3; + Require(sceSaveDataDirNameSearch2(&second, &secondResult) == 0, "the second search failed"); + Require(secondResult.hit_num == 3 && secondResult.set_num == 3, "the second search must return all three saves"); + Require(std::string(secondNames[0].data) == "SORT_A" && std::string(secondNames[1].data) == "SORT_C" && std::string(secondNames[2].data) == "SORT_B", "the second search must sort like the first"); + second.key = 6; + Require(sceSaveDataDirNameSearch2(&second, &secondResult) == SaveDataErrorParameter, "the second search must reject an unknown sort key"); SaveDataDirNameSearchCond cond{}; cond.user_id = 1; cond.key = 6; diff --git a/docs/dev/debt/libSceJson2.md b/docs/dev/debt/libSceJson2.md index 946784429..61011254e 100644 --- a/docs/dev/debt/libSceJson2.md +++ b/docs/dev/debt/libSceJson2.md @@ -8,5 +8,5 @@ ### Functional -- PPSA30601 imports declared without parameters, signatures unknown, added without an implementation because the title fails to load without them: [six sce::Json::Object::Pair, sce::Json::Object and sce::Json::Array::iterator members](../../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2), [sceMouseResetAbsolutePosition](../../../core/libs/prx/libSceMouse/Export.cpp) (libSceMouse) and [sceSaveDataDirNameSearch2](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) +- PPSA30601 imports declared without parameters, signatures unknown, added without an implementation because the title fails to load without them: [six sce::Json::Object::Pair, sce::Json::Object and sce::Json::Array::iterator members](../../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2) and [sceMouseResetAbsolutePosition](../../../core/libs/prx/libSceMouse/Export.cpp) (libSceMouse) - [sce::Json::InitParameter2 base-object constructor](../../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2) - forwards to the complete-object constructor and uses its inferred layout and default field values; constructor equivalence and initialization bytes remain unverified on the console diff --git a/docs/dev/debt/libSceSaveData.native.md b/docs/dev/debt/libSceSaveData.native.md index cd0b5ce0b..dfec69c2a 100644 --- a/docs/dev/debt/libSceSaveData.native.md +++ b/docs/dev/debt/libSceSaveData.native.md @@ -8,3 +8,8 @@ - [sceSaveDataCancel](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - imported by PPSA23126, which fails to load without it; added without an implementation because its signature is unknown. Every save data call here finishes before it returns, so nothing is ever in flight to cancel, but what the console returns then is unknown - [sceSaveDataDirNameSearch](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - the sort keys (0 directory name, 1 user parameter, 2 blocks, 3 modification time, 5 free blocks) and orders (0 ascending, 1 descending) follow shadPS4, not a hardware run; saves with equal keys keep directory-name order before a descending reverse. Every native save reports `SAVE_DATA_BLOCKS_MAX` blocks, as `sceSaveDataGetMountInfo` does, so the two block keys keep directory-name order. The search infos (blocks, free blocks and 32 reserved bytes per returned name, following shadPS4's `OrbisSaveDataSearchInfo`) report `SAVE_DATA_BLOCKS_MAX` for both. Keys other than 0, 1, 2, 3 and 5 (including 4) and orders above 1 return `SCE_SAVE_DATA_ERROR_PARAMETER`; shadPS4 and KytyPS5 only reject keys above 5, so key 4 is rejected here because no source names it. In the directory name pattern `%` matches any run of characters, none included, and `_` exactly one, as the comments of shadPS4's matcher describe; also not confirmed on hardware - [sceSaveDataInitialize3](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - a repeated initialize succeeds: PPSA12544's executable and its Unity SaveData plugin both initialize, and the plugin fails on any error. Initializations are counted and `sceSaveDataTerminate` ends the session at the last one; how the console pairs them is unknown + +### Functional + +- [sceSaveDataDirNameSearch2](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) runs the same search as `sceSaveDataDirNameSearch` with the same condition and result structures, as [SharpEmu](https://github.com/sharpemu/sharpemu/blob/main/src/SharpEmu.Libs/SaveData/SaveDataExports.cs) does, its only source; what distinguishes it on the console is unknown. +