cellSearch updates from Brolijah

Co-authored-by: Brolijah <brolijahrh@gmail.com>
This commit is contained in:
Silent 2020-02-08 11:07:18 +01:00 committed by Ivan
parent bcbe324534
commit d2b83c69bb

View file

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
@ -6,6 +6,8 @@
#include "cellSysutil.h"
#include "cellSearch.h"
#include "xxhash.h"
#include "Utilities/StrUtil.h"
LOG_CHANNEL(cellSearch);
@ -42,12 +44,33 @@ void fmt_class_string<CellSearchError>::format(std::string& out, u64 arg)
});
}
namespace {
struct search_info
{
vm::ptr<CellSearchSystemCallback> func;
vm::ptr<void> userData;
};
struct search_content_t
{
CellSearchContentType type = CELL_SEARCH_CONTENTTYPE_NONE;
CellSearchTimeInfo timeInfo;
CellSearchContentInfoPath infoPath;
union
{
CellSearchMusicInfo music;
CellSearchPhotoInfo photo;
CellSearchVideoInfo video;
CellSearchMusicListInfo music_list;
CellSearchPhotoListInfo photo_list;
CellSearchVideoListInfo video_list;
CellSearchVideoSceneInfo scene;
} data;
};
using ContentIdType = std::pair<u64, std::shared_ptr<search_content_t>>;
using ContentIdMap = std::unordered_map<u64, std::shared_ptr<search_content_t>>;
struct search_object_t
{
// TODO: Figured out the correct values to set here
@ -55,18 +78,57 @@ struct search_object_t
static const u32 id_step = 1;
static const u32 id_count = 64;
static const u32 invalid = 0xFFFFFFFF;
std::vector<ContentIdType> content_ids;
};
enum class search_state
{
not_initialized = 0,
idle,
in_progress,
initializing,
canceling,
finalizing,
};
}
static search_state s_search_state = search_state::not_initialized;
error_code cellSearchInitialize(CellSearchMode mode, u32 container, vm::ptr<CellSearchSystemCallback> func, vm::ptr<void> userData)
{
cellSearch.warning("cellSearchInitialize(mode=0x%x, container=0x%x, func=*0x%x, userData=*0x%x)", +mode, container, func, userData);
if (!func)
{
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::not_initialized:
break;
case search_state::initializing:
return CELL_SEARCH_ERROR_BUSY;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
default:
return CELL_SEARCH_ERROR_ALREADY_INITIALIZED;
}
if (mode != CELL_SEARCH_MODE_NORMAL)
{
return CELL_SEARCH_ERROR_UNKNOWN_MODE;
}
const auto search = g_fxo->get<search_info>();
search->func = func;
search->userData = userData;
s_search_state = search_state::initializing;
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
s_search_state = search_state::idle;
func(ppu, CELL_SEARCH_EVENT_INITIALIZE_RESULT, CELL_OK, vm::null, userData);
return CELL_OK;
});
@ -76,12 +138,29 @@ error_code cellSearchInitialize(CellSearchMode mode, u32 container, vm::ptr<Cell
error_code cellSearchFinalize()
{
cellSearch.warning("cellSearchFinalize()");
cellSearch.todo("cellSearchFinalize()");
const auto search = g_fxo->get<search_info>();
sysutil_register_cb([=](ppu_thread& ppu) -> s32
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::initializing:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
s_search_state = search_state::finalizing;
sysutil_register_cb([=, search = g_fxo->get<search_info>()](ppu_thread& ppu) -> s32
{
s_search_state = search_state::not_initialized;
search->func(ppu, CELL_SEARCH_EVENT_FINALIZE_RESULT, CELL_OK, vm::null, search->userData);
return CELL_OK;
});
@ -98,16 +177,53 @@ error_code cellSearchStartListSearch(CellSearchListSearchType type, CellSearchSo
return CELL_SEARCH_ERROR_PARAM;
}
const auto search = g_fxo->get<search_info>();
switch (type)
{
case CELL_SEARCH_LISTSEARCHTYPE_MUSIC_ALBUM:
case CELL_SEARCH_LISTSEARCHTYPE_MUSIC_GENRE:
case CELL_SEARCH_LISTSEARCHTYPE_MUSIC_ARTIST:
case CELL_SEARCH_LISTSEARCHTYPE_PHOTO_YEAR:
case CELL_SEARCH_LISTSEARCHTYPE_PHOTO_MONTH:
case CELL_SEARCH_LISTSEARCHTYPE_PHOTO_ALBUM:
case CELL_SEARCH_LISTSEARCHTYPE_PHOTO_PLAYLIST:
case CELL_SEARCH_LISTSEARCHTYPE_VIDEO_ALBUM:
case CELL_SEARCH_LISTSEARCHTYPE_MUSIC_PLAYLIST:
break;
default:
return CELL_SEARCH_ERROR_PARAM;
}
if (sortOrder != CELL_SEARCH_SORTORDER_ASCENDING && sortOrder != CELL_SEARCH_SORTORDER_DESCENDING)
{
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
*outSearchId = idm::make<search_object_t>();
sysutil_register_cb([=](ppu_thread& ppu) -> s32
s_search_state = search_state::in_progress;
sysutil_register_cb([=, search = g_fxo->get<search_info>()](ppu_thread& ppu) -> s32
{
vm::var<CellSearchResultParam> resultParam;
resultParam->searchId = *outSearchId;
resultParam->resultNum = 0; // TODO
s_search_state = search_state::idle;
search->func(ppu, CELL_SEARCH_EVENT_LISTSEARCH_RESULT, CELL_OK, vm::cast(resultParam.addr()), search->userData);
return CELL_OK;
});
@ -124,16 +240,54 @@ error_code cellSearchStartContentSearchInList(vm::cptr<CellSearchContentId> list
return CELL_SEARCH_ERROR_PARAM;
}
const auto search = g_fxo->get<search_info>();
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;
default:
return CELL_SEARCH_ERROR_PARAM;
}
if (sortOrder != CELL_SEARCH_SORTORDER_ASCENDING && sortOrder != CELL_SEARCH_SORTORDER_DESCENDING)
{
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
*outSearchId = idm::make<search_object_t>();
sysutil_register_cb([=](ppu_thread& ppu) -> s32
s_search_state = search_state::in_progress;
sysutil_register_cb([=, search = g_fxo->get<search_info>()](ppu_thread& ppu) -> s32
{
vm::var<CellSearchResultParam> resultParam;
resultParam->searchId = *outSearchId;
resultParam->resultNum = 0; // TODO
s_search_state = search_state::idle;
search->func(ppu, CELL_SEARCH_EVENT_CONTENTSEARCH_INLIST_RESULT, CELL_OK, vm::cast(resultParam.addr()), search->userData);
return CELL_OK;
});
@ -150,16 +304,178 @@ error_code cellSearchStartContentSearch(CellSearchContentSearchType type, CellSe
return CELL_SEARCH_ERROR_PARAM;
}
const auto search = g_fxo->get<search_info>();
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;
default:
return CELL_SEARCH_ERROR_PARAM;
}
if (sortOrder != CELL_SEARCH_SORTORDER_ASCENDING && sortOrder != CELL_SEARCH_SORTORDER_DESCENDING)
{
return CELL_SEARCH_ERROR_PARAM;
}
const char* media_dir;
switch (type)
{
case CELL_SEARCH_CONTENTSEARCHTYPE_MUSIC_ALL: media_dir = "music"; break;
case CELL_SEARCH_CONTENTSEARCHTYPE_PHOTO_ALL: media_dir = "photo"; break;
case CELL_SEARCH_CONTENTSEARCHTYPE_VIDEO_ALL: media_dir = "video"; break;
default:
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
*outSearchId = idm::make<search_object_t>();
sysutil_register_cb([=](ppu_thread& ppu) -> s32
s_search_state = search_state::in_progress;
sysutil_register_cb([=, content_map = g_fxo->get<ContentIdMap>(), search = g_fxo->get<search_info>()](ppu_thread& ppu) -> s32
{
auto curr_search = idm::get<search_object_t>(*outSearchId);
vm::var<CellSearchResultParam> resultParam;
resultParam->searchId = *outSearchId;
resultParam->resultNum = 0; // TODO
resultParam->resultNum = 0; // Set again later
std::function<void(const std::string&, const std::string&)> searchInFolder = [&, type](const std::string& vpath, const std::string& prev)
{
const std::string relative_vpath = (!prev.empty() ? prev + "/" : "") + vpath;
for (auto&& item : fs::dir(vfs::get(relative_vpath)))
{
item.name = vfs::unescape(item.name);
if (item.name == "." || item.name == "..")
{
continue;
}
if (item.is_directory)
{
searchInFolder(item.name, relative_vpath);
continue;
}
// TODO
// Perform first check that file is of desired type. For example, don't wanna go
// identifying "AlbumArt.jpg" as an MP3. Hrm... Postpone this thought. Do games
// perform their own checks? DIVA ignores anything without the MP3 extension.
// TODO - Identify sorting method and insert the appropriate values where applicable
const std::string item_path(relative_vpath + "/" + item.name);
const u64 hash = XXH64(item_path.c_str(), item_path.length(), 0);
auto found = content_map->find(hash);
if (found == content_map->end()) // content isn't yet being tracked
{
auto ext_offset = item.name.find_last_of("."); // used later if no "Title" found
std::shared_ptr<search_content_t> curr_find = std::make_shared<search_content_t>();
strcpy_trunc(curr_find->infoPath.contentPath, item_path); // TODO: This is the case where linking is required
// TODO - curr_find.infoPath.thumbnailPath
if (type == CELL_SEARCH_CONTENTSEARCHTYPE_MUSIC_ALL)
{
curr_find->type = CELL_SEARCH_CONTENTTYPE_MUSIC;
CellSearchMusicInfo& info = curr_find->data.music;
// TODO - Some kinda file music analysis and assign the values as such
info.duration = 0;
info.size = item.size;
info.importedDate = 0;
info.lastPlayedDate = 0;
info.releasedYear = 0;
info.trackNumber = 0;
info.bitrate = 0;
info.samplingRate = 0;
info.quantizationBitrate = 0;
info.playCount = 0;
info.drmEncrypted = 0;
info.codec = 0; // CellSearchCodec
info.status = 0; // CellSearchContentStatus
strcpy_trunc(info.title, item.name.substr(0, ext_offset)); // it'll do for the moment...
strcpy_trunc(info.albumTitle, "ALBUM TITLE");
strcpy_trunc(info.artistName, "ARTIST NAME");
strcpy_trunc(info.genreName, "GENRE NAME");
}
else if (type == CELL_SEARCH_CONTENTSEARCHTYPE_PHOTO_ALL)
{
curr_find->type = CELL_SEARCH_CONTENTTYPE_PHOTO;
CellSearchPhotoInfo& info = curr_find->data.photo;
// TODO - Some kinda file photo analysis and assign the values as such
info.size = item.size;
info.importedDate = 0;
info.takenDate = 0;
info.width = 0;
info.height = 0;
info.orientation = 0; // CellSearchOrientation
info.codec = 0; // CellSearchCodec
info.status = 0; // CellSearchContentStatus
strcpy_trunc(info.title, item.name.substr(0, ext_offset).c_str());
strcpy_trunc(info.albumTitle, "ALBUM TITLE");
}
else if (type == CELL_SEARCH_CONTENTSEARCHTYPE_VIDEO_ALL)
{
curr_find->type = CELL_SEARCH_CONTENTTYPE_VIDEO;
CellSearchVideoInfo& info = curr_find->data.video;
// TODO - Some kinda file video analysis and assign the values as such
info.duration = 0;
info.size = item.size;
info.importedDate = 0;
info.takenDate = 0;
info.videoBitrate = 0;
info.audioBitrate = 0;
info.playCount = 0;
info.drmEncrypted = 0;
info.videoCodec = 0; // CellSearchCodec
info.audioCodec = 0; // CellSearchCodec
info.status = 0; // CellSearchContentStatus
strcpy_trunc(info.title, item.name.substr(0, ext_offset).c_str()); // it'll do for the moment...
strcpy_trunc(info.albumTitle, "ALBUM TITLE");
}
content_map->emplace(hash, curr_find);
curr_search->content_ids.emplace_back(hash, curr_find); // place this file's "ID" into the list of found types
cellSearch.notice("cellSearchStartContentSearch(): Content ID: %08X Path: \"%s\"", hash, item_path);
}
else // file is already stored and tracked
{ // TODO
// Perform checks to see if the identified file has been modified since last checked
// In which case, update the stored content's properties
// auto content_found = &content_map->at(content_id);
curr_search->content_ids.emplace_back(found->first, found->second);
}
}
};
searchInFolder(fmt::format("/dev_hdd0/%s", media_dir), "");
resultParam->resultNum = ::narrow<s32>(curr_search->content_ids.size());
s_search_state = search_state::idle;
search->func(ppu, CELL_SEARCH_EVENT_CONTENTSEARCH_RESULT, CELL_OK, vm::cast(resultParam.addr()), search->userData);
return CELL_OK;
});
@ -176,16 +492,50 @@ error_code cellSearchStartSceneSearchInVideo(vm::cptr<CellSearchContentId> video
return CELL_SEARCH_ERROR_PARAM;
}
const auto search = g_fxo->get<search_info>();
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;
default:
return CELL_SEARCH_ERROR_PARAM;
}
if (sortOrder != CELL_SEARCH_SORTORDER_ASCENDING && sortOrder != CELL_SEARCH_SORTORDER_DESCENDING)
{
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
*outSearchId = idm::make<search_object_t>();
sysutil_register_cb([=](ppu_thread& ppu) -> s32
s_search_state = search_state::in_progress;
sysutil_register_cb([=, search = g_fxo->get<search_info>()](ppu_thread& ppu) -> s32
{
vm::var<CellSearchResultParam> resultParam;
resultParam->searchId = *outSearchId;
resultParam->resultNum = 0; // TODO
s_search_state = search_state::idle;
search->func(ppu, CELL_SEARCH_EVENT_SCENESEARCH_INVIDEO_RESULT, CELL_OK, vm::cast(resultParam.addr()), search->userData);
return CELL_OK;
});
@ -202,16 +552,45 @@ error_code cellSearchStartSceneSearch(CellSearchSceneSearchType searchType, vm::
return CELL_SEARCH_ERROR_PARAM;
}
const auto search = g_fxo->get<search_info>();
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;
default:
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
*outSearchId = idm::make<search_object_t>();
sysutil_register_cb([=](ppu_thread& ppu) -> s32
s_search_state = search_state::in_progress;
sysutil_register_cb([=, search = g_fxo->get<search_info>()](ppu_thread& ppu) -> s32
{
vm::var<CellSearchResultParam> resultParam;
resultParam->searchId = *outSearchId;
resultParam->resultNum = 0; // TODO
s_search_state = search_state::idle;
search->func(ppu, CELL_SEARCH_EVENT_SCENESEARCH_RESULT, CELL_OK, vm::cast(resultParam.addr()), search->userData);
return CELL_OK;
});
@ -221,7 +600,7 @@ error_code cellSearchStartSceneSearch(CellSearchSceneSearchType searchType, vm::
error_code cellSearchGetContentInfoByOffset(CellSearchId searchId, s32 offset, vm::ptr<void> infoBuffer, vm::ptr<CellSearchContentType> outContentType, vm::ptr<CellSearchContentId> outContentId)
{
cellSearch.todo("cellSearchGetContentInfoByOffset(searchId=0x%x, offset=0x%x, infoBuffer=*0x%x, outContentType=*0x%x, outContentId=*0x%x)", searchId, offset, infoBuffer, outContentType, outContentId);
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)
{
@ -235,30 +614,157 @@ error_code cellSearchGetContentInfoByOffset(CellSearchId searchId, s32 offset, v
return CELL_SEARCH_ERROR_INVALID_SEARCHID;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
if (offset >= 0 && offset < searchObject->content_ids.size())
{
const auto& content_id = searchObject->content_ids[offset];
const auto& content_info = content_id.second;
switch (content_info->type)
{
case CELL_SEARCH_CONTENTTYPE_MUSIC:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.music, sizeof(content_info->data.music));
break;
case CELL_SEARCH_CONTENTTYPE_PHOTO:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.photo, sizeof(content_info->data.photo));
break;
case CELL_SEARCH_CONTENTTYPE_VIDEO:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.video, sizeof(content_info->data.photo));
break;
case CELL_SEARCH_CONTENTTYPE_MUSICLIST:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.music_list, sizeof(content_info->data.music_list));
break;
case CELL_SEARCH_CONTENTTYPE_PHOTOLIST:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.photo_list, sizeof(content_info->data.photo_list));
break;
case CELL_SEARCH_CONTENTTYPE_VIDEOLIST:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.video_list, sizeof(content_info->data.video_list));
break;
case CELL_SEARCH_CONTENTTYPE_SCENE:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.scene, sizeof(content_info->data.scene));
break;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
const u128 content_id_128 = content_id.first;
*outContentType = content_info->type;
std::memcpy(outContentId->data, &content_id_128, CELL_SEARCH_CONTENT_ID_SIZE);
}
else // content ID not found, perform a search first
{
return CELL_SEARCH_ERROR_OUT_OF_RANGE;
}
return CELL_OK;
}
error_code cellSearchGetContentInfoByContentId(vm::cptr<CellSearchContentId> contentId, vm::ptr<void> infoBuffer, vm::ptr<CellSearchContentType> outContentType)
{
cellSearch.todo("cellSearchGetContentInfoByContentId(contentId=*0x%x, infoBuffer=*0x%x, outContentType=*0x%x)", contentId, infoBuffer, outContentType);
cellSearch.warning("cellSearchGetContentInfoByContentId(contentId=*0x%x, infoBuffer=*0x%x, outContentType=*0x%x)", contentId, infoBuffer, outContentType);
if (!outContentType)
{
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
const auto content_map = g_fxo->get<ContentIdMap>();
auto found = content_map->find(*reinterpret_cast<const u64*>(contentId->data));
if (found != content_map->end())
{
const auto& content_info = found->second;
switch (content_info->type)
{
case CELL_SEARCH_CONTENTTYPE_MUSIC:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.music, sizeof(content_info->data.music));
break;
case CELL_SEARCH_CONTENTTYPE_PHOTO:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.photo, sizeof(content_info->data.photo));
break;
case CELL_SEARCH_CONTENTTYPE_VIDEO:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.video, sizeof(content_info->data.photo));
break;
case CELL_SEARCH_CONTENTTYPE_MUSICLIST:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.music_list, sizeof(content_info->data.music_list));
break;
case CELL_SEARCH_CONTENTTYPE_PHOTOLIST:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.photo_list, sizeof(content_info->data.photo_list));
break;
case CELL_SEARCH_CONTENTTYPE_VIDEOLIST:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.video_list, sizeof(content_info->data.video_list));
break;
case CELL_SEARCH_CONTENTTYPE_SCENE:
std::memcpy(infoBuffer.get_ptr(), &content_info->data.scene, sizeof(content_info->data.scene));
break;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
*outContentType = content_info->type;
}
else // content ID not found, perform a search first
{
return CELL_SEARCH_ERROR_CONTENT_NOT_FOUND;
}
return CELL_OK;
}
error_code cellSearchGetOffsetByContentId(CellSearchId searchId, vm::cptr<CellSearchContentId> contentId, vm::ptr<s32> outOffset)
{
cellSearch.todo("cellSearchGetOffsetByContentId(searchId=0x%x, contentId=*0x%x, outOffset=*0x%x)", searchId, contentId, outOffset);
cellSearch.warning("cellSearchGetOffsetByContentId(searchId=0x%x, contentId=*0x%x, outOffset=*0x%x)", searchId, contentId, outOffset);
if (!outOffset)
{
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
const auto searchObject = idm::get<search_object_t>(searchId);
if (!searchObject)
@ -266,7 +772,19 @@ error_code cellSearchGetOffsetByContentId(CellSearchId searchId, vm::cptr<CellSe
return CELL_SEARCH_ERROR_INVALID_SEARCHID;
}
return CELL_OK;
s32 i = 0;
const u64 content_hash = *reinterpret_cast<const u64*>(contentId->data);
for (auto& content_id : searchObject->content_ids)
{
if (content_id.first == content_hash)
{
*outOffset = i;
return CELL_OK;
}
++i;
}
return CELL_SEARCH_ERROR_CONTENT_NOT_FOUND;
}
error_code cellSearchGetContentIdByOffset(CellSearchId searchId, s32 offset, vm::ptr<CellSearchContentType> outContentType, vm::ptr<CellSearchContentId> outContentId, vm::ptr<CellSearchTimeInfo> outTimeInfo)
@ -285,6 +803,40 @@ error_code cellSearchGetContentIdByOffset(CellSearchId searchId, s32 offset, vm:
return CELL_SEARCH_ERROR_INVALID_SEARCHID;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
if (offset > -1 && offset < searchObject->content_ids.size())
{
auto& content_id = searchObject->content_ids.at(offset);
const u128 content_id_128 = content_id.first;
*outContentType = content_id.second->type;
std::memcpy(outContentId->data, &content_id_128, CELL_SEARCH_CONTENT_ID_SIZE);
if (outTimeInfo)
{
std::memcpy(outTimeInfo.get_ptr(), &content_id.second->timeInfo, sizeof(content_id.second->timeInfo));
}
}
else // content ID not found, perform a search first
{
return CELL_SEARCH_ERROR_OUT_OF_RANGE;
}
return CELL_OK;
}
@ -340,6 +892,37 @@ error_code cellSearchGetContentInfoPath(vm::cptr<CellSearchContentId> contentId,
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
const u64 id = *reinterpret_cast<const u64*>(contentId->data);
const auto content_map = g_fxo->get<ContentIdMap>();
auto found = content_map->find(id);
if(found != content_map->end())
{
std::memcpy(infoPath.get_ptr(), &found->second->infoPath, sizeof(found->second->infoPath));
}
else
{
cellSearch.error("cellSearchGetContentInfoPath(): ID not found : 0x%08X", id);
return CELL_SEARCH_ERROR_CONTENT_NOT_FOUND;
}
cellSearch.success("contentId = %08X contentPath = \"%s\"", id, infoPath->contentPath);
return CELL_OK;
}
@ -364,6 +947,25 @@ error_code cellSearchPrepareFile(vm::cptr<char> path)
return CELL_SEARCH_ERROR_PARAM;
}
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
// TODO: Create a hard link if file path is too long
// Store mappings in cellSearch internally and resolve them here if needed
return CELL_OK;
}
@ -402,12 +1004,47 @@ error_code cellSearchCancel(CellSearchId searchId)
return CELL_SEARCH_ERROR_INVALID_SEARCHID;
}
switch (s_search_state)
{
case search_state::in_progress:
break;
case search_state::not_initialized:
case search_state::initializing:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
case search_state::idle:
return CELL_SEARCH_ERROR_ALREADY_GOT_RESULT;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
// TODO
return CELL_OK;
}
error_code cellSearchEnd(CellSearchId searchId)
{
cellSearch.warning("cellSearchEnd(searchId=0x%x)", searchId);
cellSearch.todo("cellSearchEnd(searchId=0x%x)", searchId);
switch (s_search_state)
{
case search_state::idle:
break;
case search_state::not_initialized:
return CELL_SEARCH_ERROR_NOT_INITIALIZED;
case search_state::finalizing:
return CELL_SEARCH_ERROR_FINALIZING;
case search_state::in_progress:
case search_state::initializing:
case search_state::canceling:
return CELL_SEARCH_ERROR_BUSY;
default:
return CELL_SEARCH_ERROR_GENERIC;
}
const auto searchObject = idm::get<search_object_t>(searchId);