diff --git a/rpcs3/Emu/Cell/Modules/cellSearch.cpp b/rpcs3/Emu/Cell/Modules/cellSearch.cpp index 2fc1e16db1..8ce1f4fda3 100644 --- a/rpcs3/Emu/Cell/Modules/cellSearch.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSearch.cpp @@ -10,6 +10,8 @@ #include "Utilities/StrUtil.h" #include "util/media_utils.h" +#include + LOG_CHANNEL(cellSearch); template<> @@ -386,16 +388,16 @@ error_code cellSearchInitialize(CellSearchMode mode, u32 container, vm::ptrget(); if (error_code error = check_search_state(search.state.compare_and_swap(search_state::not_initialized, search_state::initializing), search_state::initializing)) @@ -450,6 +452,9 @@ error_code cellSearchStartListSearch(CellSearchListSearchType type, CellSearchSo return CELL_SEARCH_ERROR_PARAM; } + // Reset values first + *outSearchId = 0; + const char* media_dir; switch (type) @@ -479,6 +484,11 @@ error_code cellSearchStartListSearch(CellSearchListSearchType type, CellSearchSo return CELL_SEARCH_ERROR_PARAM; } + if (sortOrder != CELL_SEARCH_SORTORDER_ASCENDING) + { + return CELL_SEARCH_ERROR_NOT_SUPPORTED_SEARCH; + } + auto& search = g_fxo->get(); if (error_code error = check_search_state(search.state.compare_and_swap(search_state::idle, search_state::in_progress), search_state::in_progress)) @@ -675,6 +685,12 @@ error_code cellSearchStartContentSearchInList(vm::cptr list { cellSearch.todo("cellSearchStartContentSearchInList(listId=*0x%x, sortKey=0x%x, sortOrder=0x%x, outSearchId=*0x%x)", listId, +sortKey, +sortOrder, outSearchId); + // Reset values first + if (outSearchId) + { + *outSearchId = 0; + } + if (!listId || !outSearchId) { return CELL_SEARCH_ERROR_PARAM; @@ -693,6 +709,7 @@ error_code cellSearchStartContentSearchInList(vm::cptr list case CELL_SEARCH_SORTKEY_USERDEFINED: case CELL_SEARCH_SORTKEY_MODIFIEDDATE: break; + case CELL_SEARCH_SORTKEY_NONE: default: return CELL_SEARCH_ERROR_PARAM; } @@ -895,6 +912,12 @@ error_code cellSearchStartContentSearch(CellSearchContentSearchType type, CellSe { cellSearch.todo("cellSearchStartContentSearch(type=0x%x, sortKey=0x%x, sortOrder=0x%x, outSearchId=*0x%x)", +type, +sortKey, +sortOrder, outSearchId); + // Reset values first + if (outSearchId) + { + *outSearchId = 0; + } + if (!outSearchId) { return CELL_SEARCH_ERROR_PARAM; @@ -941,6 +964,59 @@ error_code cellSearchStartContentSearch(CellSearchContentSearchType type, CellSe return error; } + if (sortKey == CELL_SEARCH_SORTKEY_DEFAULT) + { + switch (type) + { + case CELL_SEARCH_CONTENTSEARCHTYPE_MUSIC_ALL: sortKey = CELL_SEARCH_SORTKEY_ARTISTNAME; break; + case CELL_SEARCH_CONTENTSEARCHTYPE_PHOTO_ALL: sortKey = CELL_SEARCH_SORTKEY_TAKENDATE; break; + case CELL_SEARCH_CONTENTSEARCHTYPE_VIDEO_ALL: sortKey = CELL_SEARCH_SORTKEY_TITLE; break; + default: break; + } + } + + if (sortKey != CELL_SEARCH_SORTKEY_IMPORTEDDATE && sortKey != CELL_SEARCH_SORTKEY_MODIFIEDDATE) + { + switch (type) + { + case CELL_SEARCH_CONTENTSEARCHTYPE_MUSIC_ALL: + { + if (sortOrder != CELL_SEARCH_SORTORDER_ASCENDING) + { + return CELL_SEARCH_ERROR_NOT_SUPPORTED_SEARCH; + } + if (sortKey != CELL_SEARCH_SORTKEY_ARTISTNAME && + sortKey != CELL_SEARCH_SORTKEY_ALBUMTITLE && + sortKey != CELL_SEARCH_SORTKEY_GENRENAME && + sortKey != CELL_SEARCH_SORTKEY_TITLE) + { + return CELL_SEARCH_ERROR_NOT_SUPPORTED_SEARCH; + } + break; + } + case CELL_SEARCH_CONTENTSEARCHTYPE_PHOTO_ALL: + { + if (sortKey != CELL_SEARCH_SORTKEY_TAKENDATE) + { + if (sortOrder != CELL_SEARCH_SORTORDER_ASCENDING || sortKey != CELL_SEARCH_SORTKEY_TITLE) + { + return CELL_SEARCH_ERROR_NOT_SUPPORTED_SEARCH; + } + } + break; + } + case CELL_SEARCH_CONTENTSEARCHTYPE_VIDEO_ALL: + { + if (sortOrder != CELL_SEARCH_SORTORDER_ASCENDING || sortKey != CELL_SEARCH_SORTKEY_TITLE) + { + return CELL_SEARCH_ERROR_NOT_SUPPORTED_SEARCH; + } + break; + } + default: break; + } + } + const u32 id = *outSearchId = idm::make(); sysutil_register_cb([=, &content_map = g_fxo->get(), &search](ppu_thread& ppu) -> s32 @@ -1077,6 +1153,12 @@ error_code cellSearchStartSceneSearchInVideo(vm::cptr video { cellSearch.todo("cellSearchStartSceneSearchInVideo(videoId=*0x%x, searchType=0x%x, sortOrder=0x%x, outSearchId=*0x%x)", videoId, +searchType, +sortOrder, outSearchId); + // Reset values first + if (outSearchId) + { + *outSearchId = 0; + } + if (!videoId || !outSearchId) { return CELL_SEARCH_ERROR_PARAM; @@ -1084,13 +1166,13 @@ error_code cellSearchStartSceneSearchInVideo(vm::cptr video switch (searchType) { - case CELL_SEARCH_SCENESEARCHTYPE_NONE: case CELL_SEARCH_SCENESEARCHTYPE_CHAPTER: case CELL_SEARCH_SCENESEARCHTYPE_CLIP_HIGHLIGHT: case CELL_SEARCH_SCENESEARCHTYPE_CLIP_USER: case CELL_SEARCH_SCENESEARCHTYPE_CLIP: case CELL_SEARCH_SCENESEARCHTYPE_ALL: break; + case CELL_SEARCH_SCENESEARCHTYPE_NONE: default: return CELL_SEARCH_ERROR_PARAM; } @@ -1141,6 +1223,12 @@ error_code cellSearchStartSceneSearch(CellSearchSceneSearchType searchType, vm:: { cellSearch.todo("cellSearchStartSceneSearch(searchType=0x%x, gameTitle=%s, tags=**0x%x, tagNum=0x%x, sortKey=0x%x, sortOrder=0x%x, outSearchId=*0x%x)", +searchType, gameTitle, tags, tagNum, +sortKey, +sortOrder, outSearchId); + // Reset values first + if (outSearchId) + { + *outSearchId = 0; + } + if (!gameTitle || !outSearchId) { return CELL_SEARCH_ERROR_PARAM; @@ -1148,13 +1236,31 @@ error_code cellSearchStartSceneSearch(CellSearchSceneSearchType searchType, vm:: switch (searchType) { - case CELL_SEARCH_SCENESEARCHTYPE_NONE: case CELL_SEARCH_SCENESEARCHTYPE_CHAPTER: case CELL_SEARCH_SCENESEARCHTYPE_CLIP_HIGHLIGHT: case CELL_SEARCH_SCENESEARCHTYPE_CLIP_USER: case CELL_SEARCH_SCENESEARCHTYPE_CLIP: case CELL_SEARCH_SCENESEARCHTYPE_ALL: break; + case CELL_SEARCH_SCENESEARCHTYPE_NONE: + default: + return CELL_SEARCH_ERROR_PARAM; + } + + switch (sortKey) + { + case CELL_SEARCH_SORTKEY_DEFAULT: + case CELL_SEARCH_SORTKEY_TITLE: + case CELL_SEARCH_SORTKEY_ALBUMTITLE: + case CELL_SEARCH_SORTKEY_GENRENAME: + case CELL_SEARCH_SORTKEY_ARTISTNAME: + case CELL_SEARCH_SORTKEY_IMPORTEDDATE: + case CELL_SEARCH_SORTKEY_TRACKNUMBER: + case CELL_SEARCH_SORTKEY_TAKENDATE: + case CELL_SEARCH_SORTKEY_USERDEFINED: + case CELL_SEARCH_SORTKEY_MODIFIEDDATE: + break; + case CELL_SEARCH_SORTKEY_NONE: default: return CELL_SEARCH_ERROR_PARAM; } @@ -1175,6 +1281,14 @@ error_code cellSearchStartSceneSearch(CellSearchSceneSearchType searchType, vm:: } } + if (sortKey != CELL_SEARCH_SORTKEY_DEFAULT && + sortKey != CELL_SEARCH_SORTKEY_IMPORTEDDATE && + sortKey != CELL_SEARCH_SORTKEY_MODIFIEDDATE && + (sortKey != CELL_SEARCH_SORTKEY_TITLE || sortOrder != CELL_SEARCH_SORTORDER_ASCENDING)) + { + return CELL_SEARCH_ERROR_NOT_SUPPORTED_SEARCH; + } + auto& search = g_fxo->get(); if (error_code error = check_search_state(search.state.compare_and_swap(search_state::idle, search_state::in_progress), search_state::in_progress)) @@ -1202,9 +1316,21 @@ error_code cellSearchGetContentInfoByOffset(CellSearchId searchId, s32 offset, v { cellSearch.warning("cellSearchGetContentInfoByOffset(searchId=0x%x, offset=0x%x, infoBuffer=*0x%x, outContentType=*0x%x, outContentId=*0x%x)", searchId, offset, infoBuffer, outContentType, outContentId); - if (!outContentType) + // Reset values first + if (outContentType) { - return CELL_SEARCH_ERROR_PARAM; + *outContentType = CELL_SEARCH_CONTENTTYPE_NONE; + } + + if (infoBuffer) + { + std::memset(infoBuffer.get_ptr(), 0, CELL_SEARCH_CONTENT_BUFFER_SIZE_MAX); + } + + if (outContentId) + { + std::memset(outContentId->data, 0, 4); + std::memset(outContentId->data + 4, -1, CELL_SEARCH_CONTENT_ID_SIZE - 4); } const auto searchObject = idm::get(searchId); @@ -1214,6 +1340,11 @@ error_code cellSearchGetContentInfoByOffset(CellSearchId searchId, s32 offset, v return CELL_SEARCH_ERROR_INVALID_SEARCHID; } + if (!outContentType || (!outContentId && !infoBuffer)) + { + return CELL_SEARCH_ERROR_PARAM; + } + if (error_code error = check_search_state(g_fxo->get().state.load(), search_state::in_progress)) { return error; @@ -1253,7 +1384,11 @@ error_code cellSearchGetContentInfoByOffset(CellSearchId searchId, s32 offset, v const u128 content_id_128 = content_id.first; *outContentType = content_info->type; - std::memcpy(outContentId->data, &content_id_128, CELL_SEARCH_CONTENT_ID_SIZE); + + if (outContentId) + { + std::memcpy(outContentId->data, &content_id_128, CELL_SEARCH_CONTENT_ID_SIZE); + } } else // content ID not found, perform a search first { @@ -1267,7 +1402,18 @@ error_code cellSearchGetContentInfoByContentId(vm::cptr con { cellSearch.warning("cellSearchGetContentInfoByContentId(contentId=*0x%x, infoBuffer=*0x%x, outContentType=*0x%x)", contentId, infoBuffer, outContentType); - if (!outContentType) + // Reset values first + if (outContentType) + { + *outContentType = CELL_SEARCH_CONTENTTYPE_NONE; + } + + if (infoBuffer) + { + std::memset(infoBuffer.get_ptr(), 0, CELL_SEARCH_CONTENT_BUFFER_SIZE_MAX); + } + + if (!outContentType || !contentId) { return CELL_SEARCH_ERROR_PARAM; } @@ -1323,9 +1469,9 @@ error_code cellSearchGetOffsetByContentId(CellSearchId searchId, vm::cptrget().state.load(), search_state::in_progress)) @@ -1340,6 +1486,11 @@ error_code cellSearchGetOffsetByContentId(CellSearchId searchId, vm::cptr(contentId->data); for (auto& content_id : searchObject->content_ids) @@ -1359,9 +1510,23 @@ error_code cellSearchGetContentIdByOffset(CellSearchId searchId, s32 offset, vm: { cellSearch.todo("cellSearchGetContentIdByOffset(searchId=0x%x, offset=0x%x, outContentType=*0x%x, outContentId=*0x%x, outTimeInfo=*0x%x)", searchId, offset, outContentType, outContentId, outTimeInfo); - if (!outContentType || !outContentId) + // Reset values first + if (outTimeInfo) { - return CELL_SEARCH_ERROR_PARAM; + outTimeInfo->modifiedDate = -1; + outTimeInfo->takenDate = -1; + outTimeInfo->importedDate = -1; + } + + if (outContentType) + { + *outContentType = CELL_SEARCH_CONTENTTYPE_NONE; + } + + if (outContentId) + { + std::memset(outContentId->data, 0, 4); + std::memset(outContentId->data + 4, -1, CELL_SEARCH_CONTENT_ID_SIZE - 4); } const auto searchObject = idm::get(searchId); @@ -1371,6 +1536,11 @@ error_code cellSearchGetContentIdByOffset(CellSearchId searchId, s32 offset, vm: return CELL_SEARCH_ERROR_INVALID_SEARCHID; } + if (!outContentType || !outContentId) + { + return CELL_SEARCH_ERROR_PARAM; + } + if (error_code error = check_search_state(g_fxo->get().state.load(), search_state::in_progress)) { return error; @@ -1401,6 +1571,12 @@ error_code cellSearchGetContentInfoGameComment(vm::cptr con { cellSearch.todo("cellSearchGetContentInfoGameComment(contentId=*0x%x, gameComment=*0x%x)", contentId, gameComment); + // Reset values first + if (gameComment) + { + gameComment[0] = 0; + } + if (!contentId || !gameComment) { return CELL_SEARCH_ERROR_PARAM; @@ -1445,6 +1621,9 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptrdata, 0, 4); + const auto searchObject = idm::get(searchId); if (!searchObject) @@ -1472,6 +1651,20 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr std::shared_ptr + { + if (searchObject->content_ids.size() == 1) + { + return first_content; + } + std::vector result; + std::sample(searchObject->content_ids.begin(), searchObject->content_ids.end(), std::back_inserter(result), 1, std::mt19937{std::random_device{}()}); + ensure(result.size() == 1); + std::shared_ptr content = result[0].second; + ensure(!!content); + return content; + }; + if (contentId) { // Try to find the specified content @@ -1500,6 +1693,13 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr content = get_random_content(); + context.content_path = content->infoPath.contentPath; + cellSearch.notice("cellSearchGetMusicSelectionContext(): Hash=%08X, Assigning random track: Type=0x%x, Path=%s", content_hash, +content->type, context.content_path); + } else { // Select the first track by default @@ -1512,6 +1712,13 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr content = get_random_content(); + context.content_path = content->infoPath.contentPath; + cellSearch.notice("cellSearchGetMusicSelectionContext(): Assigning random track: Type=0x%x, Path=%s", +content->type, context.content_path); + } else { // Select the first track by default @@ -1540,6 +1747,12 @@ error_code cellSearchGetMusicSelectionContextOfSingleTrack(vm::cptrdata, 0, 4); + } + if (!contentId || !outContext) { return CELL_SEARCH_ERROR_PARAM; @@ -1587,7 +1800,13 @@ error_code cellSearchGetContentInfoPath(vm::cptr contentId, { cellSearch.todo("cellSearchGetContentInfoPath(contentId=*0x%x, infoPath=*0x%x)", contentId, infoPath); - if (!infoPath) + // Reset values first + if (infoPath) + { + *infoPath = {}; + } + + if (!contentId || !infoPath) { return CELL_SEARCH_ERROR_PARAM; } @@ -1619,6 +1838,12 @@ error_code cellSearchGetContentInfoPathMovieThumb(vm::cptr { cellSearch.todo("cellSearchGetContentInfoPathMovieThumb(contentId=*0x%x, infoMt=*0x%x)", contentId, infoMt); + // Reset values first + if (infoMt) + { + *infoMt = {}; + } + if (!contentId || !infoMt) { return CELL_SEARCH_ERROR_PARAM; @@ -1680,6 +1905,12 @@ error_code cellSearchGetContentInfoDeveloperData(vm::cptr c { cellSearch.todo("cellSearchGetContentInfoDeveloperData(contentId=*0x%x, developerData=*0x%x)", contentId, developerData); + // Reset values first + if (developerData) + { + developerData[0] = 0; + } + if (!contentId || !developerData) { return CELL_SEARCH_ERROR_PARAM; @@ -1718,6 +1949,12 @@ error_code cellSearchGetContentInfoSharable(vm::cptr conten { cellSearch.todo("cellSearchGetContentInfoSharable(contentId=*0x%x, sharable=*0x%x)", contentId, sharable); + // Reset values first + if (sharable) + { + *sharable = CELL_SEARCH_SHARABLETYPE_PROHIBITED; + } + if (!contentId || !sharable) { return CELL_SEARCH_ERROR_PARAM; @@ -1774,6 +2011,11 @@ error_code cellSearchEnd(CellSearchId searchId) { cellSearch.todo("cellSearchEnd(searchId=0x%x)", searchId); + if (!searchId) // This check has to come first + { + return CELL_SEARCH_ERROR_INVALID_SEARCHID; + } + if (error_code error = check_search_state(g_fxo->get().state.load(), search_state::finalizing)) { return error;