mirror of
https://github.com/AdAstra-LD/DS-Pokemon-Rom-Editor.git
synced 2026-05-13 15:36:14 -05:00
add custom charmap system and an editor to easily add and remove aliases
This commit is contained in:
parent
f2633f184f
commit
4f910ca841
|
|
@ -344,6 +344,13 @@
|
|||
<Compile Include="ReopenProjectConfirmation.Designer.cs">
|
||||
<DependentUpon>ReopenProjectConfirmation.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Resources\CharMaps\CharMapManager.cs" />
|
||||
<Compile Include="Resources\CharMaps\CharMapManagerForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Resources\CharMaps\CharMapManagerForm.Designer.cs">
|
||||
<DependentUpon>CharMapManagerForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Resources\CustomScrcmdManager.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
|
@ -626,6 +633,9 @@
|
|||
<EmbeddedResource Include="ReopenProjectConfirmation.resx">
|
||||
<DependentUpon>ReopenProjectConfirmation.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\CharMaps\CharMapManagerForm.resx">
|
||||
<DependentUpon>CharMapManagerForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\CustomScrcmdManager.resx">
|
||||
<DependentUpon>CustomScrcmdManager.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
|
|||
|
|
@ -4,93 +4,13 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml.Linq;
|
||||
using DSPRE.CharMaps;
|
||||
|
||||
namespace DSPRE
|
||||
{
|
||||
internal class TextConverter
|
||||
{
|
||||
|
||||
private static Dictionary<ushort, string> decodeMap;
|
||||
private static Dictionary<string, ushort> encodeMap;
|
||||
private static Dictionary<ushort, string> commandMap;
|
||||
|
||||
private static bool mapsInitialized = false;
|
||||
|
||||
public static Dictionary<ushort, string> GetDecodingMap()
|
||||
{
|
||||
if (!mapsInitialized)
|
||||
{
|
||||
InitializeCharMaps();
|
||||
}
|
||||
return decodeMap;
|
||||
}
|
||||
|
||||
public static Dictionary<string, ushort> GetEncodingMap()
|
||||
{
|
||||
if (!mapsInitialized)
|
||||
{
|
||||
InitializeCharMaps();
|
||||
}
|
||||
return encodeMap;
|
||||
}
|
||||
|
||||
private static void InitializeCharMaps()
|
||||
{
|
||||
decodeMap = new Dictionary<ushort, string>();
|
||||
encodeMap = new Dictionary<string, ushort>();
|
||||
commandMap = new Dictionary<ushort, string>();
|
||||
|
||||
string charmapPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tools", "charmap.xml");
|
||||
if (!File.Exists(charmapPath))
|
||||
throw new FileNotFoundException("Charmap XML file not found.", charmapPath);
|
||||
|
||||
var xml = XDocument.Load(charmapPath, LoadOptions.PreserveWhitespace);
|
||||
|
||||
foreach (var entry in xml.Descendants("entry"))
|
||||
{
|
||||
var code = entry.Attribute("code")?.Value;
|
||||
var kind = entry.Attribute("kind")?.Value;
|
||||
var value = entry.Value;
|
||||
|
||||
if (code == null || kind == null || value == null)
|
||||
{
|
||||
AppLogger.Error("Found charmap entry with null value.");
|
||||
continue;
|
||||
}
|
||||
|
||||
ushort codeValue;
|
||||
string codeKind = kind.ToLower();
|
||||
string chars = value.ToString();
|
||||
|
||||
if (!ushort.TryParse(code, System.Globalization.NumberStyles.HexNumber, null, out codeValue))
|
||||
{
|
||||
AppLogger.Error($"Invalid code value in charmap: {code}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (codeKind == "char" || codeKind == "escape")
|
||||
{
|
||||
decodeMap[codeValue] = chars;
|
||||
encodeMap[chars] = codeValue;
|
||||
}
|
||||
else if (codeKind == "alias")
|
||||
{
|
||||
encodeMap[chars] = codeValue;
|
||||
}
|
||||
else if (codeKind == "command")
|
||||
{
|
||||
commandMap[codeValue] = chars;
|
||||
}
|
||||
else
|
||||
{
|
||||
AppLogger.Error($"Unknown kind '{kind}' in charmap entry.");
|
||||
}
|
||||
}
|
||||
|
||||
mapsInitialized = true;
|
||||
}
|
||||
|
||||
public static List<string> ReadMessageFromStream(Stream stream, out UInt16 key)
|
||||
{
|
||||
List<string> messages = new List<string>();
|
||||
|
|
@ -248,9 +168,9 @@ namespace DSPRE
|
|||
{
|
||||
ushort code = message[i];
|
||||
// Regular characters and escape sequences
|
||||
if (GetDecodingMap().ContainsKey(code))
|
||||
if (CharMapManager.GetDecodingMap().ContainsKey(code))
|
||||
{
|
||||
decodedMessage.Append(GetDecodingMap()[code]);
|
||||
decodedMessage.Append(CharMapManager.GetDecodingMap()[code]);
|
||||
i++;
|
||||
}
|
||||
// Commands
|
||||
|
|
@ -294,9 +214,9 @@ namespace DSPRE
|
|||
while (i < message.Length)
|
||||
{
|
||||
// Regular characters
|
||||
if (GetEncodingMap().ContainsKey(message[i].ToString()))
|
||||
if (CharMapManager.GetEncodingMap().ContainsKey(message[i].ToString()))
|
||||
{
|
||||
encodedMessage.Add(GetEncodingMap()[message[i].ToString()]);
|
||||
encodedMessage.Add(CharMapManager.GetEncodingMap()[message[i].ToString()]);
|
||||
i++;
|
||||
}
|
||||
// Escape sequences
|
||||
|
|
@ -317,9 +237,9 @@ namespace DSPRE
|
|||
else if (i + 1 < message.Length)
|
||||
{
|
||||
string escapeSeq = message.Substring(i, 2);
|
||||
if (GetEncodingMap().ContainsKey(escapeSeq))
|
||||
if (CharMapManager.GetEncodingMap().ContainsKey(escapeSeq))
|
||||
{
|
||||
encodedMessage.Add(GetEncodingMap()[escapeSeq]);
|
||||
encodedMessage.Add(CharMapManager.GetEncodingMap()[escapeSeq]);
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -363,9 +283,9 @@ namespace DSPRE
|
|||
if (endIndex != -1)
|
||||
{
|
||||
string multiCharSeq = message.Substring(i, endIndex - i + 1);
|
||||
if (GetEncodingMap().ContainsKey(multiCharSeq))
|
||||
if (CharMapManager.GetEncodingMap().ContainsKey(multiCharSeq))
|
||||
{
|
||||
encodedMessage.Add(GetEncodingMap()[multiCharSeq]);
|
||||
encodedMessage.Add(CharMapManager.GetEncodingMap()[multiCharSeq]);
|
||||
i = endIndex + 1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -424,7 +344,7 @@ namespace DSPRE
|
|||
// Special case for string buffer vars that have 1 byte command ids
|
||||
int specialByte = 0;
|
||||
|
||||
if (!commandMap.ContainsKey(commandID) && commandMap.ContainsKey((ushort)(commandID & 0xFF00)))
|
||||
if (!CharMapManager.GetCommandMap().ContainsKey(commandID) && CharMapManager.GetCommandMap().ContainsKey((ushort)(commandID & 0xFF00)))
|
||||
{
|
||||
specialByte = (ushort)(commandID & 0x00FF);
|
||||
commandID = (ushort)(commandID & 0xFF00);
|
||||
|
|
@ -434,9 +354,9 @@ namespace DSPRE
|
|||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("{");
|
||||
if (commandMap.ContainsKey(commandID))
|
||||
if (CharMapManager.GetCommandMap().ContainsKey(commandID))
|
||||
{
|
||||
sb.Append($"{commandMap[commandID]}");
|
||||
sb.Append($"{CharMapManager.GetCommandMap()[commandID]}");
|
||||
sb.Append($", {specialByte}");
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
|
|
@ -492,9 +412,9 @@ namespace DSPRE
|
|||
encodedCommand.Add(0xFFFE);
|
||||
|
||||
// Get ID from name or parse hex
|
||||
if (commandMap.ContainsValue(commandName))
|
||||
if (CharMapManager.GetCommandMap().ContainsValue(commandName))
|
||||
{
|
||||
encodedCommand.Add(commandMap.Reverse()[commandName]);
|
||||
encodedCommand.Add(CharMapManager.GetCommandMap().Reverse()[commandName]);
|
||||
}
|
||||
else if (ushort.TryParse(commandName, out ushort commandID))
|
||||
{
|
||||
|
|
@ -564,9 +484,9 @@ namespace DSPRE
|
|||
if (curChar == 0x1FF)
|
||||
break;
|
||||
|
||||
if (GetDecodingMap().ContainsKey(curChar))
|
||||
if (CharMapManager.GetDecodingMap().ContainsKey(curChar))
|
||||
{
|
||||
decoded.Append(GetDecodingMap()[curChar]);
|
||||
decoded.Append(CharMapManager.GetDecodingMap()[curChar]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -589,9 +509,9 @@ namespace DSPRE
|
|||
// Get list of characters to encode
|
||||
foreach (char c in nameContent)
|
||||
{
|
||||
if (GetEncodingMap().ContainsKey(c.ToString()))
|
||||
if (CharMapManager.GetEncodingMap().ContainsKey(c.ToString()))
|
||||
{
|
||||
var code = GetEncodingMap()[c.ToString()];
|
||||
var code = CharMapManager.GetEncodingMap()[c.ToString()];
|
||||
|
||||
// Ensure code fits in 9 bits
|
||||
if (code >> 9 != 0)
|
||||
|
|
|
|||
38
DS_Map/Main Window.Designer.cs
generated
38
DS_Map/Main Window.Designer.cs
generated
|
|
@ -132,8 +132,8 @@
|
|||
this.wildEditorButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.pokemonEditorButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.moveEditorButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.tradeEditorButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.itemEditorButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.tradeEditorButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.separator_afterEditors = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.scriptCommandsButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.romToolboxToolStripButton = new System.Windows.Forms.ToolStripButton();
|
||||
|
|
@ -152,6 +152,7 @@
|
|||
this.weatherMapEditor = new System.Windows.Forms.ToolStripButton();
|
||||
this.versionLabel = new System.Windows.Forms.Label();
|
||||
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.openCharmapManagerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mainTabControl.SuspendLayout();
|
||||
this.headerEditorTabPage.SuspendLayout();
|
||||
this.matrixEditorTabPage.SuspendLayout();
|
||||
|
|
@ -716,6 +717,7 @@
|
|||
this.listBasedBatchRenameToolStripMenuItem,
|
||||
this.listBuilderToolStripMenuItem,
|
||||
this.nSBMDUtilityToolStripMenuItem,
|
||||
this.openCharmapManagerToolStripMenuItem,
|
||||
this.generateCSVToolStripMenuItem});
|
||||
this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
|
||||
this.aboutToolStripMenuItem.Size = new System.Drawing.Size(46, 20);
|
||||
|
|
@ -1263,19 +1265,6 @@
|
|||
this.moveEditorButton.Text = "Move Editor";
|
||||
this.moveEditorButton.Click += new System.EventHandler(this.moveEditorToolStripMenuItem_Click);
|
||||
//
|
||||
// tradeEditorButton
|
||||
//
|
||||
this.tradeEditorButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
|
||||
this.tradeEditorButton.Enabled = false;
|
||||
this.tradeEditorButton.Image = global::DSPRE.Properties.Resources.trade_editor_icon;
|
||||
this.tradeEditorButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
|
||||
this.tradeEditorButton.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.tradeEditorButton.Margin = new System.Windows.Forms.Padding(4, 6, 0, 2);
|
||||
this.tradeEditorButton.Name = "tradeEditorButton";
|
||||
this.tradeEditorButton.Size = new System.Drawing.Size(36, 36);
|
||||
this.tradeEditorButton.Text = "Trade Editor";
|
||||
this.tradeEditorButton.Click += new System.EventHandler(this.tradeEditorToolStripMenuItem_Click);
|
||||
//
|
||||
// itemEditorButton
|
||||
//
|
||||
this.itemEditorButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
|
||||
|
|
@ -1289,6 +1278,19 @@
|
|||
this.itemEditorButton.Text = "Item Editor";
|
||||
this.itemEditorButton.Click += new System.EventHandler(this.itemEditorToolStripMenuItem_Click);
|
||||
//
|
||||
// tradeEditorButton
|
||||
//
|
||||
this.tradeEditorButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
|
||||
this.tradeEditorButton.Enabled = false;
|
||||
this.tradeEditorButton.Image = global::DSPRE.Properties.Resources.trade_editor_icon;
|
||||
this.tradeEditorButton.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None;
|
||||
this.tradeEditorButton.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.tradeEditorButton.Margin = new System.Windows.Forms.Padding(4, 6, 0, 2);
|
||||
this.tradeEditorButton.Name = "tradeEditorButton";
|
||||
this.tradeEditorButton.Size = new System.Drawing.Size(36, 36);
|
||||
this.tradeEditorButton.Text = "Trade Editor";
|
||||
this.tradeEditorButton.Click += new System.EventHandler(this.tradeEditorToolStripMenuItem_Click);
|
||||
//
|
||||
// separator_afterEditors
|
||||
//
|
||||
this.separator_afterEditors.Name = "separator_afterEditors";
|
||||
|
|
@ -1457,6 +1459,13 @@
|
|||
this.versionLabel.Text = "ROM:";
|
||||
this.versionLabel.Visible = false;
|
||||
//
|
||||
// openCharmapManagerToolStripMenuItem
|
||||
//
|
||||
this.openCharmapManagerToolStripMenuItem.Name = "openCharmapManagerToolStripMenuItem";
|
||||
this.openCharmapManagerToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
|
||||
this.openCharmapManagerToolStripMenuItem.Text = "Open Charmap Manager";
|
||||
this.openCharmapManagerToolStripMenuItem.Click += new System.EventHandler(this.openCharmapManagerToolStripMenuItem_Click);
|
||||
//
|
||||
// MainProgram
|
||||
//
|
||||
this.AllowDrop = true;
|
||||
|
|
@ -1676,6 +1685,7 @@
|
|||
private System.Windows.Forms.ToolStripSeparator separator_afterEditors;
|
||||
private System.Windows.Forms.ToolStripButton itemEditorButton;
|
||||
private System.Windows.Forms.ToolStripButton tradeEditorButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem openCharmapManagerToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1908,6 +1908,12 @@ namespace DSPRE
|
|||
}
|
||||
}
|
||||
|
||||
private void openCharmapManagerToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
CharMaps.CharMapManagerForm charMapManager = new CharMaps.CharMapManagerForm();
|
||||
charMapManager.ShowDialog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,87 +124,87 @@
|
|||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
|
||||
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
|
||||
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACM
|
||||
EgAAAk1TRnQBSQFMAgEBCgEAAfgBHgH4AR4BEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
|
||||
AwABQAMAATADAAEBAQABCAYAAQwYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
|
||||
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
|
||||
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
|
||||
AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm
|
||||
AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM
|
||||
AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA
|
||||
ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz
|
||||
AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ
|
||||
AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM
|
||||
AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA
|
||||
AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA
|
||||
AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ
|
||||
AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/
|
||||
AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA
|
||||
AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm
|
||||
ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ
|
||||
Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz
|
||||
AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA
|
||||
AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM
|
||||
AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM
|
||||
ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM
|
||||
Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA
|
||||
AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM
|
||||
AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ
|
||||
AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz
|
||||
AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm
|
||||
AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw
|
||||
AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD/xMABLwEAAS8KwAGvAIA
|
||||
BOkBvAMABOkBvCoAASYBHgQAArwBAATpBAAE6QG8KgABJgEeAgABJgEeAQABvAEAAukBvAIABLwBAALp
|
||||
AbwtAAG8ASYBHgMAAukBvAEABAsCvALpAbwsAAEmAR4CAAG8AgAC6QG8AgsBvAEAAgsBvALpAbwmAAO8
|
||||
AgABJgEeAgABvAMAAukBvAILArwCCwEAAukBvCUAAc0BCgEAAbwBAAEmAR4BAAHsAwABvAEAAukBvAUL
|
||||
AgAC6QG8JQABzQEKAQACvAEmAR4BAAESArwBAAG8AQAC6QG8AgsCvAMAAukBvCQAAc0BCgMAAbwBAAEm
|
||||
AR4GAALpAbwBAAILA7wBAALpAbwkAAHNAQoBEgHsAQABEgG8CAAC6QG8AgADCwIAAukBvCQAAc0BCgES
|
||||
AgABEgG8CAAC6QO8BAABvALpAbwjAAHNAQoBAAG8AwABvAgABOkBvAMABOkBvAEAAbwhAAHNAQoBAAG8
|
||||
AwAB7AG8BwAE6QQABOkBGwExAZkhAAFlGwADMT0AARsBMQEbKQAB7AESAe8FAAH0EQAKEhgAAvMC6wHv
|
||||
AewB6wHzBQAB6gH0BQAC8gH0BgADEgZKAxIUAAHzAfEBvALsAQcBvAEHAewB6wEHBAABDgESAe0EAAHw
|
||||
ASIBKQHrAfMFAAESAkoGbgJKARIDAAEPBwABDwUAAQ8BAAG8AfcB7QGSAe8BvAEHAfAB9AHyAesB6gQA
|
||||
AQ4BbQHtAwABBwEjAisBKgHrAfMDAAESAUoBbgFKBm4BSgFuAUoBEgEAAQ8J7wEPAwAB7wIAAW0C9wHw
|
||||
AbwB8wLyAvQB7QHrAQcDAAEHARUB6gPtASkBKwElAR8BJQEqAesB9AIAARIBSgFuAUoGkwFKAW4BSgES
|
||||
AgAB7wEBAR8G7wMAAu8CAAG8Ae8B8QH0AfYB8gLwAfQB9gHvAewBbQMAAfQBEAHrAUoBMAEDASUBFwH5
|
||||
AiABJQEqAeoCAAESAUoBkwFuBkkBbgGTAUoBEgIAAe8CAQEfBe8BAAIPAu8CAAHyAe8C9gH3AW0B6wHy
|
||||
AfQB9gHzAesB7AEHAgAB9AEQAXMBRQEkASAB+QEXAfkBIAEfASABMQEiAfQBAAESAZMBbgFJBmwBSQFu
|
||||
AZMBEgIAAe8BAQEfBu8DAALvAwAB7wHzAbwBkgHwAfcB9gH3Ae0BBwHrAewB7wMAAfIBEQFFAR8CIAH5
|
||||
ARcB+QEgAR8BMQEiAfQBAAESAZMBSQJsBHECbAFJAZMBEgEAAQ8J7wEPAwAB7wMAAQcB8AFEASUBGgKS
|
||||
AfIC8wH0ARIB6wHyAgAB8gFDAewBRQEfASAB+QEXASYBMQE3ATABFAIAAUkBbgFsAXEBlwRxAZcBcQFs
|
||||
AW4BEgIAAQ8HAAEPBQABDwIAAfQBbQEsASUB6wH0AvEC7wHyAusBvAIAAfMBbQHrAUUBHwIgAfkBMQFR
|
||||
Am0B8wIAAUkCbAGXAnEClwJxAZcCbAFJAgABFQEPARUDAAEVAQ8BFQgAARwBLAErAeoBBwG8Au8B9AK8
|
||||
AfMCbQMAAfABEwFFAR8BJAIrAVEBvAUAAUkBbAJxBpcCcQFsAUkBAAEVAfcBBwH3ARUBAAEVAfcBBwH3
|
||||
ARUGAAHvAisBSwHvAQcBvAHxBAcB9AGLAeoDAAHwAREBSwEkASMBAwFKAfAHAAFsAXEDlwJ4A5cBcQFs
|
||||
AgABDwEHAQABBwEPAQABDwEHAQABBwEPBQAB7wErASwBRQK8AQcB7wEHAbwB8AEZAtsBbAEHAwAB8AEj
|
||||
AisBDgHwAfEIAAFJAXEClwF4BZcBcQFJAgABFQH3AQcB9wEVAQABFQH3AQcB9wEVBQABEgEsAUUB8gHz
|
||||
Ae8B8gHxAbsC2gGzAosB8wQAAfABIwE3ATEBDgsAAUkBcQKXAXgDlwFxAUkEAAEVAQ8BFQMAARUBDwEV
|
||||
BwABEgG8AgABBwGzAdQBswJsAe8IAAHvAg4B8wwAAWwBcQSXAXEBbBkAAQcCEgG8HQAEcRcAAfQL8wH0
|
||||
EwAN8xMAAQcL7wEHAgAPEAEAAQcNswEHBwAEQwcAAe8BAAG7BrMBuwIAAe8CAAEQBjgBEAbTARABAAGz
|
||||
DQABswUAAkME8AJDBQAB7wEAAbMGAAGzAgAB7wIAARACOAMAATgBEALTAgAC0wEQAQABsw0AAbMEAAFD
|
||||
CPABQwQAAe8BAAGtAQABlwJWAZcBAAGzAgAB7wIAARADOAEAAjgBEAHTAQAC0wEAAdMBEAEAAbMBAAFW
|
||||
CVABVgEAAbMDAAFDA/ABkgJDAZID8AFDAwAB7wEAAa0BAARWAQABswH0AQAB7wIAARACOAIAAjgBEAHT
|
||||
AQAC0wEAAdMBEAEAAbMBAAtWAQABswMAAUMB8AGSARIBQwHwAZIBQwESAZIB8AFDAwAB7wEAAa0BAARW
|
||||
AQABswH0AQAB7wIAARADOAEAAjgBEALTAgAC0wEQAQABswEAC1YBAAGzAgABQwHwARICYwFDAQAB8AFD
|
||||
AmMBEgHwAUMCAAHvAQABrQEABHgBAAGzAfQBAAHvAgABEAY4ARAG0wEQAQABswEAC1YBAAGzAgABQwES
|
||||
BEcCQwRHARIBQwIAAe8BAAGtBgABswHzAQAB7wIADxABAAGzAQALVgEAAbMCAAFDDEcBQwIAAe8BAAG7
|
||||
Aq0EswG7AfMBAAHvAgABEAZHARAGAAEQAQABswEAC1YBAAGzAgABQwxHAUMCAAHvAQAB8wP0AfMB9AQA
|
||||
Ae8CAAEQAkcCAAJHARAGAAEQAQABswEAC1YBAAGzAwABQwJHApQGRwFDAwAB7wEAAXQCMgEsAXQBAAG8
|
||||
AvcBAAHvAgABEAFHAQACRwEAAUcBEAYAARABAAGzAQABVgl4AVYBAAGzAwABQwFHBJQFRwFDAwAB7wEA
|
||||
ASwDwwFTAQAB9wIAAfMB8AIAARABRwEAAkcBAAFHARAGAAEQAQABswEAC3gBAAGzBAABQwSUBEcBQwQA
|
||||
Ae8BAAF0AywBdAEAAfcBAAHzAfADAAEQAkcCAAJHARAGAAEQAQABswEAC3gBAAGzBQACQwGUA0cCQwUA
|
||||
Ae8IAAHzAfAEAAEQBkcBEAYAARABAAGzDQABswcABEMHAAEHCO8BBwUADxABAAEJDbMBCREAAUIBTQE+
|
||||
BwABPgMAASgDAAFAAwABMAMAAQEBAAEBBQABgAEBFgAD/wEAAv8CwwQAAf8BgQKDBAAB/wEAAYcBgwQA
|
||||
Af8BMAGMASMEAAH/AeEBiAEDBAAB/wHBAYEBAwQAAfEBgwGAASMEAAHhAQ4BgAFjBAAB4AEAAYAB4wQA
|
||||
AcABgQGIASMEAAHAAX8BjAFjBAABxAF/AYMBwwQAAYQBfwGDAYIEAAGEAT8BhwGABAABjAF/Af8B+AQA
|
||||
A/8B+AQAAf8BjwG/Af8B4AEHAv8B+AEHAo8BwAEDAv8BwAEHAY8BBwHAAQMBgAE8AYABBwGOAQMBgAEB
|
||||
AQABGAGAAQMBgAEBAYABAQIAAYABAwGAAQEBgAEBAgABgAEBAYABAAGAAQECAAHAAQEBwAEAAYABAQEA
|
||||
ARgBwAEAAcABAQGAAQEBgAE8AcABAAHAAQEBgAEBAY4BPwHAAQAB4AEPAYABAQEEAR8BgAEAAeABHwHA
|
||||
AQMBJAGfAgAB4AE/AcABAwEEAR8BAAEBAeAB/wHgAQcBjgE/AZgBDwHwAf8B8AEPAv8B+AF/Av8B/AE/
|
||||
Av8BgAEDAv8BgAEDAv8BgAEDAQABAQEAAQEB/AE/AaABGwEAAQEBfwH9AfABDwGvAdsBAAExAX8B/QHg
|
||||
AQcBqAFbAQABSQFAAQUBwAEDAagBSwEAAUkBQAEFAcABAwGoAUsBAAExAUABBQGBAQEBqAFLAQABAQFA
|
||||
AQUBgAEBAa8BywEAAQEBQAEFAYABAQGgAQsBAAH9AUABBQGAAQEBoAF7ARgBxQFAAQUBwAEDAaABiwEk
|
||||
Ae0BQAEFAcABAwGgAbMBJAHNAUABBQHgAQcBoAGnARgB7QFAAQUB8AEPAb8BzwEAAf0BfwH9AfwBPwGA
|
||||
AR8BAAEBAQABAQL/Cw==
|
||||
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACK
|
||||
EgAAAk1TRnQBSQFMAgEBCgIAAR8BAAEfARABAAEQAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA
|
||||
AUADAAEwAwABAQEAAQgGAAEMGAABgAIAAYADAAKAAQABgAMAAYABAAGAAQACgAIAA8ABAAHAAdwBwAEA
|
||||
AfABygGmAQABMwUAATMBAAEzAQABMwEAAjMCAAMWAQADHAEAAyIBAAMpAQADVQEAA00BAANCAQADOQEA
|
||||
AYABfAH/AQACUAH/AQABkwEAAdYBAAH/AewBzAEAAcYB1gHvAQAB1gLnAQABkAGpAa0CAAH/ATMDAAFm
|
||||
AwABmQMAAcwCAAEzAwACMwIAATMBZgIAATMBmQIAATMBzAIAATMB/wIAAWYDAAFmATMCAAJmAgABZgGZ
|
||||
AgABZgHMAgABZgH/AgABmQMAAZkBMwIAAZkBZgIAApkCAAGZAcwCAAGZAf8CAAHMAwABzAEzAgABzAFm
|
||||
AgABzAGZAgACzAIAAcwB/wIAAf8BZgIAAf8BmQIAAf8BzAEAATMB/wIAAf8BAAEzAQABMwEAAWYBAAEz
|
||||
AQABmQEAATMBAAHMAQABMwEAAf8BAAH/ATMCAAMzAQACMwFmAQACMwGZAQACMwHMAQACMwH/AQABMwFm
|
||||
AgABMwFmATMBAAEzAmYBAAEzAWYBmQEAATMBZgHMAQABMwFmAf8BAAEzAZkCAAEzAZkBMwEAATMBmQFm
|
||||
AQABMwKZAQABMwGZAcwBAAEzAZkB/wEAATMBzAIAATMBzAEzAQABMwHMAWYBAAEzAcwBmQEAATMCzAEA
|
||||
ATMBzAH/AQABMwH/ATMBAAEzAf8BZgEAATMB/wGZAQABMwH/AcwBAAEzAv8BAAFmAwABZgEAATMBAAFm
|
||||
AQABZgEAAWYBAAGZAQABZgEAAcwBAAFmAQAB/wEAAWYBMwIAAWYCMwEAAWYBMwFmAQABZgEzAZkBAAFm
|
||||
ATMBzAEAAWYBMwH/AQACZgIAAmYBMwEAA2YBAAJmAZkBAAJmAcwBAAFmAZkCAAFmAZkBMwEAAWYBmQFm
|
||||
AQABZgKZAQABZgGZAcwBAAFmAZkB/wEAAWYBzAIAAWYBzAEzAQABZgHMAZkBAAFmAswBAAFmAcwB/wEA
|
||||
AWYB/wIAAWYB/wEzAQABZgH/AZkBAAFmAf8BzAEAAcwBAAH/AQAB/wEAAcwBAAKZAgABmQEzAZkBAAGZ
|
||||
AQABmQEAAZkBAAHMAQABmQMAAZkCMwEAAZkBAAFmAQABmQEzAcwBAAGZAQAB/wEAAZkBZgIAAZkBZgEz
|
||||
AQABmQEzAWYBAAGZAWYBmQEAAZkBZgHMAQABmQEzAf8BAAKZATMBAAKZAWYBAAOZAQACmQHMAQACmQH/
|
||||
AQABmQHMAgABmQHMATMBAAFmAcwBZgEAAZkBzAGZAQABmQLMAQABmQHMAf8BAAGZAf8CAAGZAf8BMwEA
|
||||
AZkBzAFmAQABmQH/AZkBAAGZAf8BzAEAAZkC/wEAAcwDAAGZAQABMwEAAcwBAAFmAQABzAEAAZkBAAHM
|
||||
AQABzAEAAZkBMwIAAcwCMwEAAcwBMwFmAQABzAEzAZkBAAHMATMBzAEAAcwBMwH/AQABzAFmAgABzAFm
|
||||
ATMBAAGZAmYBAAHMAWYBmQEAAcwBZgHMAQABmQFmAf8BAAHMAZkCAAHMAZkBMwEAAcwBmQFmAQABzAKZ
|
||||
AQABzAGZAcwBAAHMAZkB/wEAAswCAALMATMBAALMAWYBAALMAZkBAAPMAQACzAH/AQABzAH/AgABzAH/
|
||||
ATMBAAGZAf8BZgEAAcwB/wGZAQABzAH/AcwBAAHMAv8BAAHMAQABMwEAAf8BAAFmAQAB/wEAAZkBAAHM
|
||||
ATMCAAH/AjMBAAH/ATMBZgEAAf8BMwGZAQAB/wEzAcwBAAH/ATMB/wEAAf8BZgIAAf8BZgEzAQABzAJm
|
||||
AQAB/wFmAZkBAAH/AWYBzAEAAcwBZgH/AQAB/wGZAgAB/wGZATMBAAH/AZkBZgEAAf8CmQEAAf8BmQHM
|
||||
AQAB/wGZAf8BAAH/AcwCAAH/AcwBMwEAAf8BzAFmAQAB/wHMAZkBAAH/AswBAAH/AcwB/wEAAv8BMwEA
|
||||
AcwB/wFmAQAC/wGZAQAC/wHMAQACZgH/AQABZgH/AWYBAAFmAv8BAAH/AmYBAAH/AWYB/wEAAv8BZgEA
|
||||
ASEBAAGlAQADXwEAA3cBAAOGAQADlgEAA8sBAAOyAQAD1wEAA90BAAPjAQAD6gEAA/EBAAP4AQAB8AH7
|
||||
Af8BAAGkAqABAAOAAwAB/wIAAf8DAAL/AQAB/wMAAf8BAAH/AQAC/wIAA/8TAAS8BAAEvCsABrwCAATp
|
||||
AbwDAATpAbwqAAEmAR4EAAK8AQAE6QQABOkBvCoAASYBHgIAASYBHgEAAbwBAALpAbwCAAS8AQAC6QG8
|
||||
LQABvAEmAR4DAALpAbwBAAQLArwC6QG8LAABJgEeAgABvAIAAukBvAILAbwBAAILAbwC6QG8JgADvAIA
|
||||
ASYBHgIAAbwDAALpAbwCCwK8AgsBAALpAbwlAAHNAQoBAAG8AQABJgEeAQAB7AMAAbwBAALpAbwFCwIA
|
||||
AukBvCUAAc0BCgEAArwBJgEeAQABEgK8AQABvAEAAukBvAILArwDAALpAbwkAAHNAQoDAAG8AQABJgEe
|
||||
BgAC6QG8AQACCwO8AQAC6QG8JAABzQEKARIB7AEAARIBvAgAAukBvAIAAwsCAALpAbwkAAHNAQoBEgIA
|
||||
ARIBvAgAAukDvAQAAbwC6QG8IwABzQEKAQABvAMAAbwIAATpAbwDAATpAbwBAAG8IQABzQEKAQABvAMA
|
||||
AewBvAcABOkEAATpARsBMQGZIQABZRsAAzE9AAEbATEBGykAAewBEgHvBQAB9BEAChIYAALzAusB7wHs
|
||||
AesB8wUAAeoB9AUAAvIB9AYAAxIGSgMSFAAB8wHxAbwC7AEHAbwBBwHsAesBBwQAAQ4BEgHtBAAB8AEi
|
||||
ASkB6wHzBQABEgJKBm4CSgESAwABDwcAAQ8FAAEPAQABvAH3Ae0BkgHvAbwBBwHwAfQB8gHrAeoEAAEO
|
||||
AW0B7QMAAQcBIwIrASoB6wHzAwABEgFKAW4BSgZuAUoBbgFKARIBAAEPCe8BDwMAAe8CAAFtAvcB8AG8
|
||||
AfMC8gL0Ae0B6wEHAwABBwEVAeoD7QEpASsBJQEfASUBKgHrAfQCAAESAUoBbgFKBpMBSgFuAUoBEgIA
|
||||
Ae8BAQEfBu8DAALvAgABvAHvAfEB9AH2AfIC8AH0AfYB7wHsAW0DAAH0ARAB6wFKATABAwElARcB+QIg
|
||||
ASUBKgHqAgABEgFKAZMBbgZJAW4BkwFKARICAAHvAgEBHwXvAQACDwLvAgAB8gHvAvYB9wFtAesB8gH0
|
||||
AfYB8wHrAewBBwIAAfQBEAFzAUUBJAEgAfkBFwH5ASABHwEgATEBIgH0AQABEgGTAW4BSQZsAUkBbgGT
|
||||
ARICAAHvAQEBHwbvAwAC7wMAAe8B8wG8AZIB8AH3AfYB9wHtAQcB6wHsAe8DAAHyAREBRQEfAiAB+QEX
|
||||
AfkBIAEfATEBIgH0AQABEgGTAUkCbARxAmwBSQGTARIBAAEPCe8BDwMAAe8DAAEHAfABRAElARoCkgHy
|
||||
AvMB9AESAesB8gIAAfIBQwHsAUUBHwEgAfkBFwEmATEBNwEwARQCAAFJAW4BbAFxAZcEcQGXAXEBbAFu
|
||||
ARICAAEPBwABDwUAAQ8CAAH0AW0BLAElAesB9ALxAu8B8gLrAbwCAAHzAW0B6wFFAR8CIAH5ATEBUQJt
|
||||
AfMCAAFJAmwBlwJxApcCcQGXAmwBSQIAARUBDwEVAwABFQEPARUIAAEcASwBKwHqAQcBvALvAfQCvAHz
|
||||
Am0DAAHwARMBRQEfASQCKwFRAbwFAAFJAWwCcQaXAnEBbAFJAQABFQH3AQcB9wEVAQABFQH3AQcB9wEV
|
||||
BgAB7wIrAUsB7wEHAbwB8QQHAfQBiwHqAwAB8AERAUsBJAEjAQMBSgHwBwABbAFxA5cCeAOXAXEBbAIA
|
||||
AQ8BBwEAAQcBDwEAAQ8BBwEAAQcBDwUAAe8BKwEsAUUCvAEHAe8BBwG8AfABGQLbAWwBBwMAAfABIwIr
|
||||
AQ4B8AHxCAABSQFxApcBeAWXAXEBSQIAARUB9wEHAfcBFQEAARUB9wEHAfcBFQUAARIBLAFFAfIB8wHv
|
||||
AfIB8QG7AtoBswKLAfMEAAHwASMBNwExAQ4LAAFJAXEClwF4A5cBcQFJBAABFQEPARUDAAEVAQ8BFQcA
|
||||
ARIBvAIAAQcBswHUAbMCbAHvCAAB7wIOAfMMAAFsAXEElwFxAWwZAAEHAhIBvB0ABHEXAAH0C/MB9BMA
|
||||
DfMTAAEHC+8BBwIADxABAAEHDbMBBwcABEMHAAHvAQABuwazAbsCAAHvAgABEAY4ARAG0wEQAQABsw0A
|
||||
AbMFAAJDBPACQwUAAe8BAAGzBgABswIAAe8CAAEQAjgDAAE4ARAC0wIAAtMBEAEAAbMNAAGzBAABQwjw
|
||||
AUMEAAHvAQABrQEAAZcCVgGXAQABswIAAe8CAAEQAzgBAAI4ARAB0wEAAtMBAAHTARABAAGzAQABVglQ
|
||||
AVYBAAGzAwABQwPwAZICQwGSA/ABQwMAAe8BAAGtAQAEVgEAAbMB9AEAAe8CAAEQAjgCAAI4ARAB0wEA
|
||||
AtMBAAHTARABAAGzAQALVgEAAbMDAAFDAfABkgESAUMB8AGSAUMBEgGSAfABQwMAAe8BAAGtAQAEVgEA
|
||||
AbMB9AEAAe8CAAEQAzgBAAI4ARAC0wIAAtMBEAEAAbMBAAtWAQABswIAAUMB8AESAmMBQwEAAfABQwJj
|
||||
ARIB8AFDAgAB7wEAAa0BAAR4AQABswH0AQAB7wIAARAGOAEQBtMBEAEAAbMBAAtWAQABswIAAUMBEgRH
|
||||
AkMERwESAUMCAAHvAQABrQYAAbMB8wEAAe8CAA8QAQABswEAC1YBAAGzAgABQwxHAUMCAAHvAQABuwKt
|
||||
BLMBuwHzAQAB7wIAARAGRwEQBgABEAEAAbMBAAtWAQABswIAAUMMRwFDAgAB7wEAAfMD9AHzAfQEAAHv
|
||||
AgABEAJHAgACRwEQBgABEAEAAbMBAAtWAQABswMAAUMCRwKUBkcBQwMAAe8BAAF0AjIBLAF0AQABvAL3
|
||||
AQAB7wIAARABRwEAAkcBAAFHARAGAAEQAQABswEAAVYJeAFWAQABswMAAUMBRwSUBUcBQwMAAe8BAAEs
|
||||
A8MBUwEAAfcCAAHzAfACAAEQAUcBAAJHAQABRwEQBgABEAEAAbMBAAt4AQABswQAAUMElARHAUMEAAHv
|
||||
AQABdAMsAXQBAAH3AQAB8wHwAwABEAJHAgACRwEQBgABEAEAAbMBAAt4AQABswUAAkMBlANHAkMFAAHv
|
||||
CAAB8wHwBAABEAZHARAGAAEQAQABsw0AAbMHAARDBwABBwjvAQcFAA8QAQABCQ2zAQkRAAFCAU0BPgcA
|
||||
AT4DAAEoAwABQAMAATADAAEBAQABAQUAAYABARYAA/8BAAL/AsMEAAH/AYECgwQAAf8BAAGHAYMEAAH/
|
||||
ATABjAEjBAAB/wHhAYgBAwQAAf8BwQGBAQMEAAHxAYMBgAEjBAAB4QEOAYABYwQAAeABAAGAAeMEAAHA
|
||||
AYEBiAEjBAABwAF/AYwBYwQAAcQBfwGDAcMEAAGEAX8BgwGCBAABhAE/AYcBgAQAAYwBfwH/AfgEAAP/
|
||||
AfgEAAH/AY8BvwH/AeABBwL/AfgBBwKPAcABAwL/AcABBwGPAQcBwAEDAYABPAGAAQcBjgEDAYABAQEA
|
||||
ARgBgAEDAYABAQGAAQECAAGAAQMBgAEBAYABAQIAAYABAQGAAQABgAEBAgABwAEBAcABAAGAAQEBAAEY
|
||||
AcABAAHAAQEBgAEBAYABPAHAAQABwAEBAYABAQGOAT8BwAEAAeABDwGAAQEBBAEfAYABAAHgAR8BwAED
|
||||
ASQBnwIAAeABPwHAAQMBBAEfAQABAQHgAf8B4AEHAY4BPwGYAQ8B8AH/AfABDwL/AfgBfwL/AfwBPwL/
|
||||
AYABAwL/AYABAwL/AYABAwEAAQEBAAEBAfwBPwGgARsBAAEBAX8B/QHwAQ8BrwHbAQABMQF/Af0B4AEH
|
||||
AagBWwEAAUkBQAEFAcABAwGoAUsBAAFJAUABBQHAAQMBqAFLAQABMQFAAQUBgQEBAagBSwEAAQEBQAEF
|
||||
AYABAQGvAcsBAAEBAUABBQGAAQEBoAELAQAB/QFAAQUBgAEBAaABewEYAcUBQAEFAcABAwGgAYsBJAHt
|
||||
AUABBQHAAQMBoAGzASQBzQFAAQUB4AEHAaABpwEYAe0BQAEFAfABDwG/Ac8BAAH9AX8B/QH8AT8BgAEf
|
||||
AQABAQEAAQEC/ws=
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
|
|
|
|||
206
DS_Map/Resources/CharMaps/CharMapManager.cs
Normal file
206
DS_Map/Resources/CharMaps/CharMapManager.cs
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace DSPRE.CharMaps
|
||||
{
|
||||
internal static class CharMapManager
|
||||
{
|
||||
|
||||
private static Dictionary<ushort, string> decodeMap;
|
||||
private static Dictionary<string, ushort> encodeMap;
|
||||
private static Dictionary<ushort, string> commandMap;
|
||||
|
||||
public static readonly string charmapFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tools", "charmap.xml");
|
||||
public static readonly string customCharmapFilePath = Path.Combine(Program.DspreDataPath, "charmap.xml");
|
||||
|
||||
private static bool mapsInitialized = false;
|
||||
|
||||
public static Dictionary<ushort, string> GetDecodingMap()
|
||||
{
|
||||
if (!mapsInitialized)
|
||||
{
|
||||
InitializeCharMaps();
|
||||
}
|
||||
return decodeMap;
|
||||
}
|
||||
|
||||
public static Dictionary<string, ushort> GetEncodingMap()
|
||||
{
|
||||
if (!mapsInitialized)
|
||||
{
|
||||
InitializeCharMaps();
|
||||
}
|
||||
return encodeMap;
|
||||
}
|
||||
|
||||
public static Dictionary<ushort, string> GetCommandMap()
|
||||
{
|
||||
if (!mapsInitialized)
|
||||
{
|
||||
InitializeCharMaps();
|
||||
}
|
||||
return commandMap;
|
||||
}
|
||||
|
||||
public static void InvalidateMaps()
|
||||
{
|
||||
mapsInitialized = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the character maps by loading data from the charmap XML file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Loads the custom charmap file if it exists; otherwise, loads the default charmap file.
|
||||
/// If neither file is found, a FileNotFoundException is thrown.
|
||||
/// </remarks>
|
||||
/// <exception cref="FileNotFoundException"></exception>
|
||||
private static void InitializeCharMaps()
|
||||
{
|
||||
decodeMap = new Dictionary<ushort, string>();
|
||||
encodeMap = new Dictionary<string, ushort>();
|
||||
commandMap = new Dictionary<ushort, string>();
|
||||
|
||||
string charmapPath = "";
|
||||
|
||||
if (File.Exists(customCharmapFilePath))
|
||||
{
|
||||
AppLogger.Info("Loading custom charmap from user data directory.");
|
||||
charmapPath = customCharmapFilePath;
|
||||
}
|
||||
else if (File.Exists(charmapFilePath))
|
||||
{
|
||||
AppLogger.Info("Loading default charmap from application directory.");
|
||||
charmapPath = charmapFilePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileNotFoundException("No charmap XML file found in application or user data directory.");
|
||||
}
|
||||
|
||||
var xml = XDocument.Load(charmapPath, LoadOptions.PreserveWhitespace);
|
||||
|
||||
foreach (var entry in xml.Descendants("entry"))
|
||||
{
|
||||
var code = entry.Attribute("code")?.Value;
|
||||
var kind = entry.Attribute("kind")?.Value;
|
||||
var value = entry.Value;
|
||||
|
||||
if (code == null || kind == null || value == null)
|
||||
{
|
||||
AppLogger.Error("Found charmap entry with null value.");
|
||||
continue;
|
||||
}
|
||||
|
||||
ushort codeValue;
|
||||
string codeKind = kind.ToLower();
|
||||
string chars = value.ToString();
|
||||
|
||||
if (!ushort.TryParse(code, System.Globalization.NumberStyles.HexNumber, null, out codeValue))
|
||||
{
|
||||
AppLogger.Error($"Invalid code value in charmap: {code}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (codeKind == "char" || codeKind == "escape")
|
||||
{
|
||||
decodeMap[codeValue] = chars;
|
||||
encodeMap[chars] = codeValue;
|
||||
}
|
||||
else if (codeKind == "alias")
|
||||
{
|
||||
encodeMap[chars] = codeValue;
|
||||
}
|
||||
else if (codeKind == "command")
|
||||
{
|
||||
commandMap[codeValue] = chars;
|
||||
}
|
||||
else
|
||||
{
|
||||
AppLogger.Error($"Unknown kind '{kind}' in charmap entry.");
|
||||
}
|
||||
}
|
||||
|
||||
mapsInitialized = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a custom character map file by copying the default character map file to a specified location.
|
||||
/// </summary>
|
||||
/// <remarks>This method ensures that the directory for the custom character map file exists
|
||||
/// before attempting to copy the file. If the operation succeeds, the custom character map file will overwrite
|
||||
/// any existing file at the target location.</remarks>
|
||||
/// <returns><see langword="true"/> if the custom character map file is successfully created; otherwise, <see
|
||||
/// langword="false"/>.</returns>
|
||||
public static bool CreateCustomCharMapFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(customCharmapFilePath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(customCharmapFilePath));
|
||||
}
|
||||
File.Copy(charmapFilePath, customCharmapFilePath, overwrite: true);
|
||||
AppLogger.Info("Custom charmap file created successfully.");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Error($"Failed to create custom charmap file: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the custom character map file if it exists.
|
||||
/// </summary>
|
||||
/// <remarks>This method checks for the existence of the custom character map file at the
|
||||
/// predefined path and deletes it if found.</remarks>
|
||||
/// <returns><see langword="true"/> if the operation completes successfully, regardless of whether the file existed;
|
||||
/// otherwise, <see langword="false"/> if an error occurs during the deletion process.</returns>
|
||||
public static bool DeleteCustomCharMapFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(customCharmapFilePath))
|
||||
{
|
||||
File.Delete(customCharmapFilePath);
|
||||
AppLogger.Info("Custom charmap file deleted successfully.");
|
||||
}
|
||||
else
|
||||
{
|
||||
AppLogger.Info("No custom charmap file to delete.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Error($"Failed to delete custom charmap file: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SaveCustomCharMap(XmlDocument xml)
|
||||
{
|
||||
try
|
||||
{
|
||||
xml.Save(customCharmapFilePath);
|
||||
AppLogger.Info("Custom charmap XML saved successfully.");
|
||||
InvalidateMaps();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Error($"Failed to save custom charmap XML: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
282
DS_Map/Resources/CharMaps/CharMapManagerForm.Designer.cs
generated
Normal file
282
DS_Map/Resources/CharMaps/CharMapManagerForm.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
namespace DSPRE.CharMaps
|
||||
{
|
||||
partial class CharMapManagerForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.aliasLabel = new System.Windows.Forms.Label();
|
||||
this.aliasListBox = new System.Windows.Forms.ListBox();
|
||||
this.reloadButton = new System.Windows.Forms.Button();
|
||||
this.addAliasButton = new System.Windows.Forms.Button();
|
||||
this.newAliasTextBox = new System.Windows.Forms.TextBox();
|
||||
this.newAliasLabel = new System.Windows.Forms.Label();
|
||||
this.charLabel = new System.Windows.Forms.Label();
|
||||
this.codeComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.aliasGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.removeAliasButton = new System.Windows.Forms.Button();
|
||||
this.charmapGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.charmapLabel = new System.Windows.Forms.Label();
|
||||
this.charMapListBox = new System.Windows.Forms.ListBox();
|
||||
this.saveButton = new System.Windows.Forms.Button();
|
||||
this.createCustomMapButton = new System.Windows.Forms.Button();
|
||||
this.deleteCustomMapButton = new System.Windows.Forms.Button();
|
||||
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.aliasGroupBox.SuspendLayout();
|
||||
this.charmapGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// aliasLabel
|
||||
//
|
||||
this.aliasLabel.AutoSize = true;
|
||||
this.aliasLabel.Location = new System.Drawing.Point(3, 29);
|
||||
this.aliasLabel.Name = "aliasLabel";
|
||||
this.aliasLabel.Size = new System.Drawing.Size(84, 13);
|
||||
this.aliasLabel.TabIndex = 0;
|
||||
this.aliasLabel.Text = "Avalable Aliases";
|
||||
//
|
||||
// aliasListBox
|
||||
//
|
||||
this.aliasListBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.aliasListBox.FormattingEnabled = true;
|
||||
this.aliasListBox.ItemHeight = 20;
|
||||
this.aliasListBox.Location = new System.Drawing.Point(6, 46);
|
||||
this.aliasListBox.Name = "aliasListBox";
|
||||
this.aliasListBox.Size = new System.Drawing.Size(151, 224);
|
||||
this.aliasListBox.TabIndex = 1;
|
||||
//
|
||||
// reloadButton
|
||||
//
|
||||
this.reloadButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.reloadButton.Image = global::DSPRE.Properties.Resources.resetIcon;
|
||||
this.reloadButton.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.reloadButton.Location = new System.Drawing.Point(214, 163);
|
||||
this.reloadButton.Name = "reloadButton";
|
||||
this.reloadButton.Size = new System.Drawing.Size(100, 50);
|
||||
this.reloadButton.TabIndex = 2;
|
||||
this.reloadButton.Text = "Reload \r\nMappings";
|
||||
this.reloadButton.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.toolTip.SetToolTip(this.reloadButton, "Reload mappings from file. Unsaved edits will be lost!");
|
||||
this.reloadButton.UseVisualStyleBackColor = true;
|
||||
this.reloadButton.Click += new System.EventHandler(this.reloadButton_Click);
|
||||
//
|
||||
// addAliasButton
|
||||
//
|
||||
this.addAliasButton.Image = global::DSPRE.Properties.Resources.addIcon;
|
||||
this.addAliasButton.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.addAliasButton.Location = new System.Drawing.Point(163, 132);
|
||||
this.addAliasButton.Name = "addAliasButton";
|
||||
this.addAliasButton.Size = new System.Drawing.Size(151, 23);
|
||||
this.addAliasButton.TabIndex = 3;
|
||||
this.addAliasButton.Text = "Add New Alias";
|
||||
this.addAliasButton.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.toolTip.SetToolTip(this.addAliasButton, "Add new alias");
|
||||
this.addAliasButton.UseVisualStyleBackColor = true;
|
||||
this.addAliasButton.Click += new System.EventHandler(this.addAliasButton_Click);
|
||||
//
|
||||
// newAliasTextBox
|
||||
//
|
||||
this.newAliasTextBox.Location = new System.Drawing.Point(163, 62);
|
||||
this.newAliasTextBox.Name = "newAliasTextBox";
|
||||
this.newAliasTextBox.Size = new System.Drawing.Size(151, 20);
|
||||
this.newAliasTextBox.TabIndex = 4;
|
||||
//
|
||||
// newAliasLabel
|
||||
//
|
||||
this.newAliasLabel.AutoSize = true;
|
||||
this.newAliasLabel.Location = new System.Drawing.Point(160, 46);
|
||||
this.newAliasLabel.Name = "newAliasLabel";
|
||||
this.newAliasLabel.Size = new System.Drawing.Size(29, 13);
|
||||
this.newAliasLabel.TabIndex = 5;
|
||||
this.newAliasLabel.Text = "Alias";
|
||||
//
|
||||
// charLabel
|
||||
//
|
||||
this.charLabel.AutoSize = true;
|
||||
this.charLabel.Location = new System.Drawing.Point(160, 86);
|
||||
this.charLabel.Name = "charLabel";
|
||||
this.charLabel.Size = new System.Drawing.Size(53, 13);
|
||||
this.charLabel.TabIndex = 6;
|
||||
this.charLabel.Text = "Character";
|
||||
//
|
||||
// codeComboBox
|
||||
//
|
||||
this.codeComboBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.codeComboBox.FormattingEnabled = true;
|
||||
this.codeComboBox.Location = new System.Drawing.Point(163, 102);
|
||||
this.codeComboBox.Name = "codeComboBox";
|
||||
this.codeComboBox.Size = new System.Drawing.Size(151, 24);
|
||||
this.codeComboBox.TabIndex = 7;
|
||||
//
|
||||
// aliasGroupBox
|
||||
//
|
||||
this.aliasGroupBox.Controls.Add(this.removeAliasButton);
|
||||
this.aliasGroupBox.Controls.Add(this.aliasListBox);
|
||||
this.aliasGroupBox.Controls.Add(this.newAliasLabel);
|
||||
this.aliasGroupBox.Controls.Add(this.charLabel);
|
||||
this.aliasGroupBox.Controls.Add(this.codeComboBox);
|
||||
this.aliasGroupBox.Controls.Add(this.aliasLabel);
|
||||
this.aliasGroupBox.Controls.Add(this.addAliasButton);
|
||||
this.aliasGroupBox.Controls.Add(this.newAliasTextBox);
|
||||
this.aliasGroupBox.Location = new System.Drawing.Point(12, 12);
|
||||
this.aliasGroupBox.Name = "aliasGroupBox";
|
||||
this.aliasGroupBox.Size = new System.Drawing.Size(320, 280);
|
||||
this.aliasGroupBox.TabIndex = 8;
|
||||
this.aliasGroupBox.TabStop = false;
|
||||
this.aliasGroupBox.Text = "Manage Aliases";
|
||||
//
|
||||
// removeAliasButton
|
||||
//
|
||||
this.removeAliasButton.Image = global::DSPRE.Properties.Resources.deleteIcon;
|
||||
this.removeAliasButton.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.removeAliasButton.Location = new System.Drawing.Point(163, 161);
|
||||
this.removeAliasButton.Name = "removeAliasButton";
|
||||
this.removeAliasButton.Size = new System.Drawing.Size(151, 23);
|
||||
this.removeAliasButton.TabIndex = 8;
|
||||
this.removeAliasButton.Text = "Remove Alias";
|
||||
this.removeAliasButton.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.toolTip.SetToolTip(this.removeAliasButton, "Remove selected alias");
|
||||
this.removeAliasButton.UseVisualStyleBackColor = true;
|
||||
this.removeAliasButton.Click += new System.EventHandler(this.removeAliasButton_Click);
|
||||
//
|
||||
// charmapGroupBox
|
||||
//
|
||||
this.charmapGroupBox.Controls.Add(this.charmapLabel);
|
||||
this.charmapGroupBox.Controls.Add(this.charMapListBox);
|
||||
this.charmapGroupBox.Controls.Add(this.saveButton);
|
||||
this.charmapGroupBox.Controls.Add(this.createCustomMapButton);
|
||||
this.charmapGroupBox.Controls.Add(this.deleteCustomMapButton);
|
||||
this.charmapGroupBox.Controls.Add(this.reloadButton);
|
||||
this.charmapGroupBox.Location = new System.Drawing.Point(338, 12);
|
||||
this.charmapGroupBox.Name = "charmapGroupBox";
|
||||
this.charmapGroupBox.Size = new System.Drawing.Size(320, 280);
|
||||
this.charmapGroupBox.TabIndex = 9;
|
||||
this.charmapGroupBox.TabStop = false;
|
||||
this.charmapGroupBox.Text = "Manage Custom Charmap";
|
||||
//
|
||||
// charmapLabel
|
||||
//
|
||||
this.charmapLabel.AutoSize = true;
|
||||
this.charmapLabel.Location = new System.Drawing.Point(6, 28);
|
||||
this.charmapLabel.Name = "charmapLabel";
|
||||
this.charmapLabel.Size = new System.Drawing.Size(68, 13);
|
||||
this.charmapLabel.TabIndex = 13;
|
||||
this.charmapLabel.Text = "Full Charmap";
|
||||
//
|
||||
// charMapListBox
|
||||
//
|
||||
this.charMapListBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.charMapListBox.FormattingEnabled = true;
|
||||
this.charMapListBox.ItemHeight = 20;
|
||||
this.charMapListBox.Location = new System.Drawing.Point(6, 45);
|
||||
this.charMapListBox.Name = "charMapListBox";
|
||||
this.charMapListBox.Size = new System.Drawing.Size(202, 224);
|
||||
this.charMapListBox.TabIndex = 12;
|
||||
this.toolTip.SetToolTip(this.charMapListBox, "List of all mappings. Double-click to select character.\r\n");
|
||||
this.charMapListBox.DoubleClick += new System.EventHandler(this.charMapListBox_DoubleClick);
|
||||
//
|
||||
// saveButton
|
||||
//
|
||||
this.saveButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.saveButton.Image = global::DSPRE.Properties.Resources.save_rom;
|
||||
this.saveButton.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.saveButton.Location = new System.Drawing.Point(214, 219);
|
||||
this.saveButton.Name = "saveButton";
|
||||
this.saveButton.Size = new System.Drawing.Size(100, 50);
|
||||
this.saveButton.TabIndex = 11;
|
||||
this.saveButton.Text = "Save\r\nMappings";
|
||||
this.saveButton.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.toolTip.SetToolTip(this.saveButton, "Save edits to file.");
|
||||
this.saveButton.UseVisualStyleBackColor = true;
|
||||
this.saveButton.Click += new System.EventHandler(this.saveButton_Click);
|
||||
//
|
||||
// createCustomMapButton
|
||||
//
|
||||
this.createCustomMapButton.Image = global::DSPRE.Properties.Resources.addIcon;
|
||||
this.createCustomMapButton.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.createCustomMapButton.Location = new System.Drawing.Point(214, 51);
|
||||
this.createCustomMapButton.Name = "createCustomMapButton";
|
||||
this.createCustomMapButton.Size = new System.Drawing.Size(100, 50);
|
||||
this.createCustomMapButton.TabIndex = 10;
|
||||
this.createCustomMapButton.Text = "Create Custom Charmap";
|
||||
this.createCustomMapButton.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.toolTip.SetToolTip(this.createCustomMapButton, "Create new custom charmap. Will overwrite existing map.");
|
||||
this.createCustomMapButton.UseVisualStyleBackColor = true;
|
||||
this.createCustomMapButton.Click += new System.EventHandler(this.createCustomMapButton_Click);
|
||||
//
|
||||
// deleteCustomMapButton
|
||||
//
|
||||
this.deleteCustomMapButton.Image = global::DSPRE.Properties.Resources.deleteIcon;
|
||||
this.deleteCustomMapButton.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.deleteCustomMapButton.Location = new System.Drawing.Point(214, 107);
|
||||
this.deleteCustomMapButton.Name = "deleteCustomMapButton";
|
||||
this.deleteCustomMapButton.Size = new System.Drawing.Size(100, 50);
|
||||
this.deleteCustomMapButton.TabIndex = 9;
|
||||
this.deleteCustomMapButton.Text = "Delete Custom Charmap";
|
||||
this.deleteCustomMapButton.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
this.toolTip.SetToolTip(this.deleteCustomMapButton, "Delete charmap file. Once you close the editor this can not be undone.");
|
||||
this.deleteCustomMapButton.UseVisualStyleBackColor = true;
|
||||
this.deleteCustomMapButton.Click += new System.EventHandler(this.deleteCustomMapButton_Click);
|
||||
//
|
||||
// CharMapManagerForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(669, 303);
|
||||
this.Controls.Add(this.charmapGroupBox);
|
||||
this.Controls.Add(this.aliasGroupBox);
|
||||
this.Name = "CharMapManagerForm";
|
||||
this.Text = "Character Map Manager";
|
||||
this.aliasGroupBox.ResumeLayout(false);
|
||||
this.aliasGroupBox.PerformLayout();
|
||||
this.charmapGroupBox.ResumeLayout(false);
|
||||
this.charmapGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label aliasLabel;
|
||||
private System.Windows.Forms.ListBox aliasListBox;
|
||||
private System.Windows.Forms.Button reloadButton;
|
||||
private System.Windows.Forms.Button addAliasButton;
|
||||
private System.Windows.Forms.TextBox newAliasTextBox;
|
||||
private System.Windows.Forms.Label newAliasLabel;
|
||||
private System.Windows.Forms.Label charLabel;
|
||||
private System.Windows.Forms.ComboBox codeComboBox;
|
||||
private System.Windows.Forms.GroupBox aliasGroupBox;
|
||||
private System.Windows.Forms.Button removeAliasButton;
|
||||
private System.Windows.Forms.GroupBox charmapGroupBox;
|
||||
private System.Windows.Forms.Button deleteCustomMapButton;
|
||||
private System.Windows.Forms.Button createCustomMapButton;
|
||||
private System.Windows.Forms.Button saveButton;
|
||||
private System.Windows.Forms.Label charmapLabel;
|
||||
private System.Windows.Forms.ListBox charMapListBox;
|
||||
private System.Windows.Forms.ToolTip toolTip;
|
||||
}
|
||||
}
|
||||
374
DS_Map/Resources/CharMaps/CharMapManagerForm.cs
Normal file
374
DS_Map/Resources/CharMaps/CharMapManagerForm.cs
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace DSPRE.CharMaps
|
||||
{
|
||||
public partial class CharMapManagerForm : Form
|
||||
{
|
||||
|
||||
private XmlDocument currentMap;
|
||||
Dictionary<ushort, string> decodeDict = new Dictionary<ushort, string>();
|
||||
Dictionary<string, ushort> encodeDict = new Dictionary<string, ushort>();
|
||||
|
||||
private bool dirty = false;
|
||||
|
||||
public CharMapManagerForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
LoadCustomMap();
|
||||
ReadCurrentMap();
|
||||
}
|
||||
|
||||
private void SetDirty(bool isDirty)
|
||||
{
|
||||
dirty = isDirty;
|
||||
|
||||
if (dirty)
|
||||
{
|
||||
this.Text = "Character Map Manager*";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Text = "Character Map Manager";
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCustomMap()
|
||||
{
|
||||
// If file exists, try loading it
|
||||
if (!File.Exists(CharMapManager.customCharmapFilePath))
|
||||
{
|
||||
// File does not exist, this is okay and a valid state
|
||||
currentMap = null;
|
||||
EnableDisableControls(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
currentMap = new XmlDocument();
|
||||
currentMap.PreserveWhitespace = true;
|
||||
currentMap.Load(CharMapManager.customCharmapFilePath);
|
||||
EnableDisableControls(true);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// File is somehow invalid, this should be considered a valid state
|
||||
currentMap = null;
|
||||
EnableDisableControls(false);
|
||||
AppLogger.Error("Failed to load custom charmap: " + ex.ToString());
|
||||
MessageBox.Show("Failed to load custom charmap: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadCurrentMap()
|
||||
{
|
||||
charMapListBox.Items.Clear();
|
||||
aliasListBox.Items.Clear();
|
||||
codeComboBox.Items.Clear();
|
||||
codeComboBox.SelectedIndex = -1;
|
||||
decodeDict.Clear();
|
||||
|
||||
SetDirty(false);
|
||||
|
||||
if (currentMap == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (XmlNode entry in currentMap.SelectNodes("//entry"))
|
||||
{
|
||||
string codeString = entry.Attributes["code"]?.Value;
|
||||
string kind = entry.Attributes["kind"]?.Value;
|
||||
string text = entry.InnerText;
|
||||
|
||||
if (codeString == null || kind == null || text == null)
|
||||
{
|
||||
AppLogger.Warn("Found charmap entry with null value in custom map. Skipping.");
|
||||
continue;
|
||||
}
|
||||
|
||||
ushort code;
|
||||
|
||||
if (!ushort.TryParse(codeString, System.Globalization.NumberStyles.HexNumber, null, out code))
|
||||
{
|
||||
AppLogger.Error($"Invalid code value in charmap: {codeString}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (kind == "command")
|
||||
{
|
||||
// We don't display commands in this manager
|
||||
continue;
|
||||
}
|
||||
|
||||
charMapListBox.Items.Add($"0x{code:X4} <-> {text} ({kind})");
|
||||
|
||||
if (kind == "char")
|
||||
{
|
||||
decodeDict[code] = text;
|
||||
codeComboBox.Items.Add($"0x{code:X4} <-> {text}");
|
||||
}
|
||||
else if (kind == "alias")
|
||||
{
|
||||
encodeDict[text] = code;
|
||||
// Get the original character this alias points to
|
||||
if (decodeDict.TryGetValue(code, out string originalValue))
|
||||
{
|
||||
// Add alias to listbox
|
||||
aliasListBox.Items.Add($"{text} -> {originalValue} <-> 0x{code:X4}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableDisableControls(bool enableControls)
|
||||
{
|
||||
addAliasButton.Enabled = enableControls;
|
||||
removeAliasButton.Enabled = enableControls;
|
||||
saveButton.Enabled = enableControls;
|
||||
deleteCustomMapButton.Enabled = enableControls;
|
||||
}
|
||||
|
||||
private void addAliasButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (currentMap == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string alias = newAliasTextBox.Text.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(alias))
|
||||
{
|
||||
MessageBox.Show("Alias name cannot be empty.", "Invalid Alias", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Warn if single character alias without brackets is used
|
||||
if (alias.Length == 1)
|
||||
{
|
||||
var result = MessageBox.Show("Unbracketed single character aliases are not recommended and may lead to encoding issues. " +
|
||||
"Do you want to enclose the character in brackets?", "Single Character Alias", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning);
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
alias = "[" + alias + "]";
|
||||
}
|
||||
else if (result == DialogResult.Cancel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Ensure that multi character aliased are enclosed in []
|
||||
else if (alias.Length > 1 && !(alias.StartsWith("[") && alias.EndsWith("]")))
|
||||
{
|
||||
alias = "[" + alias + "]";
|
||||
}
|
||||
|
||||
// Check if alias already exists
|
||||
if (encodeDict.ContainsKey(alias))
|
||||
{
|
||||
MessageBox.Show("Alias already exists in the charmap.", "Duplicate Alias", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get selected code
|
||||
if (codeComboBox.SelectedItem == null)
|
||||
{
|
||||
MessageBox.Show("Please select a character code to alias.", "No Code Selected", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
string selectedCodeStr = codeComboBox.SelectedItem.ToString().Split(' ')[0];
|
||||
ushort selectedCode = ushort.Parse(selectedCodeStr.Substring(2), System.Globalization.NumberStyles.HexNumber);
|
||||
|
||||
// Add new alias entry to XML
|
||||
try
|
||||
{
|
||||
var root = currentMap.DocumentElement;
|
||||
XmlElement newEntry = currentMap.CreateElement("entry");
|
||||
newEntry.SetAttribute("code", selectedCode.ToString("X4"));
|
||||
newEntry.SetAttribute("kind", "alias");
|
||||
newEntry.InnerText = alias;
|
||||
|
||||
// Find the last entry element
|
||||
XmlNode lastEntry = root.SelectSingleNode("entry[last()]");
|
||||
|
||||
if (lastEntry != null)
|
||||
{
|
||||
// Get the whitespace (newline + indent) before the last entry
|
||||
XmlNode whitespaceBeforeLast = lastEntry.PreviousSibling;
|
||||
|
||||
// Insert: whitespace, then new entry
|
||||
if (whitespaceBeforeLast != null && whitespaceBeforeLast.NodeType == XmlNodeType.Whitespace)
|
||||
{
|
||||
// Clone the whitespace pattern
|
||||
XmlNode newWhitespace = currentMap.CreateTextNode(whitespaceBeforeLast.Value);
|
||||
root.InsertAfter(newWhitespace, lastEntry);
|
||||
root.InsertAfter(newEntry, newWhitespace);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: add newline + 2 spaces
|
||||
root.InsertAfter(currentMap.CreateTextNode("\n "), lastEntry);
|
||||
root.InsertAfter(newEntry, lastEntry.NextSibling);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
root.AppendChild(newEntry);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Error("Failed to add alias to charmap: " + ex.ToString());
|
||||
MessageBox.Show("Failed to add alias to charmap: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add alias to listbox and dictionary
|
||||
encodeDict[alias] = selectedCode;
|
||||
aliasListBox.Items.Add($"{alias} <-> 0x{selectedCode:X4}");
|
||||
aliasListBox.SelectedIndex = aliasListBox.Items.Count - 1;
|
||||
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void removeAliasButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (currentMap == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (aliasListBox.SelectedItem == null)
|
||||
{
|
||||
MessageBox.Show("Please select an alias to remove.", "No Alias Selected", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
string selectedAliasStr = aliasListBox.SelectedItem.ToString();
|
||||
string aliasName = selectedAliasStr.Split(' ')[0];
|
||||
|
||||
// Find and remove the alias entry from XML
|
||||
try
|
||||
{
|
||||
var entryToRemove = currentMap.DocumentElement.SelectSingleNode($"entry[@kind='alias' and text()='{aliasName}']");
|
||||
if (entryToRemove != null)
|
||||
{
|
||||
// Remove the whitespace after the entry (the newline following it)
|
||||
// this is just to keep the XML tidy
|
||||
XmlNode nextNode = entryToRemove.NextSibling;
|
||||
|
||||
entryToRemove.ParentNode.RemoveChild(entryToRemove);
|
||||
|
||||
// If next node was whitespace (newline + indent for next entry), remove it
|
||||
if (nextNode != null && nextNode.NodeType == XmlNodeType.Whitespace)
|
||||
{
|
||||
nextNode.ParentNode.RemoveChild(nextNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Selected alias not found in charmap XML. " +
|
||||
"This indicates some mismatch between display and the internal data.", "Alias Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Error("Failed to remove alias from charmap: " + ex.ToString());
|
||||
MessageBox.Show("Failed to remove alias from charmap: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove alias from listbox and dictionary
|
||||
aliasListBox.Items.Remove(aliasListBox.SelectedItem);
|
||||
aliasListBox.SelectedIndex = aliasListBox.Items.Count - 1;
|
||||
|
||||
encodeDict.Remove(aliasName);
|
||||
|
||||
SetDirty(true);
|
||||
}
|
||||
|
||||
private void createCustomMapButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (File.Exists(CharMapManager.customCharmapFilePath))
|
||||
{
|
||||
var result = MessageBox.Show("A custom charmap already exists. Do you want to overwrite it?", "Custom Charmap Exists", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||
if (result != DialogResult.Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CharMapManager.CreateCustomCharMapFile();
|
||||
LoadCustomMap();
|
||||
ReadCurrentMap();
|
||||
|
||||
}
|
||||
|
||||
private void deleteCustomMapButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var result = MessageBox.Show("Are you sure you want to delete the custom charmap? This action cannot be undone.", "Delete Custom Charmap", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
CharMapManager.DeleteCustomCharMapFile();
|
||||
}
|
||||
}
|
||||
|
||||
private void reloadButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var result = MessageBox.Show("Are you sure you want to reload the custom charmap? All unsaved changes will be lost.", "Reload Custom Charmap", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
LoadCustomMap();
|
||||
ReadCurrentMap();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (currentMap == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CharMapManager.SaveCustomCharMap(currentMap);
|
||||
SetDirty(false);
|
||||
}
|
||||
|
||||
private void charMapListBox_DoubleClick(object sender, EventArgs e)
|
||||
{
|
||||
// Get clicked item
|
||||
if (charMapListBox.SelectedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string selectedItemStr = charMapListBox.SelectedItem.ToString();
|
||||
|
||||
// Try to select corresponding code in combo box
|
||||
string codeStr = selectedItemStr.Split(' ')[0];
|
||||
|
||||
for (int i = 0; i < codeComboBox.Items.Count; i++)
|
||||
{
|
||||
string comboItemStr = codeComboBox.Items[i].ToString();
|
||||
if (comboItemStr.StartsWith(codeStr))
|
||||
{
|
||||
codeComboBox.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
126
DS_Map/Resources/CharMaps/CharMapManagerForm.resx
Normal file
126
DS_Map/Resources/CharMaps/CharMapManagerForm.resx
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
Loading…
Reference in New Issue
Block a user