Files
AnyPS5/core/libs/tests/GuestCesChinese.cpp
T

351 lines
22 KiB
C++

#include "prx/libSceCesCs/include/Api.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
#include <cstring>
static void Require(bool value) { if (!value) std::abort(); }
static const std::uint8_t* Bytes(const char* text) { return reinterpret_cast<const std::uint8_t*>(text); }
static constexpr int invalidParameter = static_cast<int>(0x805C0001);
static constexpr int invalidSrcBuffer = static_cast<int>(0x805C0010);
static constexpr int srcBufferEnd = static_cast<int>(0x805C0011);
static constexpr int invalidEncode = static_cast<int>(0x805C0014);
constexpr int outOfCodeSpace = static_cast<int>(0x805C0015);
static constexpr int unassignedCode = static_cast<int>(0x805C0020);
static constexpr int invalidDstBuffer = static_cast<int>(0x805C0030);
static constexpr int dstBufferEnd = static_cast<int>(0x805C0031);
struct Gb18030Sequence {
std::uint32_t bytes;
std::uint32_t code2000;
std::uint32_t code2005;
};
struct Gb18030Difference {
std::uint32_t bytes;
std::uint32_t code2000;
std::uint32_t code2005;
bool fallback;
};
static constexpr Gb18030Sequence GB18030_BOUNDARIES[88] = {
{0x81308130, 0x80, 0x80}, {0x8130D239, 0x450, 0x450}, {0x8130D330, 0x452, 0x452}, {0x8135F436, 0x1E3E, 0x1E3E},
{0x8135F437, 0x1E3F, 0xE7C7}, {0x8135F438, 0x1E40, 0x1E40}, {0x8136A531, 0x200F, 0x200F}, {0x8136A532, 0x2011, 0x2011},
{0x8137A838, 0x2641, 0x2641}, {0x8137A839, 0x2643, 0x2643}, {0x8138FD38, 0x2E80, 0x2E80}, {0x8138FD39, 0x2E82, 0x2E82},
{0x8230A632, 0x3619, 0x3619}, {0x8230A633, 0x361B, 0x361B}, {0x8230F237, 0x3917, 0x3917}, {0x8230F238, 0x3919, 0x3919},
{0x8231D437, 0x3CDF, 0x3CDF}, {0x8231D438, 0x3CE1, 0x3CE1}, {0x8232AF32, 0x4055, 0x4055}, {0x8232AF33, 0x4057, 0x4057},
{0x8232C936, 0x415E, 0x415E}, {0x8232C937, 0x4160, 0x4160}, {0x8232F837, 0x4336, 0x4336}, {0x8232F838, 0x4338, 0x4338},
{0x8233A338, 0x44D5, 0x44D5}, {0x8233A339, 0x44D7, 0x44D7}, {0x8233C931, 0x464B, 0x464B}, {0x8233C932, 0x464D, 0x464D},
{0x8233E837, 0x478C, 0x478C}, {0x8233E838, 0x478E, 0x478E}, {0x82349638, 0x4946, 0x4946}, {0x82349639, 0x4948, 0x4948},
{0x8234A130, 0x49B5, 0x49B5}, {0x8234A131, 0x49B8, 0x49B8}, {0x8234E733, 0x4C76, 0x4C76}, {0x8234E734, 0x4C78, 0x4C78},
{0x82358F32, 0x4DFF, 0x4DFF}, {0x82358F33, 0x9FA6, 0x9FA6}, {0x8336C738, 0xD7FF, 0xD7FF}, {0x8336C739, 0xE76C, 0xE76C},
{0x8336CF39, 0xE863, 0xE863}, {0x8336D030, 0xE865, 0xE865}, {0x84308534, 0xF92B, 0xF92B}, {0x84308535, 0xF92D, 0xF92D},
{0x84309C37, 0xFA26, 0xFA26}, {0x84309C38, 0xFA2A, 0xFA2A}, {0x84318537, 0xFE2F, 0xFE2F}, {0x84318538, 0xFE32, 0xFE32},
{0x8431A233, 0xFFDF, 0xFFDF}, {0x8431A234, 0xFFE6, 0xFFE6}, {0x8431A439, 0xFFFF, 0xFFFF}, {0x8431A530, 0x0, 0x0},
{0x8F39FE39, 0x0, 0x0}, {0x90308130, 0x10000, 0x10000}, {0x95328235, 0x1FFFF, 0x1FFFF}, {0x95328236, 0x20000, 0x20000},
{0x9A348431, 0x2FFFF, 0x2FFFF}, {0x9A348432, 0x30000, 0x30000}, {0x9F368537, 0x3FFFF, 0x3FFFF}, {0x9F368538, 0x40000, 0x40000},
{0xA4388733, 0x4FFFF, 0x4FFFF}, {0xA4388734, 0x50000, 0x50000}, {0xAA308839, 0x5FFFF, 0x5FFFF}, {0xAA308930, 0x60000, 0x60000},
{0xAF328A35, 0x6FFFF, 0x6FFFF}, {0xAF328A36, 0x70000, 0x70000}, {0xB4348C31, 0x7FFFF, 0x7FFFF}, {0xB4348C32, 0x80000, 0x80000},
{0xB9368D37, 0x8FFFF, 0x8FFFF}, {0xB9368D38, 0x90000, 0x90000}, {0xBE388F33, 0x9FFFF, 0x9FFFF}, {0xBE388F34, 0xA0000, 0xA0000},
{0xC4309039, 0xAFFFF, 0xAFFFF}, {0xC4309130, 0xB0000, 0xB0000}, {0xC9329235, 0xBFFFF, 0xBFFFF}, {0xC9329236, 0xC0000, 0xC0000},
{0xCE349431, 0xCFFFF, 0xCFFFF}, {0xCE349432, 0xD0000, 0xD0000}, {0xD3369537, 0xDFFFF, 0xDFFFF}, {0xD3369538, 0xE0000, 0xE0000},
{0xD8389733, 0xEFFFF, 0xEFFFF}, {0xD8389734, 0xF0000, 0xF0000}, {0xDE309839, 0xFFFFF, 0xFFFFF}, {0xDE309930, 0x100000, 0x100000},
{0xE3329A35, 0x10FFFF, 0x10FFFF}, {0xE3329A36, 0x0, 0x0}, {0xFD308130, 0x0, 0x0}, {0xFE39FE39, 0x0, 0x0},
};
static constexpr Gb18030Difference GB18030_DIFFERENCES[26] = {
{0xA6D9, 0xE78D, 0xFE10, true}, {0xA6DA, 0xE78E, 0xFE12, true}, {0xA6DB, 0xE78F, 0xFE11, true}, {0xA6DC, 0xE790, 0xFE13, true},
{0xA6DD, 0xE791, 0xFE14, true}, {0xA6DE, 0xE792, 0xFE15, true}, {0xA6DF, 0xE793, 0xFE16, true}, {0xA6EC, 0xE794, 0xFE17, true},
{0xA6ED, 0xE795, 0xFE18, true}, {0xA6F3, 0xE796, 0xFE19, true}, {0xA8BC, 0xE7C7, 0x1E3F, false}, {0xFE51, 0xE816, 0x20087, true},
{0xFE52, 0xE817, 0x20089, true}, {0xFE53, 0xE818, 0x200CC, true}, {0xFE59, 0xE81E, 0x9FB4, true}, {0xFE61, 0xE826, 0x9FB5, true},
{0xFE66, 0xE82B, 0x9FB6, true}, {0xFE67, 0xE82C, 0x9FB7, true}, {0xFE6C, 0xE831, 0x215D7, true}, {0xFE6D, 0xE832, 0x9FB8, true},
{0xFE76, 0xE83B, 0x2298F, true}, {0xFE7E, 0xE843, 0x9FB9, true}, {0xFE90, 0xE854, 0x9FBA, true}, {0xFE91, 0xE855, 0x241FE, true},
{0xFEA0, 0xE864, 0x9FBB, true}, {0x8135F437, 0x1E3F, 0xE7C7, false},
};
static std::uint32_t Gb18030Bytes(std::uint32_t linear) {
return (0x81 + linear / 12600) << 24 | (0x30 + linear / 1260 % 10) << 16 | (0x81 + linear / 10 % 126) << 8 | (0x30 + linear % 10);
}
static void Fnv(std::uint32_t& hash, std::uint32_t value) {
for (int i = 0; i < 4; ++i) {
hash ^= (value >> (8 * i)) & 0xFF;
hash *= 0x01000193;
}
}
static std::uint32_t Gb18030Decode(const void* gb, std::uint32_t packed) {
std::uint8_t bytes[4] = {};
const std::uint32_t size = packed > 0xFFFF ? 4 : 2;
for (std::uint32_t i = 0; i < size; ++i) bytes[i] = static_cast<std::uint8_t>(packed >> (8 * (size - 1 - i)));
std::uint32_t consumed = 0x55;
std::uint32_t code = 0xDEADBEEF;
const int result = sceCesGbToUtf32(gb, bytes, size, &consumed, &code);
if (result != 0) {
Require(result == unassignedCode && consumed == size && code == 0);
return 0;
}
Require(consumed == size);
return code;
}
static std::uint32_t Gb18030Encode(const void* gb, std::uint32_t code) {
std::uint8_t bytes[4] = {};
std::uint32_t size = 0;
Require(sceCesUtf32ToGb(code, gb, bytes, sizeof(bytes), &size) == 0 && (size == 2 || size == 4));
std::uint32_t packed = 0;
for (std::uint32_t i = 0; i < size; ++i) packed = packed << 8 | bytes[i];
return packed;
}
static void RequireGb18030Error(const void* gb, const char* bytes, std::uint32_t size, int error, std::uint32_t length) {
std::uint32_t consumed = 0x55;
std::uint32_t utf32 = 0xDEADBEEF;
Require(sceCesGbToUtf32(gb, Bytes(bytes), size, &consumed, &utf32) == error && consumed == length && utf32 == 0);
std::uint16_t ucs2 = 0xBEEF;
consumed = 0x55;
Require(sceCesMbcToUcs2(gb, Bytes(bytes), size, &consumed, &ucs2) == error && consumed == length && ucs2 == 0);
}
static void CheckGb18030(const void* gb, bool revision2005, std::uint32_t twoByteHash, std::uint32_t fourByteHash, std::uint32_t encodeHash, int fourByteOneWay, int codeOneWay) {
std::uint32_t hash = 0x811C9DC5;
for (std::uint32_t cell = 0; cell < 126 * 190; ++cell) {
const std::uint32_t column = cell % 190;
const std::uint32_t bytes = (0x81 + cell / 190) << 8 | (column < 0x3F ? 0x40 + column : 0x41 + column);
const std::uint32_t code = Gb18030Decode(gb, bytes);
Require(code != 0 && Gb18030Encode(gb, code) == bytes);
Fnv(hash, code);
}
Require(hash == twoByteHash);
hash = 0x811C9DC5;
int oneWay = 0;
for (std::uint32_t linear = 0; linear < 39420; ++linear) {
const std::uint32_t bytes = Gb18030Bytes(linear);
const std::uint32_t code = Gb18030Decode(gb, bytes);
Require(code >= 0x80 && code <= 0xFFFF);
const std::uint32_t back = Gb18030Encode(gb, code);
if (back != bytes) {
Require(back <= 0xFFFF && Gb18030Decode(gb, back) == code);
++oneWay;
}
Fnv(hash, code);
}
Require(hash == fourByteHash && oneWay == fourByteOneWay);
hash = 0x811C9DC5;
oneWay = 0;
for (std::uint32_t code = 0x80; code < 0x10000; ++code) {
if (code >= 0xD800 && code <= 0xDFFF) continue;
const std::uint32_t bytes = Gb18030Encode(gb, code);
if (Gb18030Decode(gb, bytes) != code) ++oneWay;
Fnv(hash, bytes);
}
Require(hash == encodeHash && oneWay == codeOneWay);
hash = 0x811C9DC5;
int samples = 0;
for (std::uint32_t linear = 189000; linear <= 189000 + 0xFFFFF; linear += 997) {
Fnv(hash, Gb18030Decode(gb, Gb18030Bytes(linear)));
++samples;
}
Require(hash == 0x9E77B552 && samples == 1052);
hash = 0x811C9DC5;
for (std::uint32_t code = 0x10000; code < 0x110000; code += 997) Fnv(hash, Gb18030Encode(gb, code));
Require(hash == 0x3D088D7E);
for (const Gb18030Sequence& entry : GB18030_BOUNDARIES) {
const std::uint32_t code = revision2005 ? entry.code2005 : entry.code2000;
Require(Gb18030Decode(gb, entry.bytes) == code);
if (code != 0) Require(Gb18030Encode(gb, code) == entry.bytes);
}
for (const Gb18030Difference& entry : GB18030_DIFFERENCES) {
const std::uint32_t code = revision2005 ? entry.code2005 : entry.code2000;
Require(Gb18030Decode(gb, entry.bytes) == code && Gb18030Encode(gb, code) == entry.bytes);
if (revision2005 && entry.fallback) Require(Gb18030Encode(gb, entry.code2000) == entry.bytes);
}
RequireGb18030Error(gb, "\x80", 1, invalidEncode, 1);
RequireGb18030Error(gb, "\xFF", 1, invalidEncode, 1);
RequireGb18030Error(gb, "\x81", 1, srcBufferEnd, 2);
RequireGb18030Error(gb, "\x81\x30", 2, srcBufferEnd, 4);
RequireGb18030Error(gb, "\x81\x30\x81", 3, srcBufferEnd, 4);
RequireGb18030Error(gb, "\x81\x00", 2, invalidEncode, 1);
RequireGb18030Error(gb, "\x81\x2F", 2, invalidEncode, 2);
RequireGb18030Error(gb, "\x81\x3A", 2, invalidEncode, 2);
RequireGb18030Error(gb, "\x81\x7F", 2, invalidEncode, 2);
RequireGb18030Error(gb, "\x81\xFF", 2, invalidEncode, 2);
RequireGb18030Error(gb, "\x81\x30\x80\x30", 4, invalidEncode, 4);
RequireGb18030Error(gb, "\x81\x30\xFF\x30", 4, invalidEncode, 4);
RequireGb18030Error(gb, "\x81\x30\x30\x30", 4, invalidEncode, 4);
RequireGb18030Error(gb, "\x81\x30\x81\x2F", 4, invalidEncode, 4);
RequireGb18030Error(gb, "\x81\x30\x81\x3A", 4, invalidEncode, 4);
RequireGb18030Error(gb, "\x81\x30\x81\x81", 4, invalidEncode, 4);
RequireGb18030Error(gb, "\x84\x31\xA5\x30", 4, unassignedCode, 4);
RequireGb18030Error(gb, "\xE3\x32\x9A\x36", 4, unassignedCode, 4);
RequireGb18030Error(gb, "\xFE\x39\xFE\x39", 4, unassignedCode, 4);
std::uint32_t consumed = 0x55;
std::uint32_t produced = 0x55;
std::uint16_t ucs2 = 0xBEEF;
Require(sceCesGbToUcs2(gb, Bytes("\x90\x30\x81\x30"), 4, &consumed, &ucs2) == unassignedCode && consumed == 0x55 && ucs2 == 0xBEEF);
std::uint8_t utf8[4] = {1, 2, 3, 4};
Require(sceCesGbToUtf8(gb, Bytes("\x90\x30\x81\x30"), 4, &consumed, utf8, 3, &produced) == dstBufferEnd && consumed == 0x55 && produced == 0x55);
Require(std::memcmp(utf8, "\x01\x02\x03\x04", 4) == 0);
Require(sceCesGbToUtf8(gb, Bytes("\x90\x30\x81\x30"), 4, &consumed, utf8, 4, &produced) == 0 && consumed == 4 && produced == 4);
Require(std::memcmp(utf8, "\xF0\x90\x80\x80", 4) == 0);
std::uint16_t utf16[2] = {0xBEEF, 0xBEEF};
produced = 0x55;
Require(sceCesGbToUtf16(gb, Bytes("\xE3\x32\x9A\x35"), 4, &consumed, utf16, 1, &produced) == dstBufferEnd && produced == 0x55 && utf16[0] == 0xBEEF);
Require(sceCesGbToUtf16(gb, Bytes("\xE3\x32\x9A\x35"), 4, &consumed, utf16, 2, &produced) == 0 && produced == 2 && utf16[0] == 0xDBFF && utf16[1] == 0xDFFF);
Require(sceCesGbToUtf16be(gb, Bytes("\x90\x30\x81\x30"), 4, &consumed, utf16, 2, &produced) == 0 && std::memcmp(utf16, "\xD8\x00\xDC\x00", 4) == 0);
Require(sceCesMbcToUtf16le(gb, Bytes("\x94\x39\xFC\x36"), 4, &consumed, utf16, 2, &produced) == 0 && consumed == 4 && std::memcmp(utf16, "\x3D\xD8\x00\xDE", 4) == 0);
Require(sceCesGbToUcs2(gb, Bytes("\xA2\xE3"), 2, &consumed, &ucs2) == 0 && consumed == 2 && ucs2 == 0x20AC);
std::uint8_t mbcs[4] = {1, 2, 3, 4};
produced = 0x55;
Require(sceCesUtf32ToGb(0x10000, gb, mbcs, 3, &produced) == dstBufferEnd && produced == 4 && std::memcmp(mbcs, "\x01\x02\x03\x04", 4) == 0);
Require(sceCesUtf32ToGb(0xD800, gb, mbcs, sizeof(mbcs), &produced) == outOfCodeSpace);
Require(sceCesUtf32ToGb(0x110000, gb, mbcs, sizeof(mbcs), &produced) == invalidEncode);
Require(sceCesUcs2ToGb(0x80, gb, mbcs, sizeof(mbcs), &produced) == 0 && produced == 4 && std::memcmp(mbcs, "\x81\x30\x81\x30", 4) == 0);
Require(sceCesUcs2ToGb(0x20AC, gb, mbcs, sizeof(mbcs), &produced) == 0 && produced == 2 && std::memcmp(mbcs, "\xA2\xE3", 2) == 0);
Require(sceCesUtf8ToGb(Bytes("\xF0\x9F\x98\x80"), 4, &consumed, gb, mbcs, sizeof(mbcs), &produced) == 0 && consumed == 4 && produced == 4);
Require(std::memcmp(mbcs, "\x94\x39\xFC\x36", 4) == 0);
const std::uint16_t pair[2] = {0xD83D, 0xDE00};
Require(sceCesUtf16ToGb(pair, 2, &consumed, gb, mbcs, sizeof(mbcs), &produced) == 0 && consumed == 2 && produced == 4 && std::memcmp(mbcs, "\x94\x39\xFC\x36", 4) == 0);
Require(sceCesUtf16ToGb(pair, 1, &consumed, gb, mbcs, sizeof(mbcs), &produced) == srcBufferEnd);
alignas(8) std::uint8_t context[64] = {};
Require(sceCesMbcsUcsContextInit(context, gb) == 0);
const char* utf8Text = "A\xE4\xB8\xAD\xC2\x80\xF0\x9F\x98\x80\xEF\xB8\x90";
const char* gbText = revision2005 ? "A\xD6\xD0\x81\x30\x81\x30\x94\x39\xFC\x36\xA6\xD9" : "A\xD6\xD0\x81\x30\x81\x30\x94\x39\xFC\x36\x84\x31\x82\x36";
const std::uint32_t gbSize = revision2005 ? 13 : 15;
std::uint8_t text[16] = {};
Require(sceCesUtf8StrToMbcsStr(context, Bytes(utf8Text), 13, &consumed, text, sizeof(text), &produced) == 0 && consumed == 13 && produced == gbSize);
Require(std::memcmp(text, gbText, gbSize) == 0);
std::uint8_t backUtf8[16] = {};
Require(sceCesMbcsStrToUtf8Str(context, text, gbSize, &consumed, backUtf8, sizeof(backUtf8), &produced) == 0 && consumed == gbSize && produced == 13);
Require(std::memcmp(backUtf8, utf8Text, 13) == 0);
std::uint16_t backUtf16[8] = {};
Require(sceCesMbcsStrToUtf16Str(context, text, gbSize, &consumed, backUtf16, 8, &produced) == 0 && consumed == gbSize && produced == 6);
Require(backUtf16[0] == 'A' && backUtf16[1] == 0x4E2D && backUtf16[2] == 0x80 && backUtf16[3] == 0xD83D && backUtf16[4] == 0xDE00 && backUtf16[5] == 0xFE10);
std::uint16_t shortUtf16[4] = {};
Require(sceCesMbcsStrToUtf16Str(context, text, gbSize, &consumed, shortUtf16, 4, &produced) == dstBufferEnd);
Require(sceCesMbcsStrGetUtf16Len(context, text, gbSize, &consumed, &produced) == 0 && consumed == gbSize && produced == 6);
std::uint8_t again[16] = {};
Require(sceCesUtf16StrToMbcsStr(context, backUtf16, 6, &consumed, again, sizeof(again), &produced) == 0 && consumed == 6 && produced == gbSize);
Require(std::memcmp(again, gbText, gbSize) == 0);
std::uint16_t ucs2Text[8] = {};
Require(sceCesMbcsStrToUcs2Str(context, text, gbSize, &consumed, ucs2Text, 8, &produced) == unassignedCode);
Require(sceCesUtf8StrToMbcsStr(context, Bytes("\xC2\x80"), 2, &consumed, text, 3, &produced) == dstBufferEnd);
}
int main() {
alignas(8) std::uint8_t eucSheet[64] = {};
alignas(8) std::uint8_t gbkSheet[64] = {};
alignas(8) std::uint8_t sjisSheet[64] = {};
const void* euc = sceCesUcsProfileInitEucCnGb2312(eucSheet);
const void* gbk = sceCesUcsProfileInitGbkCp936(gbkSheet);
const void* sjis = sceCesUcsProfileInitSJis1997Cp932(sjisSheet);
Require(euc == eucSheet && gbk == gbkSheet);
Require(sceCesUcsProfileInitEucCnGb2312(nullptr) == nullptr && sceCesUcsProfileInitGbkCp936(nullptr) == nullptr);
std::uint32_t consumed = 0;
std::uint32_t produced = 0;
std::uint16_t ucs2 = 0;
Require(sceCesEucCnToUcs2(euc, Bytes("\xD6\xD0"), 2, &consumed, &ucs2) == 0 && consumed == 2 && ucs2 == 0x4E2D);
Require(sceCesEucCnToUcs2(euc, Bytes("A"), 1, &consumed, &ucs2) == 0 && consumed == 1 && ucs2 == 'A');
Require(sceCesEucCnToUcs2(euc, Bytes("\xA1\xA4"), 2, &consumed, &ucs2) == 0 && ucs2 == 0x00B7);
Require(sceCesEucCnToUcs2(euc, Bytes("\x80"), 1, &consumed, &ucs2) == invalidEncode);
Require(sceCesEucCnToUcs2(euc, Bytes("\x81\x40"), 2, &consumed, &ucs2) == invalidEncode);
Require(sceCesEucCnToUcs2(euc, Bytes("\xD6\x40"), 2, &consumed, &ucs2) == invalidEncode);
Require(sceCesEucCnToUcs2(euc, Bytes("\xD6\xD0"), 1, &consumed, &ucs2) == srcBufferEnd);
Require(sceCesEucCnToUcs2(euc, Bytes("\xAA\xA1"), 2, &consumed, &ucs2) == unassignedCode);
Require(sceCesEucCnToUcs2(gbk, Bytes("\xD6\xD0"), 2, &consumed, &ucs2) == invalidParameter);
Require(sceCesEucCnToUcs2(euc, nullptr, 2, &consumed, &ucs2) == invalidSrcBuffer);
Require(sceCesEucCnToUcs2(euc, Bytes("\xD6\xD0"), 2, &consumed, nullptr) == invalidDstBuffer);
std::uint8_t utf8[4] = {};
Require(sceCesEucCnToUtf8(euc, Bytes("\xCE\xC4"), 2, &consumed, utf8, sizeof(utf8), &produced) == 0);
Require(produced == 3 && std::memcmp(utf8, "\xE6\x96\x87", 3) == 0);
std::uint16_t utf16 = 0;
Require(sceCesEucCnToUtf16be(euc, Bytes("\xD6\xD0"), 2, &consumed, &utf16, 1, &produced) == 0 && std::memcmp(&utf16, "\x4E\x2D", 2) == 0);
std::uint32_t utf32 = 0;
Require(sceCesEucCnToUtf32(euc, Bytes("\xD6\xD0"), 2, &consumed, &utf32) == 0 && utf32 == 0x4E2D);
Require(sceCesGbToUcs2(gbk, Bytes("\x80"), 1, &consumed, &ucs2) == 0 && consumed == 1 && ucs2 == 0x20AC);
Require(sceCesGbToUcs2(gbk, Bytes("\x81\x40"), 2, &consumed, &ucs2) == 0 && consumed == 2 && ucs2 == 0x4E02);
Require(sceCesGbToUcs2(gbk, Bytes("\xD6\xD0"), 2, &consumed, &ucs2) == 0 && ucs2 == 0x4E2D);
Require(sceCesGbToUcs2(gbk, Bytes("\xFF"), 1, &consumed, &ucs2) == invalidEncode);
Require(sceCesGbToUcs2(gbk, Bytes("\x81\x7F"), 2, &consumed, &ucs2) == invalidEncode);
Require(sceCesGbToUcs2(gbk, Bytes("\x81\x3F"), 2, &consumed, &ucs2) == invalidEncode);
Require(sceCesGbToUcs2(euc, Bytes("\x81\x40"), 2, &consumed, &ucs2) == invalidParameter);
Require(sceCesGbToUcs2(sjis, Bytes("A"), 1, &consumed, &ucs2) == invalidParameter);
Require(sceCesGbToUtf8(gbk, Bytes("\x80"), 1, &consumed, utf8, sizeof(utf8), &produced) == 0);
Require(produced == 3 && std::memcmp(utf8, "\xE2\x82\xAC", 3) == 0);
Require(sceCesGbToUtf8(gbk, Bytes("\x80"), 1, &consumed, utf8, 2, &produced) == dstBufferEnd);
Require(sceCesGbToUtf16(gbk, Bytes("\x81\x40"), 2, &consumed, &utf16, 1, &produced) == 0 && utf16 == 0x4E02 && produced == 1);
Require(sceCesGbToUtf32le(gbk, Bytes("\x81\x40"), 2, &consumed, &utf32) == 0 && std::memcmp(&utf32, "\x02\x4E\x00\x00", 4) == 0);
std::uint8_t mbcs[4] = {};
Require(sceCesUcs2ToEucCn(0x4E2D, euc, mbcs, sizeof(mbcs), &produced) == 0 && produced == 2 && std::memcmp(mbcs, "\xD6\xD0", 2) == 0);
Require(sceCesUcs2ToEucCn(0x4E02, euc, mbcs, sizeof(mbcs), &produced) == unassignedCode);
Require(sceCesUcs2ToEucCn(0x20AC, euc, mbcs, sizeof(mbcs), &produced) == unassignedCode);
Require(sceCesUcs2ToEucCn(0x4E2D, euc, mbcs, 1, &produced) == dstBufferEnd);
Require(sceCesUcs2ToEucCn(0xDC00, euc, mbcs, sizeof(mbcs), &produced) == outOfCodeSpace);
Require(sceCesUcs2ToGb(0x4E02, gbk, mbcs, sizeof(mbcs), &produced) == 0 && produced == 2 && std::memcmp(mbcs, "\x81\x40", 2) == 0);
Require(sceCesUcs2ToGb(0x20AC, gbk, mbcs, sizeof(mbcs), &produced) == 0 && produced == 1 && mbcs[0] == 0x80);
Require(sceCesUcs2ToGb(0x3042, euc, mbcs, sizeof(mbcs), &produced) == invalidParameter);
Require(sceCesUcs2ToGb(0x3042, gbk, nullptr, sizeof(mbcs), &produced) == invalidDstBuffer);
Require(sceCesUtf8ToEucCn(Bytes("\xE6\x96\x87"), 3, &consumed, euc, mbcs, sizeof(mbcs), &produced) == 0);
Require(consumed == 3 && std::memcmp(mbcs, "\xCE\xC4", 2) == 0);
Require(sceCesUtf8ToGb(Bytes("\xF0\x9F\x98\x80"), 4, &consumed, gbk, mbcs, sizeof(mbcs), &produced) == unassignedCode);
std::uint16_t zhongLe = 0;
std::memcpy(&zhongLe, "\x2D\x4E", 2);
Require(sceCesUtf16leToGb(&zhongLe, 1, &consumed, gbk, mbcs, sizeof(mbcs), &produced) == 0 && std::memcmp(mbcs, "\xD6\xD0", 2) == 0);
Require(sceCesUtf32ToEucCn(0x110000, euc, mbcs, sizeof(mbcs), &produced) == invalidEncode);
std::uint32_t zhongBe = 0;
std::memcpy(&zhongBe, "\x00\x00\x4E\x2D", 4);
Require(sceCesUtf32beToGb(&zhongBe, gbk, mbcs, sizeof(mbcs), &produced) == 0 && std::memcmp(mbcs, "\xD6\xD0", 2) == 0);
int gbkCount = 0;
int eucCount = 0;
for (int code = 1; code < 0x10000; ++code) {
if (code >= 0xD800 && code <= 0xDFFF) continue;
std::uint8_t encoded[4] = {};
std::uint32_t size = 0;
std::uint16_t back = 0;
if (sceCesUcs2ToGb(static_cast<std::uint16_t>(code), gbk, encoded, sizeof(encoded), &size) == 0) {
Require(sceCesGbToUcs2(gbk, encoded, size, &consumed, &back) == 0 && consumed == size && back == code);
++gbkCount;
}
if (sceCesUcs2ToEucCn(static_cast<std::uint16_t>(code), euc, encoded, sizeof(encoded), &size) == 0) {
Require(size == 1 || (encoded[0] >= 0xA1 && encoded[1] >= 0xA1));
Require(sceCesEucCnToUcs2(euc, encoded, size, &consumed, &back) == 0 && consumed == size && back == code);
++eucCount;
}
}
Require(gbkCount == 127 + 1 + 21791 && eucCount > 127 + 7000 && eucCount < gbkCount);
alignas(8) std::uint8_t context[64] = {};
Require(sceCesMbcsUcsContextInit(context, gbk) == 0);
std::uint8_t text[16] = {};
Require(sceCesUtf8StrToMbcsStr(context, Bytes("A\xE4\xB8\xAD\xE2\x82\xAC"), 16, &consumed, text, sizeof(text), &produced) == 0);
Require(consumed == 7 && produced == 4 && std::memcmp(text, "A\xD6\xD0\x80", 4) == 0);
std::uint8_t back[16] = {};
Require(sceCesMbcsStrToUtf8Str(context, text, produced, &consumed, back, sizeof(back), &produced) == 0);
Require(consumed == 4 && produced == 7 && std::memcmp(back, "A\xE4\xB8\xAD\xE2\x82\xAC", 7) == 0);
alignas(8) std::uint8_t gb2000Sheet[64] = {};
alignas(8) std::uint8_t gb2005Sheet[64] = {};
const void* gb2000 = sceCesUcsProfileInitGb18030_2000(gb2000Sheet);
const void* gb2005 = sceCesUcsProfileInitGb18030_2005(gb2005Sheet);
Require(gb2000 == gb2000Sheet && gb2005 == gb2005Sheet);
Require(sceCesUcsProfileInitGb18030_2000(nullptr) == nullptr && sceCesUcsProfileInitGb18030_2005(nullptr) == nullptr);
Require(sceCesEucCnToUcs2(gb2000, Bytes("\xD6\xD0"), 2, &consumed, &ucs2) == invalidParameter);
Require(sceCesGbToUcs2(gb2005, Bytes("\xD6\xD0"), 2, &consumed, &ucs2) == 0 && consumed == 2 && ucs2 == 0x4E2D);
CheckGb18030(gb2000, false, 0xE61D3BD3, 0x83476043, 0x469CFCE5, 0, 0);
CheckGb18030(gb2005, true, 0x83EDDA69, 0x8D188DFC, 0x31CD0B55, 18, 24);
return 0;
}