ces: implement CP932 string conversion

This commit is contained in:
nmzik
2026-09-09 14:15:22 +04:00
parent c7b0d77970
commit ba18551d6e
3 changed files with 328 additions and 181 deletions
-181
View File
@@ -3003,186 +3003,6 @@ LIB_DEFINE(InitNet_1_NpUniversalDataSystem) {
} // namespace LibNpUniversalDataSystem
namespace LibCes {
LIB_VERSION("Ces", 1, "Ces", 1, 1);
static const uint8_t* KYTY_SYSV_ABI CesRefersUcsProfileCp1252() {
PRINT_NAME();
static const uint8_t profile = 0;
return &profile;
}
static uint32_t CesDecodeUtf8(const uint8_t* utf8, uint32_t utf8max, uint32_t* utf8_len) {
if (utf8 == nullptr || utf8max == 0) {
if (utf8_len != nullptr) {
*utf8_len = 0;
}
return 0xfffd;
}
const uint8_t c0 = utf8[0];
if (c0 < 0x80) {
if (utf8_len != nullptr) {
*utf8_len = 1;
}
return c0;
}
if ((c0 & 0xe0) == 0xc0 && utf8max >= 2 && (utf8[1] & 0xc0) == 0x80) {
if (utf8_len != nullptr) {
*utf8_len = 2;
}
return ((c0 & 0x1f) << 6u) | (utf8[1] & 0x3fu);
}
if ((c0 & 0xf0) == 0xe0 && utf8max >= 3 && (utf8[1] & 0xc0) == 0x80 &&
(utf8[2] & 0xc0) == 0x80) {
if (utf8_len != nullptr) {
*utf8_len = 3;
}
return ((c0 & 0x0f) << 12u) | ((utf8[1] & 0x3fu) << 6u) | (utf8[2] & 0x3fu);
}
if ((c0 & 0xf8) == 0xf0 && utf8max >= 4 && (utf8[1] & 0xc0) == 0x80 &&
(utf8[2] & 0xc0) == 0x80 && (utf8[3] & 0xc0) == 0x80) {
if (utf8_len != nullptr) {
*utf8_len = 4;
}
return ((c0 & 0x07) << 18u) | ((utf8[1] & 0x3fu) << 12u) | ((utf8[2] & 0x3fu) << 6u) |
(utf8[3] & 0x3fu);
}
if (utf8_len != nullptr) {
*utf8_len = 1;
}
return 0xfffd;
}
struct Cp1252Mapping {
uint8_t cp1252;
uint32_t unicode;
};
static constexpr Cp1252Mapping CP1252_EXTENDED_MAP[] = {
{0x80, 0x20ac}, {0x82, 0x201a}, {0x83, 0x0192}, {0x84, 0x201e}, {0x85, 0x2026}, {0x86, 0x2020},
{0x87, 0x2021}, {0x88, 0x02c6}, {0x89, 0x2030}, {0x8a, 0x0160}, {0x8b, 0x2039}, {0x8c, 0x0152},
{0x8e, 0x017d}, {0x91, 0x2018}, {0x92, 0x2019}, {0x93, 0x201c}, {0x94, 0x201d}, {0x95, 0x2022},
{0x96, 0x2013}, {0x97, 0x2014}, {0x98, 0x02dc}, {0x99, 0x2122}, {0x9a, 0x0161}, {0x9b, 0x203a},
{0x9c, 0x0153}, {0x9e, 0x017e}, {0x9f, 0x0178},
};
static uint8_t CesUnicodeToCp1252(uint32_t code) {
if (code <= 0x7f || (code >= 0xa0 && code <= 0xff)) {
return static_cast<uint8_t>(code);
}
for (const auto& map: CP1252_EXTENDED_MAP) {
if (map.unicode == code) {
return map.cp1252;
}
}
return '?';
}
static uint32_t CesCp1252ToUnicode(uint8_t sbc) {
if (sbc <= 0x7f || sbc >= 0xa0) {
return sbc;
}
for (const auto& map: CP1252_EXTENDED_MAP) {
if (map.cp1252 == sbc) {
return map.unicode;
}
}
return sbc;
}
static uint32_t CesEncodeUtf8(uint32_t code, uint8_t* utf8, uint32_t utf8max) {
uint8_t tmp[4] {};
uint32_t len = 0;
if (code <= 0x7f) {
tmp[0] = static_cast<uint8_t>(code);
len = 1;
} else if (code <= 0x7ff) {
tmp[0] = static_cast<uint8_t>(0xc0u | ((code >> 6u) & 0x1fu));
tmp[1] = static_cast<uint8_t>(0x80u | (code & 0x3fu));
len = 2;
} else if (code <= 0xffff) {
tmp[0] = static_cast<uint8_t>(0xe0u | ((code >> 12u) & 0x0fu));
tmp[1] = static_cast<uint8_t>(0x80u | ((code >> 6u) & 0x3fu));
tmp[2] = static_cast<uint8_t>(0x80u | (code & 0x3fu));
len = 3;
} else {
tmp[0] = static_cast<uint8_t>(0xf0u | ((code >> 18u) & 0x07u));
tmp[1] = static_cast<uint8_t>(0x80u | ((code >> 12u) & 0x3fu));
tmp[2] = static_cast<uint8_t>(0x80u | ((code >> 6u) & 0x3fu));
tmp[3] = static_cast<uint8_t>(0x80u | (code & 0x3fu));
len = 4;
}
if (utf8 != nullptr && utf8max >= len) {
std::memcpy(utf8, tmp, len);
}
return len;
}
static int KYTY_SYSV_ABI CesUtf8ToSbc(const uint8_t* utf8, uint32_t utf8max, uint32_t* utf8_len,
const uint8_t* profile, uint8_t* sbc) {
PRINT_NAME();
if (sbc == nullptr || profile == nullptr) {
return -1;
}
uint32_t local_len = 0;
const auto code = CesDecodeUtf8(utf8, utf8max, &local_len);
if (utf8_len != nullptr) {
*utf8_len = local_len;
}
*sbc = CesUnicodeToCp1252(code);
return 0;
}
static int KYTY_SYSV_ABI CesSbcToUtf8(const uint8_t* profile, uint8_t sbc, uint8_t* utf8,
uint32_t utf8max, uint32_t* utf8_len) {
PRINT_NAME();
if (profile == nullptr || utf8 == nullptr) {
return -1;
}
const auto code = CesCp1252ToUnicode(sbc);
const auto len = CesEncodeUtf8(code, utf8, utf8max);
if (utf8_len != nullptr) {
*utf8_len = len;
}
return utf8max >= len ? 0 : -1;
}
static int KYTY_SYSV_ABI CesStub(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3) {
PRINT_NAME();
(void)arg0;
(void)arg1;
(void)arg2;
(void)arg3;
return 0;
}
LIB_DEFINE(InitNet_1_Ces) {
LIB_FUNC("ZiDCxUUGbec", LibCes::CesStub);
LIB_FUNC("538bRGc6Zo8", LibCes::CesStub);
LIB_FUNC("LPzYZ+FR0BI", LibCes::CesRefersUcsProfileCp1252);
LIB_FUNC("3Q1gOWWarcw", LibCes::CesUtf8ToSbc);
LIB_FUNC("xTd54EEL1Ao", LibCes::CesSbcToUtf8);
}
} // namespace LibCes
namespace LibNpGameIntent {
LIB_VERSION("NpGameIntent", 1, "NpGameIntent", 1, 1);
@@ -3992,7 +3812,6 @@ LIB_DEFINE(InitNet_1) {
LibNpAuth::InitNet_1_NpAuth(s);
LibNpTrophy2::InitNet_1_NpTrophy2(s);
LibNpUniversalDataSystem::InitNet_1_NpUniversalDataSystem(s);
LibCes::InitNet_1_Ces(s);
LibNpGameIntent::InitNet_1_NpGameIntent(s);
LibNpWebApi2::InitNet_1_NpWebApi2(s);
LibGameUpdate::InitNet_1_GameUpdate(s);