add custom charmap system and an editor to easily add and remove aliases

This commit is contained in:
Yako 2025-11-08 16:29:28 +01:00
parent f2633f184f
commit 4f910ca841
9 changed files with 1127 additions and 193 deletions

View File

@ -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>

View File

@ -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)

View File

@ -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;
}
}

View File

@ -1908,6 +1908,12 @@ namespace DSPRE
}
}
private void openCharmapManagerToolStripMenuItem_Click(object sender, EventArgs e)
{
CharMaps.CharMapManagerForm charMapManager = new CharMaps.CharMapManagerForm();
charMapManager.ShowDialog();
}
#endregion
}
}

View File

@ -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">

View 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;
}
}
}
}

View 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;
}
}

View 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;
}
}
}
}
}

View 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>