feat: add sanitizer

This commit is contained in:
kalilistic 2021-04-04 09:20:07 -04:00
parent 09e651b3ab
commit 4504bb049f
6 changed files with 230 additions and 1 deletions

View file

@ -43,6 +43,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="LocalizationTests.cs" /> <Compile Include="LocalizationTests.cs" />
<Compile Include="Plugin\Sanitizer\SanitizerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -0,0 +1,67 @@
// ReSharper disable StringLiteralTypo
using System.Linq;
using NUnit.Framework;
namespace Dalamud.Test.Plugin.Sanitizer {
[TestFixture]
public class SanitizerTests {
global::Dalamud.Plugin.Sanitizer.Sanitizer sanitizer;
[Test]
public void Sanitize_NormalString_NoChange() {
sanitizer = new global::Dalamud.Plugin.Sanitizer.Sanitizer(ClientLanguage.English);
const string str = "Pixie Cotton Hood of Healing";
var sanitizedString = sanitizer.Sanitize(str);
Assert.AreEqual(str, sanitizedString);
}
[Test]
public void Sanitize_DESpecialCharacters_Sanitized() {
sanitizer = new global::Dalamud.Plugin.Sanitizer.Sanitizer(ClientLanguage.German);
const string str = @"Anemos-Panzerhandschuhe des Drachenbluts";
var sanitizedString = sanitizer.Sanitize(str);
Assert.AreEqual(@"Anemos-Panzerhandschuhe des Drachenbluts", sanitizedString);
}
[Test]
public void Sanitize_FRSpecialCharacters_Sanitized() {
sanitizer = new global::Dalamud.Plugin.Sanitizer.Sanitizer(ClientLanguage.French);
const string str = @"Le Diademe: terrains de chasse|Le Diademe: terrains de chasse";
var sanitizedString = sanitizer.Sanitize(str);
Assert.AreEqual(@"Le Diademe: terrains de chasse|Le Diademe: terrains de chasse", sanitizedString);
}
[Test]
public void Sanitize_SpecifyLanguage_Sanitized() {
sanitizer = new global::Dalamud.Plugin.Sanitizer.Sanitizer(ClientLanguage.French);
const string str = @"Le Diademe: terrains de chasse|Le Diademe: terrains de chasse";
var sanitizedString = sanitizer.Sanitize(str, ClientLanguage.French);
Assert.AreEqual(@"Le Diademe: terrains de chasse|Le Diademe: terrains de chasse", sanitizedString);
}
[Test]
public void Sanitize_List_Sanitized() {
sanitizer = new global::Dalamud.Plugin.Sanitizer.Sanitizer(ClientLanguage.German);
const string str = @"Anemos-Panzerhandschuhe des Drachenbluts";
var sanitizedStrings = sanitizer.Sanitize(new[] {str});
Assert.AreEqual(@"Anemos-Panzerhandschuhe des Drachenbluts", sanitizedStrings.First());
}
[Test]
public void Sanitize_SpecifyLanguageList_Sanitized() {
sanitizer = new global::Dalamud.Plugin.Sanitizer.Sanitizer(ClientLanguage.German);
const string str = @"Anemos-Panzerhandschuhe des Drachenbluts";
var sanitizedStrings = sanitizer.Sanitize(new[] {str}, ClientLanguage.German);
Assert.AreEqual(@"Anemos-Panzerhandschuhe des Drachenbluts", sanitizedStrings.First());
}
[Test]
public void Sanitize_UseAlternateLanguage_Sanitized() {
sanitizer = new global::Dalamud.Plugin.Sanitizer.Sanitizer(ClientLanguage.English);
const string str = @"Anemos-Panzerhandschuhe des Drachenbluts";
var sanitizedStrings = sanitizer.Sanitize(new[] {str}, ClientLanguage.German);
Assert.AreEqual(@"Anemos-Panzerhandschuhe des Drachenbluts", sanitizedStrings.First());
}
}
}

View file

