using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using System.Windows.Controls; using System.Windows.Threading; namespace XIVChat_Desktop { public static class Util { // GOOD HEAVENS! I REALISE HOW INEFFICIENT THIS IS public static byte[] StringToByteArray(string hex) { return Enumerable.Range(0, hex.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) .ToArray(); } public static IEnumerable> Chunks(this List locations, int nSize) { for (var i = 0; i < locations.Count; i += nSize) { yield return locations.GetRange(i, Math.Min(nSize, locations.Count - i)); } } public static void Dispatch(this DispatcherObject dispatcherObj, Action action) { dispatcherObj.Dispatcher.BeginInvoke(action); } public static void Dispatch(this DispatcherObject dispatcherObj, DispatcherPriority priority, Action action) { dispatcherObj.Dispatcher.BeginInvoke(priority, action); } public static bool IsAsciiPunctuation(this char c) { // 2.1 Characters and lines // An ASCII punctuation character is !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~. switch (c) { case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case '[': case '\\': case ']': case '^': case '_': case '`': case '{': case '|': case '}': case '~': return true; } return false; } public static bool IsWhitespace(this char c) { // 2.1 Characters and lines // A whitespace character is a space(U + 0020), tab(U + 0009), newline(U + 000A), line tabulation (U + 000B), form feed (U + 000C), or carriage return (U + 000D). return c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'); } public static string? WorldName(ushort id) { return id switch { 1 => "reserved1", 2 => "c-contents", 3 => "c-whiteae", 4 => "c-baudinii", 5 => "c-contents2", 6 => "c-funereus", 16 => "konconv", 23 => "Asura", 24 => "Belias", 25 => "Chaos", 26 => "Hecatoncheir", 27 => "Moomba", 28 => "Pandaemonium", 29 => "Shinryu", 30 => "Unicorn", 31 => "Yojimbo", 32 => "Zeromus", 33 => "Twintania", 34 => "Brynhildr", 35 => "Famfrit", 36 => "Lich", 37 => "Mateus", 38 => "Shemhazai", 39 => "Omega", 40 => "Jenova", 41 => "Zalera", 42 => "Zodiark", 43 => "Alexander", 44 => "Anima", 45 => "Carbuncle", 46 => "Fenrir", 47 => "Hades", 48 => "Ixion", 49 => "Kujata", 50 => "Typhon", 51 => "Ultima", 52 => "Valefor", 53 => "Exodus", 54 => "Faerie", 55 => "Lamia", 56 => "Phoenix", 57 => "Siren", 58 => "Garuda", 59 => "Ifrit", 60 => "Ramuh", 61 => "Titan", 62 => "Diabolos", 63 => "Gilgamesh", 64 => "Leviathan", 65 => "Midgardsormr", 66 => "Odin", 67 => "Shiva", 68 => "Atomos", 69 => "Bahamut", 70 => "Chocobo", 71 => "Moogle", 72 => "Tonberry", 73 => "Adamantoise", 74 => "Coeurl", 75 => "Malboro", 76 => "Tiamat", 77 => "Ultros", 78 => "Behemoth", 79 => "Cactuar", 80 => "Cerberus", 81 => "Goblin", 82 => "Mandragora", 83 => "Louisoix", 84 => "Syldra", 85 => "Spriggan", 90 => "Aegis", 91 => "Balmung", 92 => "Durandal", 93 => "Excalibur", 94 => "Gungnir", 95 => "Hyperion", 96 => "Masamune", 97 => "Ragnarok", 98 => "Ridill", 99 => "Sargatanas", 100 => "dev_test", 101 => "zone_test", 102 => "trs_test", 103 => "contents_test", 110 => "b-tirica", 111 => "b-contents", 112 => "b-chiriri", 113 => "b-contents2", 114 => "b-jugularis", 115 => "e-regia", 116 => "e-pialii", 117 => "e-contents", 118 => "e-contents2", 119 => "e-coloria", 120 => "e-gouldiae", 121 => "e-contents3", 123 => "e-trichroa", 124 => "e-hyperion", 126 => "e-ragnarok", 127 => "e-ridill", 128 => "e-sargatanas", 129 => "a-militaris", 130 => "a-aegis", 131 => "a-balmung", 132 => "a-durandal", 133 => "a-excalibur", 134 => "a-gungnir", 135 => "a-hyperion", 136 => "a-masamune", 137 => "a-ragnarok", 138 => "a-ridill", 139 => "a-sargatanas", 140 => "a-contents", 141 => "b-contents3", 142 => "b-cyanoptera", 144 => "a-contentsx", 145 => "a-contents2", 156 => "z-japonicus", 157 => "z-dauma", 158 => "z-contents", 159 => "z-contents2", 160 => "s-bella", 161 => "Chocobo", 162 => "s-contents", 163 => "chs-contents", 164 => "s-contents2", 165 => "s-guttata", 166 => "Moogle", 167 => "chs-contents2", 168 => "Namazu", 169 => "chs-contents3", 170 => "s-poliogenys", 171 => "s-haematina", 172 => "s-contents3", 173 => "s-contents4", 174 => "s-public1", 175 => "s-public2", 176 => "s-public3", 177 => "s-public4", 178 => "s-public5", 179 => "s-public6", 180 => "s-public7", 181 => "s-public8", 182 => "s-macropus", 183 => "s-contents7", 184 => "s-latrans", 185 => "s-contents8", 186 => "s-cucullatus", 187 => "s-bicolor", 188 => "s-contents5", 189 => "s-contents6", 201 => "Nacontents01", 202 => "Nacontents02", 203 => "Nacontents03", 204 => "Nacontents04", 205 => "Nacontents05", 206 => "Nacontents06", 207 => "Nacontents07", 208 => "Nacontents08", 209 => "Nacontents09", 210 => "Nacontents10", 211 => "Nacontents11", 212 => "Nacontents12", 213 => "Nacontents13", 214 => "Nacontents14", 215 => "Nacontents15", 216 => "Nacontents16", 217 => "Nacontents17", 218 => "Nacontents18", 219 => "Nacontents19", 220 => "Nacontents20", 221 => "Nacontents21", 222 => "Nacontents22", 223 => "Nacontents23", 224 => "Nacontents24", 225 => "Jpcontents01", 226 => "Jpcontents02", 227 => "Jpcontents03", 228 => "Jpcontents04", 229 => "Jpcontents05", 230 => "Jpcontents06", 231 => "Jpcontents07", 232 => "Jpcontents08", 233 => "Jpcontents09", 234 => "Jpcontents10", 235 => "Jpcontents11", 236 => "Jpcontents12", 237 => "Jpcontents13", 238 => "Jpcontents14", 239 => "Jpcontents15", 240 => "Jpcontents16", 241 => "Jpcontents17", 242 => "Jpcontents18", 243 => "Jpcontents19", 244 => "Jpcontents20", 245 => "Jpcontents21", 246 => "Jpcontents22", 247 => "Jpcontents23", 248 => "Jpcontents24", 249 => "Jpcontents25", 250 => "Jpcontents26", 251 => "Jpcontents27", 252 => "Jpcontents28", 253 => "Jpcontents29", 254 => "Jpcontents30", 255 => "Nacontents25", 256 => "Nacontents26", 257 => "Nacontents27", 258 => "Nacontents28", 259 => "Nacontents29", 260 => "Nacontents30", 261 => "Nacontents31", 262 => "Nacontents32", 263 => "Nacontents33", 264 => "Nacontents34", 265 => "Jpcontents31", 266 => "Jpcontents32", 267 => "Jpcontents33", 268 => "Jpcontents34", 269 => "Jpcontents35", 270 => "Jpcontents36", 271 => "Nacontents36", 272 => "Nacontents37", 273 => "Nacontents38", 274 => "Nacontents39", 275 => "Nacontents40", 276 => "Nacontents41", 277 => "Nacontents42", 278 => "Nacontents43", 279 => "Nacontents44", 280 => "Nacontents45", 576 => "h-collaris", 577 => "h-metallica", 578 => "h-contents", 579 => "h-contents2", 580 => "h-cauta", 581 => "h-contents3", 582 => "h-picatus", 583 => "h-contents4", 584 => "h-sordidus", 585 => "h-canente", 586 => "h-contents5", 630 => "a-contents3", 631 => "a-contents4", 632 => "a-contents5", 633 => "a-contents6", 634 => "a-contents7", 635 => "a-contents8", 636 => "a-contents9", 637 => "a-contents10", 638 => "a-contents20", 640 => "a-public1", 641 => "a-public2", 642 => "a-public3", 643 => "a-public4", 644 => "a-public5", 645 => "a-public6", 646 => "a-public7", 647 => "a-public8", 648 => "a-public9", 649 => "a-public10", 650 => "a-public11", 651 => "a-public12", 652 => "a-public13", 653 => "a-public14", 654 => "a-public15", 655 => "a-public16", 656 => "a-public17", 657 => "a-public18", 1024 => "test1", 1025 => "test2", 1040 => "DiPingGuan", 1041 => "MiWuShiDi", 1042 => "LaNuoXiYa", 1043 => "ZiShuiZhanQiao", 1044 => "HuanYingQunDao", 1045 => "MoDuNa", 1046 => "MoShouLingYu", 1047 => "FengMoDong", 1048 => "TaiyangHaiAn", 1049 => "XiaoMaiJiuGang", 1050 => "YinLeiHu", 1051 => "ShengXiaTan", 1052 => "PuTaoJiuGang", 1053 => "HeiYiSenLin", 1054 => "QingLinQuan", 1055 => "JinChuiTaiDi", 1056 => "HongChaChuan", 1057 => "YiXiuJiaDe", 1058 => "XueSongYuan", 1059 => "YaoJingLing", 1060 => "MengYaChi", 1061 => "ZhiZhangXiaGu", 1062 => "MiYueZhiTa", 1063 => "MoLaBiWan", 1064 => "YueYaWan", 1065 => "YaoLanShu", 1066 => "QiaoMingDong", 1067 => "NiMuHe", 1068 => "HuangJinGu", 1069 => "BaiLingTi", 1070 => "TianLangXingDengTa", 1071 => "ZhuoReZouLang", 1072 => "SiYuJuMu", 1073 => "YueYingDao", 1074 => "ShuiJingTa", 1075 => "MengXiangGong", 1076 => "BaiJinHuanXiang", 1077 => "HeiJinHu", 1078 => "LongXiPuBu", 1079 => "ShiWeiTa", 1080 => "TongLingTongShan", 1081 => "ShenYiZhiDi", 1082 => "ShiJiuDaQiao", 1083 => "YongHengChuan", 1084 => "HaiWuShaTan", 1085 => "HeFengLiuDi", 1086 => "ZeMeiErYaoSai", 1087 => "JuShiQiu", 1088 => "JianDouLingYu", 1089 => "HeiChenYiZhan", 1090 => "ShuiLianYan", 1091 => "LingHangMingDeng", 1092 => "HaiCiShiKu", 1093 => "FeiCuiHu", 1094 => "XiongXinGuangChang", 1095 => "KuErZhaSi", 1096 => "LiuShaMiGong", 1097 => "FangXiangTang", 1098 => "HuaMiZhanQiao", 1099 => "LanWuYongQuan", 1100 => "ShenLingShengYu", 1101 => "BaiYunYa", 1102 => "HaiJiangShuiQu", 1103 => "YuanLingYouShu", 1104 => "ShaZhongLuTing", 1105 => "JieMeiQiu", 1106 => "JingYuZhuangYuan", 1107 => "ZuJiGu", 1108 => "ShanHuTa", 1109 => "HengDuanYa", 1110 => "ShuiShangTingYuan", 1111 => "WuXianHuiLang", 1112 => "JinDingChi", 1113 => "LvRenZhanQiao", 1114 => "LongWenYan", 1115 => "HaiManQiaoLang", 1116 => "YuanQuanZhiTi", 1117 => "MiShiTa", 1118 => "RiShengMen", 1119 => "XiFengJia", 1120 => "ShenLiZhiMen", 1121 => "FuXiaoZhiJian", 1122 => "HaiLangDong", 1123 => "XiangShuYuan", 1124 => "MoNvKaFeiGuan", 1125 => "JuLongShouYingDi", 1126 => "DiYuHeGu", 1127 => "FuRongYuanZhuo", 1128 => "ShenWoJiao", 1129 => "HuangJinGuangChang", 1130 => "WanZhiMuChang", 1131 => "QiMuQuan", 1132 => "JingChiZhanQiao", 1133 => "BaiOuTA", 1134 => "XiaoShiWangDu", 1135 => "KuaTianQiao", 1136 => "ShengRenLei", 1137 => "JianFeng", 1138 => "HouWeiTa", 1139 => "BaiYinJiShi", 1140 => "LaiShengHuiLang", 1141 => "BaoFengLuMen", 1142 => "YouLingHu", 1143 => "ShiLvHu", 1144 => "HuangHunWan", 1145 => "XiaoALaMiGe", 1146 => "FangLangShenLiTang", 1147 => "JingJiSen", 1148 => "LangYanQiu", 1149 => "ShengRenLvDao", 1150 => "BuHuiZhanQuan", 1151 => "JiuTeng", 1152 => "RongYaoXi", 1153 => "JingShu", 1154 => "YuMenYiXue", 1155 => "YiWangLvZhou", 1156 => "YanDiLing", 1157 => "GeYongLieGu", 1158 => "LiuShaWu", 1159 => "BaJianShiQianTing", 1160 => "Bahamute", 1161 => "Zhushenhuanghun", 1162 => "Wangzhezhijian", 1163 => "Luxingniao", 1164 => "Shenshengcaipansuo", 1165 => "Bingtiangong", 1166 => "Longchaoshendian", 1167 => "HongYuHai", 1168 => "HuangJinGang", 1169 => "YanXia", 1170 => "ChaoFengTing", 1171 => "ShenQuanHen", 1172 => "BaiYinXiang", 1173 => "YuZhouHeYin", 1174 => "WoXianXiRan", 1175 => "ChenXiWangZuo", 1176 => "MengYuBaoJing", 1177 => "HaiMaoChaWu", 1178 => "RouFengHaiWan", 1179 => "HuPoYuan", 1536 => "contentstest1", 1537 => "contentstest2", 1552 => "sdocontents1", 1553 => "sdocontents2", 1554 => "sdocontents3", 1555 => "sdocontents4", 1556 => "sdocontents5", 1557 => "sdocontents6", 1558 => "sdocontents7", 1559 => "sdocontents8", 1560 => "sdocontents9", 1561 => "sdocontents10", 1562 => "sdocontents11", 1563 => "sdocontents12", 1564 => "sdocontents13", 1565 => "sdocontents14", 1566 => "sdocontents15", 1567 => "sdocontents16", 1568 => "sdocontents17", 1569 => "sdocontents18", 1570 => "sdocontents19", 1571 => "sdocontents20", 1572 => "sdocontents21", 1573 => "sdocontents22", 1574 => "sdocontents23", 1575 => "sdocontents24", 1576 => "sdocontents25", 1577 => "sdocontents26", 1578 => "sdocontents27", 1579 => "sdocontents28", 1580 => "sdocontents29", 1581 => "sdocontents30", 1582 => "sdocontents31", 1583 => "sdocontents32", 1584 => "sdocontents33", 1585 => "sdocontents34", 1586 => "sdocontents35", 1587 => "sdocontents36", 1588 => "sdocontents37", 1589 => "sdocontents38", 1590 => "sdocontents39", 1591 => "sdocontents40", 1592 => "sdocontents41", 1593 => "sdocontents42", 1594 => "sdocontents43", 1595 => "sdocontents44", 1596 => "sdocontents45", 1597 => "sdocontents46", 1598 => "sdocontents47", 1599 => "sdocontents48", 1600 => "sdocontents49", 1601 => "sdocontents50", 1602 => "sdocontents51", 1603 => "sdocontents52", 1604 => "sdocontents53", 1605 => "sdocontents54", 1606 => "sdocontents55", 1607 => "sdocontents56", 1608 => "sdocontents57", 1609 => "sdocontents58", 1610 => "sdocontents59", 1611 => "sdocontents60", 1612 => "sdocontents61", 1613 => "sdocontents62", 1614 => "sdocontents63", 1615 => "sdocontents64", 1616 => "sdocontents65", 1617 => "sdocontents66", 1618 => "sdocontents67", 1619 => "sdocontents68", 1620 => "sdocontents69", 1621 => "sdocontents70", 1622 => "sdocontents71", 1623 => "sdocontents72", 1624 => "sdocontents73", 1625 => "sdocontents74", 1626 => "sdocontents75", 1627 => "sdocontents76", 1628 => "sdocontents77", 1629 => "sdocontents78", 1630 => "sdocontents79", 1631 => "sdocontents80", 1632 => "sdocontents81", 1633 => "sdocontents82", 1634 => "sdocontents83", 1635 => "sdocontents84", 1636 => "sdocontents85", 1637 => "sdocontents86", 1638 => "sdocontents87", 1639 => "sdocontents88", 1640 => "sdocontents89", 1641 => "sdocontents90", 1642 => "sdocontents91", 1643 => "sdocontents92", 1644 => "sdocontents93", 1645 => "sdocontents94", 1646 => "sdocontents95", 1647 => "sdocontents96", 1648 => "sdocontents97", 1649 => "sdocontents98", 1650 => "sdocontents99", 1651 => "sdocontents100", 1652 => "sdocontents101", 1653 => "sdocontents102", 1654 => "sdocontents103", 1655 => "sdocontents104", 1656 => "sdocontents105", 1657 => "sdocontents106", 1658 => "sdocontents107", 1659 => "sdocontents108", 1660 => "sdocontents109", 1661 => "sdocontents110", 1662 => "sdocontents111", 1663 => "sdocontents112", 1664 => "sdocontents113", 1665 => "sdocontents114", 1666 => "sdocontents115", 1667 => "sdocontents116", 1668 => "sdocontents117", 1669 => "sdocontents118", 1670 => "sdocontents119", 1671 => "sdocontents120", 2048 => "Unei", 2049 => "Doga", 2050 => "KrBahamut", 2051 => "KrIfrit", 2052 => "KrGaruda", 2053 => "KrRamuh", 2054 => "KrOdin", 2055 => "KrUltima", 2056 => "KrMandragora", 2057 => "KrTonberry2", 2058 => "KrExcalibur", 2059 => "KrPhoenix", 2060 => "KrAlexander", 2061 => "KrTitan", 2062 => "KrLeviathan", 2063 => "KrShiva", 2064 => "KrBehemoth", 2065 => "KrGilgamesh", 2066 => "KrSabotender", 2067 => "KrUnicorn", 2068 => "KrRagnarok", 2069 => "KrRamia", 2070 => "KrNewPublic1", 2071 => "KrNewPublic2", 2072 => "KrNewPublic3", 2073 => "KrNewPublic4", 2074 => "KrNewPublic5", 2075 => "KrCarbuncle", 2076 => "KrChocobo", 2077 => "KrMoogle", 2078 => "KrTonberry", 2079 => "KrCaitsith", 2560 => "koreacontents1", 2561 => "koreacontents2", 2562 => "krcontents1", 2563 => "krcontents2", 2564 => "krcontents3", 2565 => "krcontents4", 2566 => "krcontents5", 2567 => "krcontents6", 2568 => "krcontents7", 2569 => "krcontents8", 2570 => "krcontents9", 2571 => "krcontents10", 2572 => "krcontents11", 2573 => "krcontents12", 2574 => "krcontents13", 2575 => "krcontents14", 2576 => "krcontents15", 2577 => "krcontents16", 2578 => "krcontents17", 2579 => "krcontents18", 2580 => "krcontents19", 2581 => "krcontents20", 2582 => "krcontents21", 2583 => "krcontents22", 10000 => "crossworld_range", 10001 => "crossworld", 10002 => "crossworld", 10003 => "crossworld", 10004 => "crossworld", 10005 => "crossworld", 10006 => "crossworld", 10007 => "crossworld", 10008 => "crossworld", 10009 => "crossworld", 10010 => "crossworld", 65534 => "outofrange1", 65535 => "outofrange2", _ => null, }; } public static bool ContainsIgnoreCase(this string haystack, string needle) { return CultureInfo.InvariantCulture.CompareInfo.IndexOf(haystack, needle, CompareOptions.IgnoreCase) >= 0; } public static bool IsValidRegex(this string regex) { try { _ = new Regex(regex); return true; } catch (ArgumentException) { return false; } } public static bool IsValidRegex(this string regex, out ArgumentException exception) { try { _ = new Regex(regex); exception = default!; return true; } catch (ArgumentException ex) { exception = ex; return false; } } } public class RegexValidator : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { if (!(value is string text)) { return new ValidationResult(false, "Value is not text."); } return text.IsValidRegex(out var ex) ? ValidationResult.ValidResult : new ValidationResult(false, $"Invalid regular expression: {ex.Message}"); } } public class StringWrapper : INotifyPropertyChanged { private string value; public String Value { get => this.value; set { this.value = value; this.OnPropertyChanged(nameof(this.Value)); } } public StringWrapper(string value) { this.value = value; } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged([CallerMemberName] string? propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }