145 lines
7.4 KiB
C++
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;
|
|
}
|
|
|
|
}
|