@ -47,4 +47,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EFormat_002ESettingsUpgrade_002EAlignmentTabFillStyleMigration/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EFormat_002ESettingsUpgrade_002EAlignmentTabFillStyleMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dalamud/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/UserDictionary/Words/=Dalamud/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unsanitized/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -13,6 +13,7 @@ using Dalamud.Game.ClientState;
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Game.Internal; using Dalamud.Game.Internal;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Plugin.Sanitizer;
namespace Dalamud.Plugin namespace Dalamud.Plugin
{ {
@ -48,6 +49,7 @@ namespace Dalamud.Plugin
this.pluginName = pluginName; this.pluginName = pluginName;
this.configs = configs; this.configs = configs;
this.Sanitizer = new Sanitizer.Sanitizer(this.Data.Language);
this.UiLanguage = this.dalamud.Configuration.LanguageOverride; this.UiLanguage = this.dalamud.Configuration.LanguageOverride;
dalamud.LocalizationManager.OnLocalizationChanged += this.OnLocalizationChanged; dalamud.LocalizationManager.OnLocalizationChanged += this.OnLocalizationChanged;
} }
@ -132,6 +134,11 @@ namespace Dalamud.Plugin
/// </summary> /// </summary>
public string UiLanguage { get; private set; } public string UiLanguage { get; private set; }
/// <summary>
/// Gets serializer class with functions to remove special characters from strings.
/// </summary>
public ISanitizer Sanitizer { get; }
/// <summary> /// <summary>
/// Gets the action that should be executed when any plugin sends a message. /// Gets the action that should be executed when any plugin sends a message.
/// </summary> /// </summary>

View file

@ -0,0 +1,40 @@
using System.Collections.Generic;
namespace Dalamud.Plugin.Sanitizer
{
/// <summary>
/// Sanitize strings to remove soft hyphens and other special characters.
/// </summary>
public interface ISanitizer
{
/// <summary>
/// Creates a sanitized string using current clientLanguage.
/// </summary>
/// <param name="unsanitizedString">An unsanitized string to sanitize.</param>
/// <returns>A sanitized string.</returns>
string Sanitize(string unsanitizedString);
/// <summary>
/// Creates a sanitized string using request clientLanguage.
/// </summary>
/// <param name="unsanitizedString">An unsanitized string to sanitize.</param>
/// <param name="clientLanguage">Target language for sanitized strings.</param>
/// <returns>A sanitized string.</returns>
string Sanitize(string unsanitizedString, ClientLanguage clientLanguage);
/// <summary>
/// Creates a list of sanitized strings using current clientLanguage.
/// </summary>
/// <param name="unsanitizedStrings">List of unsanitized string to sanitize.</param>
/// <returns>A list of sanitized strings.</returns>
IEnumerable<string> Sanitize(IEnumerable<string> unsanitizedStrings);
/// <summary>
/// Creates a list of sanitized strings using requested clientLanguage.
/// </summary>
/// <param name="unsanitizedStrings">List of unsanitized string to sanitize.</param>
/// <param name="clientLanguage">Target language for sanitized strings.</param>
/// <returns>A list of sanitized strings.</returns>
IEnumerable<string> Sanitize(IEnumerable<string> unsanitizedStrings, ClientLanguage clientLanguage);
}
}

