mirror of
https://github.com/whoahq/whoa.git
synced 2026-02-01 00:02:45 +03:00
feat(gx): handle remaining codes in GxuDetermineQuotedCode
This commit is contained in:
parent
d1cd084309
commit
8e693843fa
@ -23,19 +23,29 @@ QUOTEDCODE GxuDetermineQuotedCode(const char* text, int32_t& advance, CImVector*
|
||||
|
||||
switch (wide) {
|
||||
case 0x0:
|
||||
case 0xFFFFFFFF:
|
||||
case 0xFFFFFFFF: {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
case '\r': {
|
||||
auto next = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(text + 1), &advance);
|
||||
advance = next == '\n' ? 2 : 1;
|
||||
|
||||
case '\r':
|
||||
advance = 2 - (SUniSGetUTF8(reinterpret_cast<const uint8_t*>(text + 1), &advance) != '\n');
|
||||
return CODE_NEWLINE;
|
||||
}
|
||||
|
||||
case '\n':
|
||||
case '\n': {
|
||||
advance = 1;
|
||||
|
||||
return CODE_NEWLINE;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (wide != '|' || flags & 0x800) {
|
||||
if (wide != '|' || flags & FLAG_IGNORE_PIPES) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
@ -46,22 +56,182 @@ QUOTEDCODE GxuDetermineQuotedCode(const char* text, int32_t& advance, CImVector*
|
||||
}
|
||||
|
||||
switch (quotedCode) {
|
||||
case 'C':
|
||||
case 'c': {
|
||||
if (flags & FLAG_IGNORE_COLORS) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
int32_t offset = advance + 1;
|
||||
uint8_t value[4];
|
||||
|
||||
for (int32_t i = 0; i < 4; i++) {
|
||||
if (!text[offset + 0] || !text[offset + 1]) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
char hex[4];
|
||||
hex[0] = text[offset + 0];
|
||||
hex[1] = text[offset + 1];
|
||||
hex[2] = '\0';
|
||||
|
||||
char* end = nullptr;
|
||||
|
||||
auto v = strtol(hex, &end, 16);
|
||||
|
||||
// Error parsing hex
|
||||
if (end && *end) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
value[i] = v;
|
||||
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
if (color) {
|
||||
// Alpha is ignored
|
||||
color->value = CImVector::MakeARGB(0xFF, value[1], value[2], value[3]);
|
||||
}
|
||||
|
||||
advance = 10;
|
||||
|
||||
return CODE_COLORON;
|
||||
}
|
||||
|
||||
case 'H': {
|
||||
if (flags & FLAG_IGNORE_HYPERLINKS) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
auto linkText = text + advance;
|
||||
|
||||
while (*linkText) {
|
||||
auto code = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(linkText), &advance);
|
||||
linkText += advance;
|
||||
|
||||
if (code == '|') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*linkText) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
auto endCode = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(linkText), &advance);
|
||||
linkText += advance;
|
||||
|
||||
// Null terminator or end code isn't |h (end link payload)
|
||||
if (!*linkText || endCode != 'h') {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
// Empty link (no payload)
|
||||
if (linkText - text == 4) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
// Empty display text
|
||||
if (linkText[0] == '|' && linkText[1] == 'h') {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
advance = linkText - text;
|
||||
|
||||
return CODE_HYPERLINKSTART;
|
||||
}
|
||||
|
||||
case 'N':
|
||||
case 'n': {
|
||||
if (flags & 0x200) {
|
||||
if (flags & FLAG_IGNORE_NEWLINES) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
advance = 2;
|
||||
|
||||
return CODE_NEWLINE;
|
||||
}
|
||||
|
||||
// TODO handle other control codes
|
||||
case 'R':
|
||||
case 'r': {
|
||||
if (flags & FLAG_IGNORE_COLORS) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
advance = 2;
|
||||
|
||||
return CODE_COLORRESTORE;
|
||||
}
|
||||
|
||||
case 'T': {
|
||||
if (flags & FLAG_IGNORE_TEXTURES) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
auto textureText = text + advance;
|
||||
|
||||
while (*textureText) {
|
||||
auto code = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(textureText), &advance);
|
||||
textureText += advance;
|
||||
|
||||
if (code == '|') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*textureText) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
auto endCode = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(textureText), &advance);
|
||||
textureText += advance;
|
||||
|
||||
// Null terminator or end code isn't |t
|
||||
if (!*textureText || endCode != 't') {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
// Empty texture (no payload)
|
||||
if (textureText - text == 4) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
advance = textureText - text;
|
||||
|
||||
return CODE_TEXTURESTART;
|
||||
}
|
||||
|
||||
case 'h': {
|
||||
if (flags & FLAG_IGNORE_HYPERLINKS) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
advance = 2;
|
||||
|
||||
return CODE_HYPERLINKSTOP;
|
||||
}
|
||||
|
||||
case 't': {
|
||||
if (flags & FLAG_IGNORE_TEXTURES) {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
advance = 2;
|
||||
|
||||
return CODE_TEXTURESTOP;
|
||||
}
|
||||
|
||||
case '|': {
|
||||
advance = 2;
|
||||
|
||||
return CODE_PIPE;
|
||||
}
|
||||
|
||||
default: {
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO remainder of function
|
||||
|
||||
return CODE_INVALIDCODE;
|
||||
}
|
||||
|
||||
int32_t GxuFontAddToBatch(CGxStringBatch* batch, CGxString* string) {
|
||||
|
||||
@ -70,4 +70,141 @@ TEST_CASE("GxuDetermineQuotedCode", "[gx]") {
|
||||
REQUIRE(quotedCode == CODE_NEWLINE);
|
||||
REQUIRE(advance == 2);
|
||||
}
|
||||
|
||||
SECTION("recognizes colors") {
|
||||
const char* str = "test1|c00123456test2|rtest3";
|
||||
uint32_t flags = 0x0;
|
||||
|
||||
int32_t advance;
|
||||
uint32_t wide;
|
||||
QUOTEDCODE quotedCode;
|
||||
CImVector color;
|
||||
|
||||
// |c00123456
|
||||
str += 5;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, &color, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_COLORON);
|
||||
REQUIRE(advance == 10);
|
||||
REQUIRE(color.value == 0xFF123456);
|
||||
str += advance;
|
||||
|
||||
// |r
|
||||
str += 5;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_COLORRESTORE);
|
||||
REQUIRE(advance == 2);
|
||||
}
|
||||
|
||||
SECTION("recognizes colors with uppercase codes") {
|
||||
const char* str = "test1|C00123456test2|Rtest3";
|
||||
uint32_t flags = 0x0;
|
||||
|
||||
int32_t advance;
|
||||
uint32_t wide;
|
||||
QUOTEDCODE quotedCode;
|
||||
CImVector color;
|
||||
|
||||
// |C00123456
|
||||
str += 5;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, &color, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_COLORON);
|
||||
REQUIRE(advance == 10);
|
||||
REQUIRE(color.value == 0xFF123456);
|
||||
str += advance;
|
||||
|
||||
// |R
|
||||
str += 5;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_COLORRESTORE);
|
||||
REQUIRE(advance == 2);
|
||||
}
|
||||
|
||||
SECTION("ignores colors when FLAG_IGNORE_COLORS is set") {
|
||||
const char* str = "test1|c00123456test2|rtest3";
|
||||
uint32_t flags = FLAG_IGNORE_COLORS;
|
||||
|
||||
int32_t advance;
|
||||
uint32_t wide;
|
||||
QUOTEDCODE quotedCode;
|
||||
|
||||
// |c00123456
|
||||
str += 5;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_INVALIDCODE);
|
||||
|
||||
// |r
|
||||
str += 15;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_INVALIDCODE);
|
||||
}
|
||||
|
||||
SECTION("recognizes hyperlinks") {
|
||||
const char* str = "test1|Hspell:2061:0|h[Flash Heal]|htest3";
|
||||
uint32_t flags = 0x0;
|
||||
|
||||
int32_t advance;
|
||||
uint32_t wide;
|
||||
QUOTEDCODE quotedCode;
|
||||
|
||||
// |Hspell:2061:0|h
|
||||
str += 5;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_HYPERLINKSTART);
|
||||
REQUIRE(advance == 16);
|
||||
str += advance;
|
||||
|
||||
// |h
|
||||
str += 12;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_HYPERLINKSTOP);
|
||||
REQUIRE(advance == 2);
|
||||
}
|
||||
|
||||
SECTION("ignores hyperlinks when FLAG_IGNORE_HYPERLINKS is set") {
|
||||
const char* str = "test1|Hspell:2061:0|h[Flash Heal]|htest3";
|
||||
uint32_t flags = FLAG_IGNORE_HYPERLINKS;
|
||||
|
||||
int32_t advance;
|
||||
uint32_t wide;
|
||||
QUOTEDCODE quotedCode;
|
||||
|
||||
// |Hspell:2061:0|h
|
||||
str += 5;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_INVALIDCODE);
|
||||
|
||||
// |h
|
||||
str += 28;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_INVALIDCODE);
|
||||
}
|
||||
|
||||
SECTION("recognizes textures") {
|
||||
const char* str = "test1|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1.blp:0|ttest3";
|
||||
uint32_t flags = 0x0;
|
||||
|
||||
int32_t advance;
|
||||
uint32_t wide;
|
||||
QUOTEDCODE quotedCode;
|
||||
|
||||
// |TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1.blp:0|t
|
||||
str += 5;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_TEXTURESTART);
|
||||
REQUIRE(advance == 57);
|
||||
}
|
||||
|
||||
SECTION("ignores textures when FLAG_IGNORE_TEXTURES is set") {
|
||||
const char* str = "test1|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1.blp:0|ttest3";
|
||||
uint32_t flags = FLAG_IGNORE_TEXTURES;
|
||||
|
||||
int32_t advance;
|
||||
uint32_t wide;
|
||||
QUOTEDCODE quotedCode;
|
||||
|
||||
// |TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1.blp:0|t
|
||||
str += 5;
|
||||
quotedCode = GxuDetermineQuotedCode(str, advance, nullptr, flags, wide);
|
||||
REQUIRE(quotedCode == CODE_INVALIDCODE);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user