#include "prx/libSceCesCs/include/Api.hpp" #include "prx/libc/include/general/VabiMacros.hpp" #include #include #include #include #include namespace { constexpr int invalidParameter = static_cast(0x805C0001); constexpr int invalidProfile = static_cast(0x805C0004); constexpr int outOfCodeSpace = static_cast(0x805C0015); constexpr int invalidEncode = static_cast(0x805C0014); constexpr int unassignedCode = static_cast(0x805C0020); void Require(bool value) { if (!value) std::abort(); } struct Sheet { alignas(8) std::uint8_t bytes[64]; }; int Convert(void* context, const char* mbcs, std::uint8_t* utf8, std::uint32_t utf8Max, std::uint32_t& produced) { std::uint32_t used = 0; return sceCesMbcsStrToUtf8Str(context, reinterpret_cast(mbcs), static_cast(std::strlen(mbcs)), &used, utf8, utf8Max, &produced); } int Encode(void* context, const char* utf8, std::uint8_t* mbcs, std::uint32_t mbcsMax, std::uint32_t& produced) { std::uint32_t used = 0; return sceCesUtf8StrToMbcsStr(context, reinterpret_cast(utf8), static_cast(std::strlen(utf8)), &used, mbcs, mbcsMax, &produced); } void RequireConverts(void* context, const char* mbcs, const char* utf8) { std::uint8_t out[32] = {}; std::uint32_t produced = 0; Require(Convert(context, mbcs, out, sizeof(out), produced) == 0); Require(produced == std::strlen(utf8) && std::memcmp(out, utf8, produced) == 0); std::uint8_t back[32] = {}; Require(Encode(context, utf8, back, sizeof(back), produced) == 0); Require(produced == std::strlen(mbcs) && std::memcmp(back, mbcs, produced) == 0); } void CheckShiftJis() { Sheet sheet{}; std::memset(sheet.bytes, 0xA5, sizeof(sheet.bytes)); Require(sceCesUcsProfileInitSJis1997Cp932(sheet.bytes) == sheet.bytes); alignas(8) std::uint8_t context[64] = {}; Require(sceCesMbcsUcsContextInit(context, sheet.bytes) == 0); RequireConverts(context, "\x5C\xB6\x41", "\x5C\xEF\xBD\xB6\x41"); Require(sceCesSJisUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileJisX0201()) == 0); RequireConverts(context, "\x5C\xB6\x41\x7E\x82\xA0", "\xC2\xA5\xEF\xBD\xB6\x41\xE2\x80\xBE\xE3\x81\x82"); std::uint8_t out[8] = {}; std::uint32_t produced = 0; Require(Encode(context, "\x5C", out, sizeof(out), produced) == 0 && produced == 2 && std::memcmp(out, "\x81\x5F", 2) == 0); Require(Encode(context, "~", out, sizeof(out), produced) == unassignedCode); Require(sceCesSJisUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileAscii()) == 0); RequireConverts(context, "\x5C\x41\x82\xA0", "\x5C\x41\xE3\x81\x82"); Require(Convert(context, "\xB6", out, sizeof(out), produced) == unassignedCode); Require(Encode(context, "\xEF\xBD\xB6", out, sizeof(out), produced) == unassignedCode); for (const std::uint8_t* other : {sceCesRefersUcsProfileIso8859_1(), sceCesRefersUcsProfileKsX1003(), sceCesRefersUcsProfileGbT1988(), sceCesRefersUcsProfileJisX0201Katakana(), sceCesRefersUcsProfileCp1252()}) { Require(sceCesSJisUcsProfileSetSbcs(sheet.bytes, other) == invalidProfile); } Require(sceCesSJisUcsProfileSetSbcs(sheet.bytes, nullptr) == invalidProfile); Require(sceCesSJisUcsProfileSetSbcs(nullptr, sceCesRefersUcsProfileAscii()) == invalidProfile); Require(sceCesSJisUcsProfileSetSbcs(sheet.bytes, sheet.bytes) == invalidProfile); Require(sceCesEucJpUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileAscii()) == invalidProfile); RequireConverts(context, "\x5C\x41", "\x5C\x41"); Require(Convert(context, "\xB6", out, sizeof(out), produced) == unassignedCode); Require(sceCesUcsProfileInitSJis1997Cp932(sheet.bytes) == sheet.bytes); RequireConverts(context, "\x5C\xB6", "\x5C\xEF\xBD\xB6"); Require(sceCesSJisUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileJisX0201()) == 0); Sheet copy{}; std::memcpy(copy.bytes, sheet.bytes, 8); alignas(8) std::uint8_t copied[64] = {}; Require(sceCesMbcsUcsContextInit(copied, copy.bytes) == 0); RequireConverts(copied, "\x5C\xB6", "\xC2\xA5\xEF\xBD\xB6"); RequireConverts(context, "\x5C\xB6", "\xC2\xA5\xEF\xBD\xB6"); Require(sceCesUcsProfileInitSJis1997Cp932(copy.bytes) == copy.bytes); RequireConverts(copied, "\x5C\xB6", "\x5C\xEF\xBD\xB6"); RequireConverts(context, "\x5C\xB6", "\xC2\xA5\xEF\xBD\xB6"); } void CheckEucFamilies() { Sheet sheet{}; alignas(8) std::uint8_t context[64] = {}; Require(sceCesUcsProfileInitEucJpCp51932(sheet.bytes) == sheet.bytes); Require(sceCesMbcsUcsContextInit(context, sheet.bytes) == 0); RequireConverts(context, "\x5C\x8E\xB6", "\x5C\xEF\xBD\xB6"); Require(sceCesEucJpUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileJisX0201Roman()) == 0); RequireConverts(context, "\x5C\x8E\xB6\xA4\xA2", "\xC2\xA5\xEF\xBD\xB6\xE3\x81\x82"); std::uint8_t out[8] = {}; std::uint32_t produced = 0; Require(Encode(context, "\x5C", out, sizeof(out), produced) == 0 && produced == 2 && std::memcmp(out, "\xA1\xC0", 2) == 0); Require(sceCesEucJpUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileJisX0201()) == invalidProfile); Require(sceCesSJisUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileAscii()) == invalidProfile); Require(sceCesUcsProfileInitEucKr(sheet.bytes) == sheet.bytes); Require(sceCesEucKrUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileKsX1003()) == 0); RequireConverts(context, "\x5C\xB0\xA1", "\xE2\x82\xA9\xEA\xB0\x80"); Require(sceCesUcsProfileInitUhc(sheet.bytes) == sheet.bytes); Require(sceCesUhcUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileKsX1003()) == 0); RequireConverts(context, "\x5C\xB0\xA1", "\xE2\x82\xA9\xEA\xB0\x80"); Require(sceCesEucKrUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileKsX1003()) == invalidProfile); Require(sceCesUhcUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileJisX0201Roman()) == invalidProfile); Require(sceCesUcsProfileInitEucCnGb2312(sheet.bytes) == sheet.bytes); Require(sceCesEucCnUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileGbT1988()) == 0); RequireConverts(context, "\x24\xB0\xA1", "\xC2\xA5\xE5\x95\x8A"); Require(sceCesGbUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileGbT1988()) == invalidProfile); Require(sceCesUcsProfileInitGbkCp936(sheet.bytes) == sheet.bytes); Require(sceCesGbUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileGbT1988()) == 0); RequireConverts(context, "\x24\xB0\xA1", "\xC2\xA5\xE5\x95\x8A"); Require(sceCesUcsProfileInitGb18030_2000(sheet.bytes) == sheet.bytes); Require(sceCesGbUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileGbT1988()) == 0); RequireConverts(context, "\x24\xB0\xA1\x81\x30\x81\x30", "\xC2\xA5\xE5\x95\x8A\xC2\x80"); Require(sceCesUcsProfileInitGb18030_2005(sheet.bytes) == sheet.bytes); Require(sceCesGbUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileGbT1988()) == 0); RequireConverts(context, "\x24\xB0\xA1", "\xC2\xA5\xE5\x95\x8A"); Require(sceCesEucCnUcsProfileSetSbcs(sheet.bytes, sceCesRefersUcsProfileGbT1988()) == invalidProfile); } void CheckReplacement() { Sheet sheet{}; alignas(8) std::uint8_t context[64] = {}; Require(sceCesUcsProfileInitSJis1997Cp932(sheet.bytes) == sheet.bytes); Require(sceCesMbcsUcsContextInit(context, sheet.bytes) == 0); std::uint8_t out[16] = {}; std::uint32_t produced = 0; for (const std::uint32_t code : {0x3Fu, 0x8148u, 0x81A6u, 0xFFu, 0u}) { Require(sceCesMbcsUcsSetMbcsReplacementCharCode(context, code) == 0); Require(Encode(context, "A\xE0\xB8\x81" "B", out, sizeof(out), produced) == unassignedCode); } for (const std::uint32_t code : {0x100u, 0x10000u}) Require(sceCesMbcsUcsSetMbcsReplacementCharCode(context, code) == outOfCodeSpace); for (const std::uint32_t code : {0x3Fu, 0x3013u, 0u}) { Require(sceCesMbcsUcsSetMbcsReplacementCharUCode(context, code) == 0); Require(Convert(context, "A\xFF" "B", out, sizeof(out), produced) == invalidEncode); } Require(sceCesMbcsUcsSetMbcsReplacementCharUCode(context, 0xFFFD) == unassignedCode); Require(sceCesMbcsUcsSetMbcsReplacementCharUCode(context, 0x110000) == invalidEncode); Require(sceCesMbcsUcsSetMbcsReplacementCharUCode(context, 0xD800) == outOfCodeSpace); alignas(8) std::uint8_t copy[64] = {}; Require(sceCesMbcsUcsContextInitCopy(copy, context) == 0); Require(Encode(copy, "\xE0\xB8\x81", out, sizeof(out), produced) == unassignedCode); Require(sceCesMbcsUcsSetMbcsReplacementCharUCode(nullptr, 0x3F) == invalidParameter); Require(sceCesMbcsUcsSetMbcsReplacementCharCode(nullptr, 0x3F) == invalidParameter); const void* bad = nullptr; alignas(8) std::uint8_t broken[64] = {}; std::memcpy(broken, &bad, sizeof(bad)); Require(sceCesMbcsUcsSetMbcsReplacementCharCode(broken, 0x3F) == invalidParameter); Require(Convert(context, "\x82\xA0", out, sizeof(out), produced) == 0 && produced == 3); } } int main() { CheckShiftJis(); CheckEucFamilies(); CheckReplacement(); return 0; }