4be7b55672
Port From (https://github.com/TrinityCore/TrinityCore/commit/1f60e76b7f157af6a24fa3c962b59f3391b21e75) Port From (https://github.com/TrinityCore/TrinityCore/commit/f647ff68659ed6d8d414d20520507dd451c2cb8d)
209 lines
6.3 KiB
C#
209 lines
6.3 KiB
C#
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
|
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
|
|
|
using Framework.Constants;
|
|
using System;
|
|
|
|
namespace Game.Chat
|
|
{
|
|
class Hyperlink
|
|
{
|
|
public static ChatCommandResult TryParse(out dynamic value, Type type, CommandHandler handler, string arg)
|
|
{
|
|
value = default;
|
|
|
|
HyperlinkInfo info = ParseSingleHyperlink(arg);
|
|
// invalid hyperlinks cannot be consumed
|
|
if (info == null)
|
|
return default;
|
|
|
|
if (!typeof(IHyperlink).IsAssignableFrom(type))
|
|
return default;
|
|
|
|
IHyperlink hyperLinkValue = (IHyperlink)Activator.CreateInstance(type);
|
|
|
|
// check if we got the right tag
|
|
if (info.Tag != hyperLinkValue.tag())
|
|
return default;
|
|
|
|
// store value
|
|
if (!hyperLinkValue.Parse(info.Data))
|
|
return new ChatCommandResult(handler.GetCypherString(CypherStrings.CmdparserLinkdataInvalid));
|
|
|
|
value = hyperLinkValue;
|
|
|
|
// finally, skip any potential delimiters
|
|
var (token, next) = info.Tail.Tokenize();
|
|
if (token.IsEmpty()) /* empty token = first character is delimiter, skip past it */
|
|
return new ChatCommandResult(next);
|
|
else
|
|
return new ChatCommandResult(info.Tail);
|
|
}
|
|
|
|
public static bool CheckAllLinks(string str)
|
|
{
|
|
// Step 1: Disallow all control sequences except ||, |H, |h, |c and |r
|
|
{
|
|
int pos = 0;
|
|
while ((pos = str.IndexOf('|', pos)) != -1)
|
|
{
|
|
char next = str[pos + 1];
|
|
if (next == 'H' || next == 'h' || next == 'c' || next == 'r' || next == '|')
|
|
pos += 2;
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Step 2: Parse all link sequences
|
|
// They look like this: |c<color>|H<linktag>:<linkdata>|h[<linktext>]|h|r
|
|
// - <color> is 8 hex characters AARRGGBB
|
|
// - <linktag> is arbitrary length [a-z_]
|
|
// - <linkdata> is arbitrary length, no | contained
|
|
// - <linktext> is printable
|
|
{
|
|
int pos = 0;
|
|
while ((pos = str.IndexOf('|', pos)) != -1)
|
|
{
|
|
if (str[pos + 1] == '|') // this is an escaped pipe character (||)
|
|
{
|
|
pos += 2;
|
|
continue;
|
|
}
|
|
|
|
HyperlinkInfo info = ParseSingleHyperlink(str.Substring(pos));
|
|
if (info == null)// todo fix me || !ValidateLinkInfo(info))
|
|
return false;
|
|
|
|
// tag is fine, find the next one
|
|
pos = str.Length - info.Tail.Length;
|
|
}
|
|
}
|
|
|
|
// all tags are valid
|
|
return true;
|
|
}
|
|
|
|
public static HyperlinkInfo ParseSingleHyperlink(string str)
|
|
{
|
|
if (str.IsEmpty())
|
|
return null;
|
|
|
|
string color = "";
|
|
string tag = "";
|
|
string data = "";
|
|
string text = "";
|
|
|
|
int pos = 0;
|
|
|
|
//color tag
|
|
if (str[pos++] != '|' || str[pos++] != 'c')
|
|
return null;
|
|
|
|
if (str.Length < 8)
|
|
return null;
|
|
|
|
if (str[pos] == 'n')
|
|
{
|
|
// numeric color id
|
|
pos++;
|
|
int endOfColor = str.IndexOf(":", pos);
|
|
if (endOfColor != -1)
|
|
{
|
|
color = str.Substring(pos, endOfColor - pos);
|
|
pos = endOfColor + 1;
|
|
}
|
|
else
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
// hex color
|
|
color = str.Substring(pos, 8);
|
|
pos += 8;
|
|
}
|
|
|
|
if (str[pos++] != '|' || str[pos++] != 'H')
|
|
return null;
|
|
|
|
// tag+data part follows
|
|
int delimPos = str.IndexOf('|', pos);
|
|
if (delimPos != -1)
|
|
{
|
|
tag = str.Substring(pos, delimPos - pos);
|
|
pos = (delimPos + 1);
|
|
}
|
|
else
|
|
return null;
|
|
|
|
// split tag if : is present (data separator)
|
|
int dataStart = tag.IndexOf(':');
|
|
if (dataStart != -1)
|
|
{
|
|
data = tag.Substring(dataStart + 1);
|
|
tag = tag.Substring(0, dataStart);
|
|
}
|
|
|
|
// ok, next should be link data end tag...
|
|
if (str[pos++] != 'h')
|
|
return null;
|
|
|
|
// extract text, must be between []
|
|
if (str[pos] != '[')
|
|
return null;
|
|
|
|
int openBrackets = 0;
|
|
for (int nameItr = pos; nameItr < str.Length; ++nameItr)
|
|
{
|
|
switch (str[nameItr])
|
|
{
|
|
case '[':
|
|
++openBrackets;
|
|
break;
|
|
case ']':
|
|
--openBrackets;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (openBrackets == 0)
|
|
{
|
|
text = str.Substring(pos + 1, (nameItr - 1) - pos);
|
|
pos = nameItr + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// check end tag
|
|
if (str[pos++] != '|' || str[pos++] != 'h' || str[pos++] != '|' || str[pos++] != 'r')
|
|
return null;
|
|
|
|
// ok, valid hyperlink, return info
|
|
return new(str.Substring(pos), color, tag, data, text);
|
|
}
|
|
}
|
|
|
|
class HyperlinkInfo
|
|
{
|
|
public string Tail;
|
|
public HyperlinkColor color;
|
|
public string Tag;
|
|
public string Data;
|
|
public string Text;
|
|
|
|
public HyperlinkInfo(string t, string c, string ta, string d, string te)
|
|
{
|
|
Tail = t;
|
|
color = new(c);
|
|
Tag = ta;
|
|
Data = d;
|
|
Text = te;
|
|
}
|
|
}
|
|
|
|
struct HyperlinkColor(string c)
|
|
{
|
|
public string data = c;
|
|
}
|
|
} |