View file

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Dalamud.Plugin.Sanitizer
{
/// <summary>
/// Sanitize strings to remove soft hyphens and other special characters.
/// </summary>
public class Sanitizer : ISanitizer
{
private readonly KeyValuePair<string, string> softHyphen = new KeyValuePair<string, string>("\u0002\u0016\u0001\u0003", string.Empty);
private readonly KeyValuePair<string, string> emphasisOpen = new KeyValuePair<string, string>("\u0002\u001A\u0003", string.Empty);
private readonly KeyValuePair<string, string> emphasisClose = new KeyValuePair<string, string>("\u0002\u001A\u0001\u0003", string.Empty);
private readonly KeyValuePair<string, string> indent = new KeyValuePair<string, string>("\u0002\u001D\u0001\u0003", string.Empty);
private readonly KeyValuePair<string, string> dagger = new KeyValuePair<string, string>("\u0020\u2020", string.Empty);
private readonly KeyValuePair<string, string> ligatureOE = new KeyValuePair<string, string>("\u0153", "\u006F\u0065");
private readonly List<KeyValuePair<string, string>> defaultSanitizationList;
/// <summary>
/// Initializes a new instance of the <see cref="Sanitizer"/> class.
/// </summary>
/// <param name="clientLanguage">Default clientLanguage for sanitizing strings.</param>
public Sanitizer(ClientLanguage clientLanguage)
{
this.defaultSanitizationList = this.BuildSanitizationList(clientLanguage);
}
/// <summary>
/// Creates a sanitized string using current clientLanguage.
/// </summary>
/// <param name="unsanitizedString">An unsanitized string to sanitize.</param>
/// <returns>A sanitized string.</returns>
public string Sanitize(string unsanitizedString)
{
return this.defaultSanitizationList == null ? unsanitizedString : ApplySanitizationList(unsanitizedString, this.defaultSanitizationList);
}
/// <summary>
/// Creates a sanitized string using request clientLanguage.
/// </summary>
/// <param name="unsanitizedString">An unsanitized string to sanitize.</param>
/// <param name="clientLanguage">Target language for sanitized strings.</param>
/// <returns>A sanitized string.</returns>
public string Sanitize(string unsanitizedString, ClientLanguage clientLanguage)
{
var newSanitizationList = this.BuildSanitizationList(clientLanguage);
return newSanitizationList == null ? unsanitizedString : ApplySanitizationList(unsanitizedString, newSanitizationList);
}
/// <summary>
/// Creates a list of sanitized strings using current clientLanguage.
/// </summary>
/// <param name="unsanitizedStrings">List of unsanitized string to sanitize.</param>
/// <returns>A list of sanitized strings.</returns>
public IEnumerable<string> Sanitize(IEnumerable<string> unsanitizedStrings)
{
return this.defaultSanitizationList == null ? unsanitizedStrings.Select(unsanitizedString => unsanitizedString) :
unsanitizedStrings.Select(unsanitizedString => ApplySanitizationList(unsanitizedString, this.defaultSanitizationList));
}
/// <summary>
/// Creates a list of sanitized strings using requested clientLanguage.
/// </summary>
/// <param name="unsanitizedStrings">List of unsanitized string to sanitize.</param>
/// <param name="clientLanguage">Target language for sanitized strings.</param>
/// <returns>A list of sanitized strings.</returns>
public IEnumerable<string> Sanitize(IEnumerable<string> unsanitizedStrings, ClientLanguage clientLanguage)
{
var newSanitizationList = this.BuildSanitizationList(clientLanguage);
return newSanitizationList == null ? unsanitizedStrings.Select(unsanitizedString => unsanitizedString) :
unsanitizedStrings.Select(unsanitizedString => ApplySanitizationList(unsanitizedString, newSanitizationList));
}
private static string ApplySanitizationList(string unsanitizedString, IEnumerable<KeyValuePair<string, string>> sanitizationList)
{
var sanitizedValue = new StringBuilder(unsanitizedString);
foreach (var item in sanitizationList) sanitizedValue.Replace(item.Key, item.Value);
return sanitizedValue.ToString();
}
private List<KeyValuePair<string, string>> BuildSanitizationList(ClientLanguage clientLanguage)
{
switch (clientLanguage)
{
case ClientLanguage.Japanese:
break;
case ClientLanguage.English:
break;
case ClientLanguage.German:
return new List<KeyValuePair<string, string>>
{
this.softHyphen,
this.emphasisOpen,
this.emphasisClose,
this.dagger,
};
case ClientLanguage.French:
return new List<KeyValuePair<string, string>>
{
this.softHyphen,
this.indent,
this.ligatureOE,
};
default:
throw new ArgumentOutOfRangeException();
}
return null;
}
}
}