AnyPS5/core/libs/prx/libSceContentSearch/Export.cpp

145 lines
7.4 KiB
C++

#include <cstdint>
#include <cstddef>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include <atomic>
#include <stdexcept>
#include <string>
namespace {
std::atomic<bool> g_initialized{false};
constexpr int ErrorNotInitialized = static_cast<int>(0x809D1001u);
constexpr int ErrorLimitTooBig = static_cast<int>(0x809D100Au);
constexpr std::uint32_t MaxSearchLimit = 92;
constexpr std::int64_t LibraryUpdateId = 0;
bool IsContentColumn(std::int32_t column) {
switch (column) {
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 9: case 10: case 11: case 12: case 14: return true;
default: return false;
}
}
bool IsSortColumn(std::int32_t column) {
switch (column) {
case 1: case 4: case 5: case 6: case 9: case 10: return true;
default: return false;
}
}
bool IsConnector(std::int32_t connector) { return connector >= 0 && connector <= 2; }
void ValidateColumnSets(const char* funcName, const ContentSearchContentColumnSet* columnSet, std::uint32_t columnSetLength) {
if (columnSet == nullptr && columnSetLength != 0) throw std::invalid_argument(std::string(funcName) + ": null column set");
for (std::uint32_t i = 0; i < columnSetLength; ++i) {
const auto& set = columnSet[i];
if (set.columns == nullptr || set.columns_length <= 0) throw std::invalid_argument(std::string(funcName) + ": empty column set");
if (!IsConnector(set.logical_connector)) throw std::invalid_argument(std::string(funcName) + ": unknown logical connector " + std::to_string(set.logical_connector));
for (std::int32_t j = 0; j < set.columns_length; ++j) {
const auto& column = set.columns[j];
if (!IsContentColumn(column.column_type)) throw std::invalid_argument(std::string(funcName) + ": unknown column " + std::to_string(column.column_type));
if (column.column_operator < 0 || column.column_operator > 5) throw std::invalid_argument(std::string(funcName) + ": unknown column operator " + std::to_string(column.column_operator));
if (column.value == nullptr) throw std::invalid_argument(std::string(funcName) + ": null column value");
if (!IsConnector(column.logical_connector)) throw std::invalid_argument(std::string(funcName) + ": unknown logical connector " + std::to_string(column.logical_connector));
}
}
}
void ValidateOrderBy(const char* funcName, const ContentSearchContentOrderByCondition* orderByConditions, std::uint32_t orderByConditionsLength) {
if (orderByConditions == nullptr && orderByConditionsLength != 0) throw std::invalid_argument(std::string(funcName) + ": null order-by conditions");
for (std::uint32_t i = 0; i < orderByConditionsLength; ++i) {
const auto& condition = orderByConditions[i];
if (!IsSortColumn(condition.column_type)) throw std::invalid_argument(std::string(funcName) + ": unknown sort column " + std::to_string(condition.column_type));
if (condition.sort_type != 0 && condition.sort_type != 1) throw std::invalid_argument(std::string(funcName) + ": unknown sort type " + std::to_string(condition.sort_type));
}
}
[[noreturn]] void ThrowUnknownMetadataId(const char* funcName, std::int32_t metadataId) {
throw std::logic_error(std::string(funcName) + ": metadata id " + std::to_string(metadataId) + " was never opened, as the host content library is empty, and the console's error for it is unknown");
}
}
extern "C" {
int APS5_VABI sceContentSearchInit(const ContentSearchInitParam* init_param) {
if (init_param == nullptr) APS5_INVALID_ARG_EX;
bool expected = false;
if (!g_initialized.compare_exchange_strong(expected, true)) throw std::logic_error(std::string(__func__) + ": already initialized");
return 0;
}
int APS5_VABI sceContentSearchCloseMetadata(std::int32_t metadataId) {
if (!g_initialized.load()) return ErrorNotInitialized;
ThrowUnknownMetadataId(__func__, metadataId);
}
int APS5_VABI sceContentSearchGetMetadataFieldInfo(std::int32_t metadataId, const char* field, std::int32_t* metadataType, std::int32_t* size) {
if (!g_initialized.load()) return ErrorNotInitialized;
if (field == nullptr || metadataType == nullptr || size == nullptr) APS5_INVALID_ARG_EX;
ThrowUnknownMetadataId(__func__, metadataId);
}
int APS5_VABI sceContentSearchGetMetadataValue(std::int32_t metadataId, const char* field, void* value) {
if (!g_initialized.load()) return ErrorNotInitialized;
if (field == nullptr || value == nullptr) APS5_INVALID_ARG_EX;
ThrowUnknownMetadataId(__func__, metadataId);
}
int APS5_VABI sceContentSearchOpenMetadata(const char* filePath, std::int32_t* metadataId) {
if (!g_initialized.load()) return ErrorNotInitialized;
if (filePath == nullptr || metadataId == nullptr) APS5_INVALID_ARG_EX;
throw std::logic_error(std::string(__func__) + ": " + filePath + " is not in the host content library, which is empty, and the console's error for it is unknown");
}
int APS5_VABI sceContentSearchSearchContent(const ContentSearchContentColumnSet* columnSet, std::uint32_t columnSetLength, const ContentSearchContentOrderByCondition* orderByConditions, std::uint32_t orderByConditionsLength, std::uint32_t offset, std::uint32_t limit, std::int64_t* numOfContent, void* infos, std::int64_t* lastUpdateId) {
(void)offset;
if (!g_initialized.load()) return ErrorNotInitialized;
if (numOfContent == nullptr || lastUpdateId == nullptr || (infos == nullptr && limit != 0)) APS5_INVALID_ARG_EX;
ValidateColumnSets(__func__, columnSet, columnSetLength);
ValidateOrderBy(__func__, orderByConditions, orderByConditionsLength);
if (limit > MaxSearchLimit) return ErrorLimitTooBig;
*numOfContent = 0;
*lastUpdateId = LibraryUpdateId;
return 0;
}
int APS5_VABI sceContentSearchGetContentLastUpdateId(std::int64_t* lastUpdateId) {
if (!g_initialized.load()) return ErrorNotInitialized;
if (lastUpdateId == nullptr) APS5_INVALID_ARG_EX;
*lastUpdateId = LibraryUpdateId;
return 0;
}
int APS5_VABI sceContentSearchOpenMetadataByContentId(std::int64_t contentId, std::int32_t* metadataId) {
if (!g_initialized.load()) return ErrorNotInitialized;
if (metadataId == nullptr) APS5_INVALID_ARG_EX;
throw std::logic_error(std::string(__func__) + ": content id " + std::to_string(contentId) + " is not in the host content library, which is empty, and the console's error for it is unknown");
}
int APS5_VABI sceContentSearchGetTotalContentSize(const ContentSearchContentColumnSet* columnSet, std::uint32_t columnSetLength, std::int64_t* size, std::int64_t* lastUpdateId) {
if (!g_initialized.load()) return ErrorNotInitialized;
if (size == nullptr || lastUpdateId == nullptr) APS5_INVALID_ARG_EX;
ValidateColumnSets(__func__, columnSet, columnSetLength);
*size = 0;
*lastUpdateId = LibraryUpdateId;
return 0;
}
int APS5_VABI sceContentSearchGetNumOfContent(const ContentSearchContentColumnSet* columnSet, std::uint32_t columnSetLength, std::int64_t* numOfContent, std::int64_t* lastUpdateId) {
if (!g_initialized.load()) return ErrorNotInitialized;
if (numOfContent == nullptr || lastUpdateId == nullptr) APS5_INVALID_ARG_EX;
ValidateColumnSets(__func__, columnSet, columnSetLength);
*numOfContent = 0;
*lastUpdateId = LibraryUpdateId;
return 0;
}
int APS5_VABI sceContentSearchTerm(void) {
bool expected = true;
if (!g_initialized.compare_exchange_strong(expected, false)) throw std::logic_error(std::string(__func__) + ": not initialized");
return 0;
}
}