aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Chat/Hyperlinks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Chat/Hyperlinks.cpp')
-rw-r--r--src/server/game/Chat/Hyperlinks.cpp204
1 files changed, 110 insertions, 94 deletions
diff --git a/src/server/game/Chat/Hyperlinks.cpp b/src/server/game/Chat/Hyperlinks.cpp
index eb49cdcc10b..ed18f7b380b 100644
--- a/src/server/game/Chat/Hyperlinks.cpp
+++ b/src/server/game/Chat/Hyperlinks.cpp
@@ -31,82 +31,90 @@ using namespace Trinity::Hyperlinks;
inline uint8 toHex(char c) { return (c >= '0' && c <= '9') ? c - '0' + 0x10 : (c >= 'a' && c <= 'f') ? c - 'a' + 0x1a : 0x00; }
// Validates a single hyperlink
-HyperlinkInfo Trinity::Hyperlinks::ParseHyperlink(char const* pos)
+HyperlinkInfo Trinity::Hyperlinks::ParseSingleHyperlink(std::string_view str)
{
- //color tag
- if (*(pos++) != '|' || *(pos++) != 'c')
- return nullptr;
uint32 color = 0;
+ std::string_view tag;
+ std::string_view data;
+ std::string_view text;
+
+ //color tag
+ if (str.substr(0, 2) != "|c")
+ return {};
+ str.remove_prefix(2);
+
+ if (str.length() < 8)
+ return {};
+
for (uint8 i = 0; i < 8; ++i)
{
- if (uint8 hex = toHex(*(pos++)))
+ if (uint8 hex = toHex(str[i]))
color = (color << 4) | (hex & 0xf);
else
- return nullptr;
+ return {};
}
- // link data start tag
- if (*(pos++) != '|' || *(pos++) != 'H')
- return nullptr;
- // link tag, find next : or |
- char const* tagStart = pos;
- size_t tagLength = 0;
- while (*pos && *pos != '|' && *(pos++) != ':') // we only advance pointer to one past if the last thing is : (not for |), this is intentional!
- ++tagLength;
- // ok, link data, skip to next |
- char const* dataStart = pos;
- size_t dataLength = 0;
- while (*pos && *(pos++) != '|')
- ++dataLength;
+ str.remove_prefix(8);
+
+ if (str.substr(0, 2) != "|H")
+ return {};
+ str.remove_prefix(2);
+
+ // tag+data part follows
+ if (size_t delimPos = str.find('|'); delimPos != std::string_view::npos)
+ {
+ tag = str.substr(0, delimPos);
+ str.remove_prefix(delimPos+1);
+ }
+ else
+ return {};
+
+ // split tag if : is present (data separator)
+ if (size_t dataStart = tag.find(':'); dataStart != std::string_view::npos)
+ {
+ data = tag.substr(dataStart+1);
+ tag = tag.substr(0, dataStart);
+ }
+
// ok, next should be link data end tag...
- if (*(pos++) != 'h')
- return nullptr;
- // then visible link text, starts with [
- if (*(pos++) != '[')
- return nullptr;
- // skip until we hit the next ], abort on unexpected |
- char const* textStart = pos;
- size_t textLength = 0;
- while (*pos)
+ if (str.substr(0, 1) != "h")
+ return {};
+ str.remove_prefix(1);
+ // skip to final |
+ if (size_t end = str.find('|'); end != std::string_view::npos)
{
- if (*pos == '|')
- return nullptr;
- if (*(pos++) == ']')
- break;
- ++textLength;
+ // check end tag
+ if (str.substr(end, 4) != "|h|r")
+ return {};
+ // check text brackets
+ if ((str[0] != '[') || (str[end - 1] != ']'))
+ return {};
+ text = str.substr(1, end - 2);
+ // tail
+ str = str.substr(end + 4);
}
- // link end tag
- if (*(pos++) != '|' || *(pos++) != 'h' || *(pos++) != '|' || *(pos++) != 'r')
- return nullptr;
+ else
+ return {};
+
// ok, valid hyperlink, return info
- return { pos, color, tagStart, tagLength, dataStart, dataLength, textStart, textLength };
+ return { str, color, tag, data, text };
}
template <typename T>
struct LinkValidator
{
- static bool IsTextValid(typename T::value_type, char const*, size_t) { return true; }
+ static bool IsTextValid(typename T::value_type, std::string_view) { return true; }
static bool IsColorValid(typename T::value_type, HyperlinkColor) { return true; }
};
-// str1 is null-terminated, str2 is length-terminated, check if they are exactly equal
-static bool equal_with_len(char const* str1, char const* str2, size_t len)
-{
- if (!*str1)
- return false;
- while (len && *str1 && *(str1++) == *(str2++))
- --len;
- return !len && !*str1;
-}
-
template <>
struct LinkValidator<LinkTags::achievement>
{
- static bool IsTextValid(AchievementLinkData const& data, char const* pos, size_t len)
+ static bool IsTextValid(AchievementLinkData const& data, std::string_view text)
{
- if (!len)
+ if (text.empty())
return false;
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
- if (equal_with_len(data.Achievement->Title[i], pos, len))
+ if (text == data.Achievement->Title[i])
return true;
return false;
}
@@ -120,22 +128,22 @@ struct LinkValidator<LinkTags::achievement>
template <>
struct LinkValidator<LinkTags::item>
{
- static bool IsTextValid(ItemLinkData const& data, char const* pos, size_t len)
+ static bool IsTextValid(ItemLinkData const& data, std::string_view text)
{
ItemLocale const* locale = sObjectMgr->GetItemLocale(data.Item->ItemId);
- char const* const* randomSuffix = nullptr;
+ char const* const* randomSuffixes = nullptr; // this is a c-style array of c strings (and i don't want to touch DBCStructure.h right now)
if (data.RandomPropertyId < 0)
{
if (ItemRandomSuffixEntry const* suffixEntry = sItemRandomSuffixStore.LookupEntry(-data.RandomPropertyId))
- randomSuffix = suffixEntry->Name;
+ randomSuffixes = suffixEntry->Name;
else
return false;
}
else if (data.RandomPropertyId > 0)
{
if (ItemRandomPropertiesEntry const* propEntry = sItemRandomPropertiesStore.LookupEntry(data.RandomPropertyId))
- randomSuffix = propEntry->Name;
+ randomSuffixes = propEntry->Name;
else
return false;
}
@@ -147,15 +155,18 @@ struct LinkValidator<LinkTags::item>
std::string const& name = (i == DEFAULT_LOCALE) ? data.Item->Name1 : locale->Name[i];
if (name.empty())
continue;
- if (randomSuffix)
+ if (randomSuffixes)
{
- if (len > name.length() + 1 &&
- (strncmp(name.c_str(), pos, name.length()) == 0) &&
- (*(pos + name.length()) == ' ') &&
- equal_with_len(randomSuffix[i], pos + name.length() + 1, len - name.length() - 1))
+ std::string_view randomSuffix(randomSuffixes[i]);
+ if (
+ (text.length() == (name.length() + 1 + randomSuffix.length())) &&
+ (text.substr(0, name.length()) == name) &&
+ (text[name.length()] == ' ') &&
+ (text.substr(name.length() + 1) == randomSuffix)
+ )
return true;
}
- else if (equal_with_len(name.c_str(), pos, len))
+ else if (text == name)
return true;
}
return false;
@@ -170,18 +181,18 @@ struct LinkValidator<LinkTags::item>
template <>
struct LinkValidator<LinkTags::quest>
{
- static bool IsTextValid(QuestLinkData const& data, char const* pos, size_t len)
+ static bool IsTextValid(QuestLinkData const& data, std::string_view text)
{
QuestLocale const* locale = sObjectMgr->GetQuestLocale(data.Quest->GetQuestId());
if (!locale)
- return equal_with_len(data.Quest->GetTitle().c_str(), pos, len);
+ return text == data.Quest->GetTitle();
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
std::string const& name = (i == DEFAULT_LOCALE) ? data.Quest->GetTitle() : locale->Title[i];
if (name.empty())
continue;
- if (equal_with_len(name.c_str(), pos, len))
+ if (text == name)
return true;
}
@@ -200,10 +211,10 @@ struct LinkValidator<LinkTags::quest>
template <>
struct LinkValidator<LinkTags::spell>
{
- static bool IsTextValid(SpellInfo const* info, char const* pos, size_t len)
+ static bool IsTextValid(SpellInfo const* info, std::string_view text)
{
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
- if (equal_with_len(info->SpellName[i], pos, len))
+ if (text == info->SpellName[i])
return true;
return false;
}
@@ -217,9 +228,9 @@ struct LinkValidator<LinkTags::spell>
template <>
struct LinkValidator<LinkTags::enchant>
{
- static bool IsTextValid(SpellInfo const* info, char const* pos, size_t len)
+ static bool IsTextValid(SpellInfo const* info, std::string_view text)
{
- if (LinkValidator<LinkTags::spell>::IsTextValid(info, pos, len))
+ if (LinkValidator<LinkTags::spell>::IsTextValid(info, text))
return true;
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(info->Id);
if (bounds.first == bounds.second)
@@ -233,12 +244,15 @@ struct LinkValidator<LinkTags::enchant>
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
- char const* skillName = skill->DisplayName[i];
- size_t skillLen = strlen(skillName);
- if (len > skillLen + 2 && // or of form [Skill Name: Spell Name]
- !strncmp(pos, skillName, skillLen) && !strncmp(pos + skillLen, ": ", 2) &&
- equal_with_len(info->SpellName[i], pos + (skillLen + 2), len - (skillLen + 2)))
- return true;
+ std::string_view spellName = info->SpellName[i];
+ std::string_view skillName = skill->DisplayName[i];
+ // alternate form [Skill Name: Spell Name]
+ return (
+ (text.length() == (spellName.length() + 2 + skillName.length())) &&
+ (text.substr(0, spellName.length()) == spellName) &&
+ (text.substr(spellName.length(), 2) == ": ") &&
+ (text.substr(spellName.length() + 2) == skillName)
+ );
}
}
return false;
@@ -253,10 +267,10 @@ struct LinkValidator<LinkTags::enchant>
template <>
struct LinkValidator<LinkTags::glyph>
{
- static bool IsTextValid(GlyphLinkData const& data, char const* pos, size_t len)
+ static bool IsTextValid(GlyphLinkData const& data, std::string_view text)
{
if (SpellInfo const* info = sSpellMgr->GetSpellInfo(data.Glyph->SpellID))
- return LinkValidator<LinkTags::spell>::IsTextValid(info, pos, len);
+ return LinkValidator<LinkTags::spell>::IsTextValid(info, text);
return false;
}
@@ -269,10 +283,10 @@ struct LinkValidator<LinkTags::glyph>
template <>
struct LinkValidator<LinkTags::talent>
{
- static bool IsTextValid(TalentLinkData const& data, char const* pos, size_t len)
+ static bool IsTextValid(TalentLinkData const& data, std::string_view text)
{
if (SpellInfo const* info = sSpellMgr->GetSpellInfo(data.Talent->SpellRank[0]))
- return LinkValidator<LinkTags::spell>::IsTextValid(info, pos, len);
+ return LinkValidator<LinkTags::spell>::IsTextValid(info, text);
return false;
}
@@ -285,9 +299,9 @@ struct LinkValidator<LinkTags::talent>
template <>
struct LinkValidator<LinkTags::trade>
{
- static bool IsTextValid(TradeskillLinkData const& data, char const* pos, size_t len)
+ static bool IsTextValid(TradeskillLinkData const& data, std::string_view text)
{
- return LinkValidator<LinkTags::spell>::IsTextValid(data.Spell, pos, len);
+ return LinkValidator<LinkTags::spell>::IsTextValid(data.Spell, text);
}
static bool IsColorValid(TradeskillLinkData const&, HyperlinkColor c)
@@ -298,17 +312,16 @@ struct LinkValidator<LinkTags::trade>
#define TryValidateAs(tagname) \
{ \
- ASSERT(!strcmp(LinkTags::tagname::tag(), #tagname)); \
- if (info.tag.second == strlen(LinkTags::tagname::tag()) && \
- !strncmp(info.tag.first, LinkTags::tagname::tag(), strlen(LinkTags::tagname::tag()))) \
+ static_assert(LinkTags::tagname::tag() == #tagname); \
+ if (info.tag == LinkTags::tagname::tag()) \
{ \
advstd::remove_cvref_t<typename LinkTags::tagname::value_type> t; \
- if (!LinkTags::tagname::StoreTo(t, info.data.first, info.data.second)) \
+ if (!LinkTags::tagname::StoreTo(t, info.data)) \
return false; \
if (!LinkValidator<LinkTags::tagname>::IsColorValid(t, info.color)) \
return false; \
if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY)) \
- if (!LinkValidator<LinkTags::tagname>::IsTextValid(t, info.text.first, info.text.second)) \
+ if (!LinkValidator<LinkTags::tagname>::IsTextValid(t, info.text)) \
return false; \
return true; \
} \
@@ -341,16 +354,19 @@ static bool ValidateLinkInfo(HyperlinkInfo const& info)
}
// Validates all hyperlinks and control sequences contained in str
-bool Trinity::Hyperlinks::CheckAllLinks(std::string const& str)
+bool Trinity::Hyperlinks::CheckAllLinks(std::string_view str)
{
// Step 1: Disallow all control sequences except ||, |H, |h, |c and |r
{
- std::string::size_type pos = 0;
+ std::string_view::size_type pos = 0;
while ((pos = str.find('|', pos)) != std::string::npos)
{
- char next = str[pos + 1];
+ ++pos;
+ if (pos == str.length())
+ return false;
+ char next = str[pos];
if (next == 'H' || next == 'h' || next == 'c' || next == 'r' || next == '|')
- pos += 2;
+ ++pos;
else
return false;
}
@@ -363,21 +379,21 @@ bool Trinity::Hyperlinks::CheckAllLinks(std::string const& str)
// - <linkdata> is arbitrary length, no | contained
// - <linktext> is printable
{
- std::string::size_type pos = 0;
- while ((pos = str.find('|', pos)) != std::string::npos)
+ std::string::size_type pos;
+ while ((pos = str.find('|')) != std::string::npos)
{
if (str[pos + 1] == '|') // this is an escaped pipe character (||)
{
- pos += 2;
+ str = str.substr(pos + 2);
continue;
}
- HyperlinkInfo info = ParseHyperlink(str.c_str() + pos);
+ HyperlinkInfo info = ParseSingleHyperlink(str.substr(pos));
if (!info || !ValidateLinkInfo(info))
return false;
// tag is fine, find the next one
- pos = info.next - str.c_str();
+ str = info.tail;
}
}